forked from MightyPork/crsn
performance improvements
This commit is contained in:
@@ -13,3 +13,4 @@ dyn-clonable = "0.9.0"
|
||||
log = "0.4.11"
|
||||
num-traits = "0.2.12"
|
||||
parking_lot = "0.11.0"
|
||||
nudge = "0.2.1"
|
||||
|
||||
@@ -7,15 +7,18 @@ pub type DebugMsg = Cow<'static, str>;
|
||||
/// Immediate value
|
||||
pub type Value = u64;
|
||||
|
||||
pub fn is_positive(val: Value) -> bool {
|
||||
#[inline(always)]
|
||||
pub const fn is_positive(val: Value) -> bool {
|
||||
0 == (val & 0x8000_0000_0000_0000)
|
||||
}
|
||||
|
||||
pub fn is_negative(val: Value) -> bool {
|
||||
#[inline(always)]
|
||||
pub const fn is_negative(val: Value) -> bool {
|
||||
0 != (val & 0x8000_0000_0000_0000)
|
||||
}
|
||||
|
||||
pub fn as_signed(val: Value) -> i64 {
|
||||
#[inline(always)]
|
||||
pub const fn as_signed(val: Value) -> i64 {
|
||||
i64::from_ne_bytes(val.to_ne_bytes())
|
||||
}
|
||||
|
||||
@@ -24,6 +27,7 @@ pub fn as_signed(val: Value) -> i64 {
|
||||
pub struct Addr(pub u64);
|
||||
|
||||
impl Addr {
|
||||
#[inline(always)]
|
||||
pub fn advance(&mut self, add: i64) {
|
||||
if add < 0 {
|
||||
self.0 = self.0.wrapping_sub(-add as u64);
|
||||
|
||||
@@ -12,15 +12,17 @@ impl Rd {
|
||||
pub const fn new(src: RdData) -> Self {
|
||||
Rd(src, Mask::FULL)
|
||||
}
|
||||
pub fn data(self) -> RdData {
|
||||
|
||||
pub const fn data(self) -> RdData {
|
||||
self.0
|
||||
}
|
||||
pub fn mask(self) -> Mask {
|
||||
|
||||
pub const fn mask(self) -> Mask {
|
||||
self.1
|
||||
}
|
||||
|
||||
pub fn immediate(val: Value) -> Rd {
|
||||
Rd(RdData::Immediate(val), Mask::default())
|
||||
pub const fn immediate(val: Value) -> Rd {
|
||||
Rd(RdData::Immediate(val), Mask::FULL)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +50,7 @@ impl Debug for Rd {
|
||||
pub struct RdObj(Register);
|
||||
|
||||
impl RdObj {
|
||||
pub fn new(reg: Register) -> Self {
|
||||
pub const fn new(reg: Register) -> Self {
|
||||
RdObj(reg)
|
||||
}
|
||||
pub const fn reg(self) -> Register {
|
||||
|
||||
+10
-3
@@ -5,8 +5,9 @@ use sexp::SourcePosition;
|
||||
|
||||
use crate::asm::instr::flatten::labels_to_skips;
|
||||
use crate::asm::parse::{ParserContext, ParserState};
|
||||
use crate::module::CrsnExtension;
|
||||
use crate::module::{CrsnExtension, CrsnUniq};
|
||||
use crate::runtime::program::Program;
|
||||
use crate::builtin::BuiltinOps;
|
||||
|
||||
pub mod data;
|
||||
pub mod error;
|
||||
@@ -15,7 +16,13 @@ pub mod parse;
|
||||
pub mod patches;
|
||||
|
||||
/// Parse a program from string and assemble a low level instruction sequence from it.
|
||||
pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Result<Arc<Program>, error::CrsnError> {
|
||||
pub fn assemble(source: &str, uniq : &CrsnUniq, mut parsers: Vec<Box<dyn CrsnExtension>>) -> Result<Arc<Program>, error::CrsnError> {
|
||||
parsers.insert(0, BuiltinOps::new());
|
||||
|
||||
for p in &mut parsers {
|
||||
p.init(uniq);
|
||||
}
|
||||
|
||||
let pcx = ParserContext {
|
||||
parsers: &parsers,
|
||||
state: RefCell::new(ParserState {
|
||||
@@ -28,5 +35,5 @@ pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Resu
|
||||
let ops = parse::parse(source, &SourcePosition::default(), &pcx)?;
|
||||
let ops = labels_to_skips(ops)?;
|
||||
|
||||
Ok(Program::new(ops, parsers)?)
|
||||
Ok(Program::new(ops, Arc::new(parsers))?)
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ use crate::asm::error::CrsnError;
|
||||
use crate::asm::instr::cond::parse_cond;
|
||||
use crate::asm::instr::Op;
|
||||
use crate::asm::parse::arg_parser::TokenParser;
|
||||
use crate::builtin::BuiltinOps;
|
||||
|
||||
use crate::module::ParseRes;
|
||||
|
||||
pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>, spos: &SourcePosition) -> Result<Option<Op>, CrsnError> {
|
||||
// Include built-in instructions
|
||||
let builtins = [BuiltinOps::new()];
|
||||
let mut cond = None;
|
||||
|
||||
if let Some(pos) = keyword.find('.') {
|
||||
@@ -17,7 +16,7 @@ pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>, spos: &S
|
||||
keyword = &keyword[..pos];
|
||||
}
|
||||
|
||||
for p in builtins.iter().chain(arg_tokens.pcx.parsers) {
|
||||
for p in arg_tokens.pcx.parsers {
|
||||
arg_tokens = match p.parse_op(spos, keyword, arg_tokens) {
|
||||
Ok(ParseRes::Parsed(kind)) => return Ok(Some(Op {
|
||||
cond,
|
||||
|
||||
@@ -14,6 +14,8 @@ use crate::asm::parse::arg_parser::TokenParser;
|
||||
use crate::runtime::fault::Fault;
|
||||
use crate::runtime::run_thread::state::RunState;
|
||||
use crate::runtime::run_thread::ThreadInfo;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
mod eval_res;
|
||||
|
||||
@@ -41,7 +43,33 @@ pub trait OpTrait: Debug + Send + Sync + 'static {
|
||||
fn to_sexp(&self) -> Sexp;
|
||||
}
|
||||
|
||||
/// CRSN initializer object.
|
||||
/// Only one should be created for the lifespan of the parser and runtime.
|
||||
#[derive(Default)]
|
||||
pub struct CrsnUniq {
|
||||
object_handle_counter : AtomicU64
|
||||
}
|
||||
|
||||
pub const UNIQ_BASE: u64 = 0x6372_736e_0000_0000;
|
||||
|
||||
impl CrsnUniq {
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
object_handle_counter: AtomicU64::new(UNIQ_BASE),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn unique_handle(&self) -> u64 {
|
||||
self.object_handle_counter.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait CrsnExtension: Debug + Send + Sync + 'static {
|
||||
fn init(&mut self, uniq: &CrsnUniq) {
|
||||
//
|
||||
}
|
||||
|
||||
/// Get name of the module
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ impl RunThread {
|
||||
let state = &mut self.state;
|
||||
let info = &self.info;
|
||||
|
||||
let op = info.program.read(state.frame.pc);
|
||||
let op = info.program.fetch_instr(state.frame.pc);
|
||||
|
||||
trace!("### {:04} : {:?}", state.frame.pc.0, op);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ impl StackFrame {
|
||||
sf
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_retvals(&mut self, vals: &[Value]) {
|
||||
for n in 0..(vals.len().min(REG_COUNT)) {
|
||||
self.res[n] = vals[n];
|
||||
|
||||
@@ -27,6 +27,7 @@ pub struct StatusFlags {
|
||||
}
|
||||
|
||||
impl StatusFlags {
|
||||
#[inline(always)]
|
||||
pub fn clear(&mut self) {
|
||||
*self = Self::default();
|
||||
}
|
||||
@@ -57,12 +58,14 @@ impl StatusFlags {
|
||||
if val & 0x100 != 0 { self.carry = true; }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn update(&mut self, val: Value) {
|
||||
self.zero = val == 0;
|
||||
self.positive = is_positive(val);
|
||||
self.negative = is_negative(val);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn test(&self, cond: Cond) -> bool {
|
||||
match cond {
|
||||
Cond::Equal => self.equal,
|
||||
@@ -86,6 +89,7 @@ impl StatusFlags {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set(&mut self, cond: Cond) {
|
||||
match cond {
|
||||
Cond::Equal => {
|
||||
|
||||
@@ -90,8 +90,10 @@ impl Program {
|
||||
}
|
||||
|
||||
/// Read a program instruction at address
|
||||
pub fn read(&self, addr: Addr) -> &Op {
|
||||
if addr.0 >= self.ops.len() as u64 {
|
||||
pub fn fetch_instr(&self, addr: Addr) -> &Op {
|
||||
if (addr.0 as usize) < self.ops.len() {
|
||||
unsafe { self.ops.get_unchecked(addr.0 as usize) }
|
||||
} else {
|
||||
&Op {
|
||||
kind: OpKind::BuiltIn(BuiltinOp::Halt),
|
||||
pos: SourcePosition {
|
||||
@@ -101,8 +103,6 @@ impl Program {
|
||||
},
|
||||
cond: None,
|
||||
}
|
||||
} else {
|
||||
&self.ops[addr.0 as usize]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ impl Program {
|
||||
if b0 != b1 {
|
||||
// block barrier that only partially intersects the jump
|
||||
if (*b0 >= from && *b0 <= to) != (*b1 >= from && *b1 <= to) {
|
||||
if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.read(*b0).kind {
|
||||
if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.fetch_instr(*b0).kind {
|
||||
return Err(Fault::JumpThroughBarrier {
|
||||
msg: msg.clone().unwrap_or("BLOCK BARRIER".into())
|
||||
});
|
||||
@@ -127,7 +127,7 @@ impl Program {
|
||||
} else {
|
||||
// point barrier
|
||||
if *b0 >= from && *b0 <= to {
|
||||
if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.read(*b0).kind {
|
||||
if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.fetch_instr(*b0).kind {
|
||||
return Err(Fault::JumpThroughBarrier {
|
||||
msg: msg.clone().unwrap_or("POINT BARRIER".into())
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
|
||||
use std::thread::JoinHandle;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -7,7 +7,7 @@ pub use info::ThreadInfo;
|
||||
pub use state::RunState;
|
||||
|
||||
use crate::asm::data::literal::Addr;
|
||||
use crate::module::EvalRes;
|
||||
use crate::module::{EvalRes, CrsnUniq};
|
||||
use crate::runtime::fault::Fault;
|
||||
use crate::runtime::frame::StackFrame;
|
||||
use crate::runtime::program::Program;
|
||||
@@ -23,13 +23,9 @@ pub struct RunThread {
|
||||
pub mod info;
|
||||
pub mod state;
|
||||
|
||||
pub fn new_uniq() -> Arc<AtomicU64> {
|
||||
Arc::new(AtomicU64::new(info::UNIQ_BASE))
|
||||
}
|
||||
|
||||
pub struct ThreadParams<'a> {
|
||||
pub id: ThreadToken,
|
||||
pub uniq: Option<Arc<AtomicU64>>,
|
||||
pub uniq: Arc<CrsnUniq>,
|
||||
pub program: Arc<Program>,
|
||||
pub pc: Addr,
|
||||
pub cycle_time: Duration,
|
||||
@@ -42,7 +38,7 @@ impl RunThread {
|
||||
|
||||
let ti = Arc::new(ThreadInfo {
|
||||
id: params.id,
|
||||
uniq: params.uniq.unwrap_or_else(new_uniq),
|
||||
uniq: params.uniq,
|
||||
program: params.program,
|
||||
cycle_time: params.cycle_time,
|
||||
extensions,
|
||||
@@ -73,12 +69,11 @@ impl RunThread {
|
||||
'run: loop {
|
||||
match self.eval_op() {
|
||||
Ok(EvalRes { cycles, advance }) => {
|
||||
std::thread::sleep(self.info.cycle_time * (cycles as u32));
|
||||
if cycles > 0 {
|
||||
std::thread::sleep(self.info.cycle_time * (cycles as u32));
|
||||
}
|
||||
trace!("Step {}; Status = {}", advance, self.state.frame.status);
|
||||
self.state.frame.pc.advance(advance);
|
||||
if self.state.frame.status.invalid {
|
||||
warn!("Operation failed with INVALID status!");
|
||||
}
|
||||
}
|
||||
Err(Fault::Halt) => {
|
||||
// TODO implement coordinated shutdown when more threads are running!
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::asm::data::literal::Value;
|
||||
use crate::runtime::program::Program;
|
||||
use crate::runtime::run_thread::ThreadToken;
|
||||
use crate::module::CrsnExtension;
|
||||
use crate::module::{CrsnExtension, CrsnUniq};
|
||||
|
||||
pub struct ThreadInfo {
|
||||
/// Thread ID
|
||||
pub id: ThreadToken,
|
||||
/// Thread ID
|
||||
pub(crate) uniq: Arc<AtomicU64>,
|
||||
/// Initializer, used to generate unique IDs
|
||||
pub(crate) uniq: Arc<CrsnUniq>,
|
||||
/// Program to run
|
||||
pub program: Arc<Program>,
|
||||
/// Program to run
|
||||
@@ -20,10 +20,8 @@ pub struct ThreadInfo {
|
||||
pub extensions: Arc<Vec<Box<dyn CrsnExtension>>>,
|
||||
}
|
||||
|
||||
pub const UNIQ_BASE: u64 = 0x6372_736e_0000_0000;
|
||||
|
||||
impl ThreadInfo {
|
||||
pub fn unique_value(&self) -> Value {
|
||||
self.uniq.fetch_add(1, Ordering::Relaxed)
|
||||
pub fn unique_handle(&self) -> Value {
|
||||
self.uniq.unique_handle()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::runtime::fault::Fault;
|
||||
use crate::runtime::frame::{CallStack, REG_COUNT, StackFrame};
|
||||
use std::sync::Arc;
|
||||
use crate::runtime::run_thread::ThreadInfo;
|
||||
use nudge::{likely};
|
||||
|
||||
pub struct RunState {
|
||||
pub thread_info: Arc<ThreadInfo>,
|
||||
@@ -49,6 +50,7 @@ impl RunState {
|
||||
}
|
||||
|
||||
/// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual)
|
||||
#[inline(always)]
|
||||
pub fn set_flag(&mut self, cond: Cond, set: bool) {
|
||||
if set {
|
||||
self.frame.status.set(cond);
|
||||
@@ -56,6 +58,7 @@ impl RunState {
|
||||
}
|
||||
|
||||
/// Check status flags for a condition
|
||||
#[inline(always)]
|
||||
pub fn test_cond(&self, cond: Cond) -> bool {
|
||||
self.frame.status.test(cond)
|
||||
}
|
||||
@@ -72,12 +75,14 @@ impl RunState {
|
||||
}
|
||||
|
||||
/// Clear status flags
|
||||
#[inline(always)]
|
||||
pub fn clear_status(&mut self) {
|
||||
self.frame.status.clear();
|
||||
}
|
||||
|
||||
/// Update status flags using a variable.
|
||||
/// The update is additive - call `clear_status()` first if desired!
|
||||
#[inline(always)]
|
||||
pub fn update_status(&mut self, val: Value) {
|
||||
self.frame.status.update(val);
|
||||
}
|
||||
@@ -90,29 +95,29 @@ impl RunState {
|
||||
/// Read a `Rd` value
|
||||
pub fn read(&mut self, rd: Rd) -> Result<Value, Fault> {
|
||||
match rd.data() {
|
||||
RdData::Immediate(v) => Ok(v),
|
||||
RdData::Register(Register::Res(rn)) => {
|
||||
if rn >= REG_COUNT as u8 {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
||||
} else {
|
||||
trace!("Rd {:?} = {}", rd, self.frame.res[rn as usize]);
|
||||
Ok(self.frame.res[rn as usize])
|
||||
}
|
||||
}
|
||||
RdData::Register(Register::Arg(rn)) => {
|
||||
if rn >= REG_COUNT as u8 {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
||||
} else {
|
||||
trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]);
|
||||
Ok(self.frame.arg[rn as usize])
|
||||
}
|
||||
}
|
||||
RdData::Register(Register::Gen(rn)) => {
|
||||
if rn >= REG_COUNT as u8 {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
||||
} else {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
|
||||
Ok(self.frame.gen[rn as usize])
|
||||
} else {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
||||
}
|
||||
}
|
||||
RdData::Immediate(v) => Ok(v),
|
||||
RdData::Register(Register::Arg(rn)) => {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]);
|
||||
Ok(self.frame.arg[rn as usize])
|
||||
} else {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
||||
}
|
||||
}
|
||||
RdData::Register(Register::Res(rn)) => {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
trace!("Rd {:?} = {}", rd, self.frame.res[rn as usize]);
|
||||
Ok(self.frame.res[rn as usize])
|
||||
} else {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
||||
}
|
||||
}
|
||||
RdData::RegObject(register) => {
|
||||
@@ -160,32 +165,32 @@ impl RunState {
|
||||
trace!("WR {:?} := {}", wr, val);
|
||||
|
||||
match wr.d() {
|
||||
WrData::Discard => {
|
||||
/* Discard */
|
||||
Ok(())
|
||||
}
|
||||
WrData::Register(Register::Res(rn)) => {
|
||||
if rn >= REG_COUNT as u8 {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
||||
WrData::Register(Register::Gen(rn)) => {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
self.frame.gen[rn as usize] = val;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
|
||||
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
||||
}
|
||||
}
|
||||
WrData::Register(Register::Arg(rn)) => {
|
||||
if rn >= REG_COUNT as u8 {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
||||
} else {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
|
||||
} else {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
||||
}
|
||||
}
|
||||
WrData::Register(Register::Gen(rn)) => {
|
||||
if rn >= REG_COUNT as u8 {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
||||
WrData::Register(Register::Res(rn)) => {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
|
||||
} else {
|
||||
self.frame.gen[rn as usize] = val;
|
||||
Ok(())
|
||||
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
||||
}
|
||||
}
|
||||
WrData::Discard => {
|
||||
/* Discard */
|
||||
Ok(())
|
||||
}
|
||||
WrData::RegObject(register) => {
|
||||
let reference = self.read(Rd::new(RdData::Register(register)))?;
|
||||
self.write_object(reference, wr.mask(), val)
|
||||
|
||||
Reference in New Issue
Block a user