diff --git a/backend-simulators/pim/pim-simulator/src/bin/pim-simulator/main.rs b/backend-simulators/pim/pim-simulator/src/bin/pim-simulator/main.rs index 56efb5b..77ea143 100644 --- a/backend-simulators/pim/pim-simulator/src/bin/pim-simulator/main.rs +++ b/backend-simulators/pim/pim-simulator/src/bin/pim-simulator/main.rs @@ -1,10 +1,13 @@ -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result, bail}; use clap::Parser; use glob::glob; +use pimcore::cpu::crossbar::Crossbar; use pimcore::json_to_instruction::json_to_executor; +use pimcore::memory_manager::CoreMemory; use pimcore::tracing::TRACER; use serde_json::Value; -use std::fs; +use std::collections::HashMap; +use std::fs::{self, read_link}; use std::io::Write; use std::path::PathBuf; @@ -43,8 +46,10 @@ fn main() -> Result<()> { let config_json = retrive_config(&args)?; let core_jsons = retrive_cores(&args)?; let memory = retrive_memory(&args)?; - let mut executor = json_to_executor::json_to_executor(config_json, core_jsons.iter()); - populate_crossbar(&args, &mut executor); + let global_crossbars = get_crossbars(&config_json, &args).unwrap(); + let crossbars = map_crossbars_to_cores(&config_json, &args, &global_crossbars); + let mut executor = + json_to_executor::json_to_executor(config_json, core_jsons.iter(), crossbars); set_memory(&mut executor, memory); TRACER .lock() @@ -55,46 +60,100 @@ fn main() -> Result<()> { Ok(()) } -fn populate_crossbar(args: &Args, executor: &mut pimcore::Executable) { - let num_cores = executor.cpu_mut().num_core(); +fn map_crossbars_to_cores<'c>( + config: &Value, + args: &Args, + global_crossbars: &'c HashMap, +) -> Vec> { + let mut res = Vec::new(); + let num_cores = config.get("core_cnt").unwrap().as_i64().unwrap() as i32; if let Some(folder) = args.folder.as_ref() { for core_idx in 0..num_cores { let core_folder = folder.join(format!("core_{}", core_idx)); + res.push(Vec::new()); if !core_folder.is_dir() { continue; } - let mut bin_files: Vec<(u32, std::path::PathBuf)> = std::fs::read_dir(&core_folder) - .expect("Failed to read core directory") - .filter_map(|entry| { - let path = entry.ok()?.path(); - let file_name = path.file_name()?.to_str()?; + let mut sym_link_files: Vec<(u32, std::path::PathBuf)> = + std::fs::read_dir(&core_folder) + .expect("Failed to read core directory") + .filter_map(|entry| { + let entry = entry.ok()?; + assert!(entry.metadata().unwrap().is_symlink()); + let path = entry.path(); + let file_name = path.file_name()?.to_str()?; - if file_name.starts_with("crossbar_") && file_name.ends_with(".bin") { - let num_str = &file_name[9..file_name.len() - 4]; - let num = num_str.parse::().ok()?; - Some((num, path)) - } else { - None - } - }) - .collect(); - bin_files.sort_by_key(|&(num, _)| num); - let core = executor.cpu_mut().core(core_idx); - let (_memory, crossbars) = core.get_memory_crossbar(); + if file_name.starts_with("crossbar_") && file_name.ends_with(".bin") { + let num_str = &file_name[9..file_name.len() - 4]; + let num = num_str.parse::().ok()?; + Some((num, path)) + } else { + None + } + }) + .collect(); + sym_link_files.sort_by_key(|&(num, _)| num); - for (i, path) in bin_files { - let bytes = std::fs::read(path).expect("Failed to read binary file"); - crossbars - .get_mut(i as usize) + for (_, symlink) in sym_link_files { + let real_path = read_link(symlink).unwrap(); + let path_as_str = real_path.to_str().unwrap(); + assert!( + global_crossbars.contains_key(path_as_str), + "symlink point to {:?}\n a not stored crossbar", + real_path + ); + + res.iter_mut() + .next_back() .unwrap() - .execute_store(&bytes) - .unwrap(); + .push(global_crossbars.get(path_as_str).unwrap()); } } } + res +} + +fn get_crossbars(config: &Value, args: &Args) -> anyhow::Result> { + let xbar_size = config.get("xbar_size").unwrap().as_array().unwrap(); + let rows_crossbar = xbar_size[0].as_i64().unwrap() as usize; + let column_corssbar = xbar_size[1].as_i64().unwrap() as usize; + let mut res = HashMap::new(); + + if let Some(folder) = args.folder.as_ref() { + let weight_folder = folder.join("weights"); + if !weight_folder.is_dir() { + bail!("Not a directory"); + } + for weight_file in + std::fs::read_dir(&weight_folder).context("Weight folder not iterable")? + { + let weight_file = weight_file.context("File not iterable")?; + if weight_file + .metadata() + .context("Doesn't contain metadata")? + .is_dir() + { + continue; + } + + let bytes = std::fs::read(weight_file.path()).expect("Failed to read binary file"); + let mut crossbar = + Crossbar::new(column_corssbar * 4, rows_crossbar, CoreMemory::new()); + crossbar.execute_store(&bytes).unwrap(); + res.insert( + weight_file + .path() + .to_str() + .context("file name not utf-8")? + .to_string(), + crossbar, + ); + } + } + Ok(res) } fn dump_memory(mut executor: pimcore::Executable, args: &Args) -> Result<()> { @@ -170,7 +229,11 @@ fn retrive_cores(args: &Args) -> Result, anyhow::Error> { let pattern_str = pattern.to_str().context("Invalid path encoding")?; let mut paths: Vec<_> = glob(pattern_str)?.map(|x| x.unwrap()).collect(); paths.sort_by_cached_key(|x| { - let mut x = x.file_stem().expect("Extracting the stem").to_str().expect("File not utf-8"); + let mut x = x + .file_stem() + .expect("Extracting the stem") + .to_str() + .expect("File not utf-8"); x = &x[5..]; x.parse::().unwrap() }); diff --git a/backend-simulators/pim/pim-simulator/src/lib/cpu/crossbar.rs b/backend-simulators/pim/pim-simulator/src/lib/cpu/crossbar.rs index cc61e80..6e2c202 100644 --- a/backend-simulators/pim/pim-simulator/src/lib/cpu/crossbar.rs +++ b/backend-simulators/pim/pim-simulator/src/lib/cpu/crossbar.rs @@ -38,14 +38,14 @@ impl Crossbar { self.memory.execute_store(0, element) } - pub fn load(&mut self, size: usize) -> Result> where + pub fn load(&self, size: usize) -> Result> where T: MemoryStorable, { if self.memory.get_len() < size //|| self.stored_bytes < size { bail!("Loading outside crossbar boundary [{} {}] < {}", self.stored_bytes, self.memory.get_len() , size); } - self.memory.load(0, size) + self.memory.load_const(0, size) } diff --git a/backend-simulators/pim/pim-simulator/src/lib/cpu/mod.rs b/backend-simulators/pim/pim-simulator/src/lib/cpu/mod.rs index cd90239..f2c6674 100644 --- a/backend-simulators/pim/pim-simulator/src/lib/cpu/mod.rs +++ b/backend-simulators/pim/pim-simulator/src/lib/cpu/mod.rs @@ -1,5 +1,5 @@ use std::{collections::HashMap, fmt::Debug}; -use anyhow::{Context, Result}; +use anyhow::{Context, Result, ensure}; use crate::{ cpu::crossbar::Crossbar, @@ -10,53 +10,44 @@ use crate::{ pub mod crossbar; #[derive(Debug, Clone)] -pub struct CPU { - cores: Box<[Core]>, +pub struct CPU<'a> { + cores: Box<[Core<'a>]>, } -impl CPU { - pub fn new(num_cores: impl TryToUsize) -> Self { +impl<'a> CPU<'a> { + pub fn new(num_cores: impl TryToUsize, crossbars: Vec> ) -> Self { let num_cores = num_cores.try_into().expect("num_cores can not be negative"); - let mut cores: Vec = std::iter::repeat_with(Core::new) - .take(num_cores + 1) - .collect(); + assert!(crossbars.len() == num_cores + 1); + let mut cores = Vec::new(); + for crossbar in crossbars { + cores.push(Core::new(crossbar)); + } Self { cores: cores.into(), } } - pub fn reserve_crossbar( - &mut self, - num_crossbar: impl TryToUsize, - byte_width: impl TryToUsize, - height: impl TryToUsize, - ) { - let num_crossbar = num_crossbar - .try_into() - .expect("num_crossbar can not be negative"); - let byte_width = byte_width - .try_into() - .expect("byte_width can not be negative"); - let height = height.try_into().expect("height can not be negative"); - for core in &mut self.cores { - core.reserve_crossbar(num_crossbar, byte_width, height); - } + pub fn host<'b>(&'b mut self) -> &'b mut Core<'a> + where 'a : 'b + { + & mut self.cores[0] } - pub fn host(&mut self) -> &mut Core { - &mut self.cores[0] - } - - pub fn core(&mut self, index: impl TryToUsize) -> &mut Core { + pub fn core<'b >(&'b mut self, index: impl TryToUsize) -> &'b mut Core<'a> + where 'a : 'b + { let index = index.try_into().expect("can not be negative"); - &mut self.cores[index] + & mut self.cores[index] } pub fn num_core(&self) -> usize { self.cores.len() } - pub(crate) fn host_and_cores(&mut self, core: impl TryToUsize) -> (&mut Core, &mut Core) { + pub(crate) fn host_and_cores<'b, 'c >(&'b mut self, core: impl TryToUsize) -> (&'c mut Core<'a>, &'c mut Core<'a>) + where 'a: 'b, + 'b: 'c + { let core = core.try_into().expect("core can not be negative"); assert_ne!( core, 0, @@ -70,45 +61,29 @@ impl CPU { (host, core) } - pub fn get_multiple_cores(&mut self, indices: [usize; N]) -> [&mut Core; N] { + pub fn get_multiple_cores<'b, const N: usize>(&'b mut self, indices: [usize; N]) -> [&'b mut Core<'a>; N] + where 'a : 'b + { self.cores.get_disjoint_mut(indices).unwrap() } } #[derive(Debug, Clone)] -pub struct Core { - crossbars: Vec, +pub struct Core<'a> { + crossbars: Vec<&'a Crossbar>, memory: CoreMemory, registers: [i32; 32], } -impl Core { - fn new() -> Self { +impl<'a> Core<'a> { + fn new(crossbars : Vec<&'a Crossbar>) -> Self { Self { - crossbars: Vec::new(), + crossbars, memory: CoreMemory::new(), registers: [0; 32], } } - pub fn reserve_crossbar( - &mut self, - num_crossbar: impl TryToUsize, - width: impl TryToUsize, - height: impl TryToUsize, - ) { - let num_crossbar = num_crossbar - .try_into() - .expect("num_crossbar can not be negative"); - let width = width.try_into().expect("width can not be negative"); - let height = height.try_into().expect("height can not be negative"); - for _ in 0..num_crossbar { - let mut crossbar = CoreMemory::new(); - crossbar.set_capacity(width * height); - self.crossbars.push(Crossbar::new(width, height, crossbar)); - } - } - pub fn execute_load(&mut self) -> Result> where T: MemoryStorable, @@ -157,7 +132,7 @@ impl Core { self.memory.load(address, size) } - pub fn get_memory_crossbar(&mut self) -> (&mut CoreMemory, &mut Vec) { + pub fn get_memory_crossbar(&mut self) -> (&mut CoreMemory, &mut Vec<&'a Crossbar>) { let Self { crossbars, memory, diff --git a/backend-simulators/pim/pim-simulator/src/lib/instruction_set/isa.rs b/backend-simulators/pim/pim-simulator/src/lib/instruction_set/isa.rs index 2eff04b..e52224a 100644 --- a/backend-simulators/pim/pim-simulator/src/lib/instruction_set/isa.rs +++ b/backend-simulators/pim/pim-simulator/src/lib/instruction_set/isa.rs @@ -76,7 +76,8 @@ pub fn functor_to_name(functor: usize) -> &'static str { /////////////////////////////////////////////////////////////// /////////////////Scalar/register Instructions////////////////// /////////////////////////////////////////////////////////////// -pub fn sldi(cores: &mut CPU, data: InstructionData) -> Result { +pub fn sldi(cores: &mut CPU, data: InstructionData) -> Result +{ TRACER.lock().unwrap().pre_sldi(cores, data); let (core_indx, rd, imm) = data.get_core_rd_imm(); let core = cores.core(core_indx); diff --git a/backend-simulators/pim/pim-simulator/src/lib/instruction_set/mod.rs b/backend-simulators/pim/pim-simulator/src/lib/instruction_set/mod.rs index 39048fe..af6da35 100644 --- a/backend-simulators/pim/pim-simulator/src/lib/instruction_set/mod.rs +++ b/backend-simulators/pim/pim-simulator/src/lib/instruction_set/mod.rs @@ -40,7 +40,9 @@ impl Instruction { Self { data, functor } } - pub fn execute(&self, cpu: &mut CPU) -> InstructionStatus { + pub fn execute<'a, 'b>(&'b self, cpu: &mut CPU<'a>) -> InstructionStatus + where 'a : 'b + { (self.functor)(cpu, self.data) .with_context(|| format!("Instruction: {}", functor_to_name(self.functor as usize))) .with_context(|| format!("Error in core: {}", self.data.core_indx() - 1)) diff --git a/backend-simulators/pim/pim-simulator/src/lib/json_to_instruction/json_to_executor.rs b/backend-simulators/pim/pim-simulator/src/lib/json_to_instruction/json_to_executor.rs index cc7d507..805c074 100644 --- a/backend-simulators/pim/pim-simulator/src/lib/json_to_instruction/json_to_executor.rs +++ b/backend-simulators/pim/pim-simulator/src/lib/json_to_instruction/json_to_executor.rs @@ -1,10 +1,11 @@ use core::panic; +use std::collections::HashMap; use serde_json::{Map, Value}; use crate::{ CoreInstructionsBuilder, Executable, - cpu::{CPU, crossbar}, + cpu::{CPU, crossbar::{self, Crossbar}}, instruction_set::{ InstructionsBuilder, instruction_data::{self, InstructionData, InstructionDataBuilder}, @@ -13,18 +14,20 @@ use crate::{ memory_manager::type_traits::TryToUsize, }; + pub fn json_to_executor<'a>( config: Value, mut cores: impl Iterator, -) -> Executable { + crossbars : Vec> +) -> Executable<'a> { let cell_precision = config.get("cell_precision").unwrap().as_i64().unwrap() as i32; let core_cnt = config.get("core_cnt").unwrap().as_i64().unwrap() as i32 - 1; let xbar_count = config.get("xbar_array_count").unwrap().as_i64().unwrap() as i32; let xbar_size = config.get("xbar_size").unwrap().as_array().unwrap(); let rows_crossbar = xbar_size[0].as_i64().unwrap() as i32; let column_corssbar = xbar_size[1].as_i64().unwrap() as i32; - let mut cpu = CPU::new(core_cnt); - cpu.reserve_crossbar(xbar_count, column_corssbar * 4, rows_crossbar); + + let mut cpu = CPU::new(core_cnt, crossbars); let mut core_insts_builder = CoreInstructionsBuilder::new(core_cnt as usize); cores.next(); for core_indx in 1..=core_cnt { diff --git a/backend-simulators/pim/pim-simulator/src/lib/memory_manager/mod.rs b/backend-simulators/pim/pim-simulator/src/lib/memory_manager/mod.rs index bcc683b..fc2ecb4 100644 --- a/backend-simulators/pim/pim-simulator/src/lib/memory_manager/mod.rs +++ b/backend-simulators/pim/pim-simulator/src/lib/memory_manager/mod.rs @@ -111,6 +111,24 @@ where { Ok(res) } + pub fn load_const(&self, address: impl TryToUsize, size: impl TryToUsize) -> Result> + where + T: MemoryStorable, + { + let address = address.try_into().expect("address can not be negative"); + let size = size.try_into().expect("size can not be negative"); + let Self { + memory, + load_requests, + } = self; + let mut res = Vec::new(); + let memory_slice = &memory[address..address + size]; + let memory_slice = unsafe { slice_from_u8(memory_slice) } + .with_context(|| format!("Accessing from {} to {}", address, address + size))?; + res.push(memory_slice); + Ok(res) + } + pub fn load(&mut self, address: impl TryToUsize, size: impl TryToUsize) -> Result> where T: MemoryStorable, diff --git a/backend-simulators/pim/pim-simulator/src/lib/pimcore.rs b/backend-simulators/pim/pim-simulator/src/lib/pimcore.rs index 3231c90..f70186e 100644 --- a/backend-simulators/pim/pim-simulator/src/lib/pimcore.rs +++ b/backend-simulators/pim/pim-simulator/src/lib/pimcore.rs @@ -67,14 +67,14 @@ impl From for CoreInstruction { } #[derive(Debug, Clone)] -pub struct Executable { - cpu: CPU, +pub struct Executable<'a> { + cpu: CPU<'a>, core_instructions: Vec, send_recv : SendRecv, } -impl Executable { - pub fn new(cpu: CPU, core_instructions: Vec) -> Self { +impl<'a> Executable<'a> { + pub fn new(cpu: CPU<'a>, core_instructions: Vec) -> Executable<'a> { let num_core = cpu.num_core(); let send_recv = SendRecv::new(num_core); assert_eq!(num_core, core_instructions.len(), "Some core doesn't have is list of istruction (required even if empty)"); @@ -85,12 +85,14 @@ impl Executable { } } - pub fn execute(&mut self) { + pub fn execute<'b>(&'b mut self) + where 'a : 'b + { let Self { - cpu, + cpu , core_instructions, send_recv - } = self; + } = self; let mut cpu_progressed = 0; let max_core = cpu.num_core(); let mut index_unit = 0; @@ -124,11 +126,11 @@ impl Executable { } } - pub fn cpu(&self) -> &CPU { + pub fn cpu(&self) -> &CPU<'a> { &self.cpu } - pub fn cpu_mut(&mut self) -> &mut CPU { + pub fn cpu_mut(&mut self) -> &mut CPU<'a> { &mut self.cpu } @@ -143,64 +145,13 @@ impl Executable { } } -fn handle_wait_sync(cpu: &mut CPU, core_instructions: &mut [CoreInstruction], core_result: InstructionStatus) { +fn handle_wait_sync<'a, 'b, 'c >(cpu: &'b mut CPU<'a>, core_instructions: &'c mut [CoreInstruction], core_result: InstructionStatus) +where 'a : 'b, + 'a : 'c +{ } -#[cfg(test)] -mod test { - use super::*; - use crate::instruction_set::instruction_data::InstructionDataBuilder; - use crate::instruction_set::{InstructionsBuilder, isa::*}; - - #[test] - fn test_only_host() { - let mut cpu = CPU::new(0); - cpu.host() - .execute_store(0, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); - let mut inst_builder = InstructionsBuilder::new(); - let mut idata_build = InstructionDataBuilder::new(); - idata_build.set_core_indx(0).fix_core_indx(); - inst_builder.make_inst(sldi, idata_build.set_rdimm(1, 0).build()); - inst_builder.make_inst(sld, idata_build.set_rdr1(1, 1).build()); - inst_builder.make_inst(sldi, idata_build.set_rdimm(2, 8).build()); - inst_builder.make_inst(sld, idata_build.set_rdr1(2, 2).build()); - inst_builder.make_inst(sadd, idata_build.set_rdr1r2(2, 1, 2).build()); - let mut core_instruction = vec![inst_builder.build().into()]; - let mut executable = Executable::new(cpu, core_instruction); - executable.execute(); - assert_eq!(executable.cpu_mut().host().register(2), 4, "Not sum to 4"); - } - - #[test] - fn test_10_core_same_code() { - let setup_core = |index: usize, cpu: &mut CPU| -> Instructions { - cpu.core(index) - .execute_store(0, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); - let mut inst_builder = InstructionsBuilder::new(); - let mut idata_build = InstructionDataBuilder::new(); - idata_build.set_core_indx(index as i32).fix_core_indx(); - inst_builder.make_inst(sldi, idata_build.set_rdimm(1, 0).build()); - inst_builder.make_inst(sld, idata_build.set_rdr1(1, 1).build()); - inst_builder.make_inst(sldi, idata_build.set_rdimm(2, 8).build()); - inst_builder.make_inst(sld, idata_build.set_rdr1(2, 2).build()); - inst_builder.make_inst(sadd, idata_build.set_rdr1r2(2, 1, 2).build()); - inst_builder.build() - }; - - let mut cpu = CPU::new(10); - let mut core_instruction = Vec::new(); - for i in 0..cpu.num_core() { - core_instruction.push(setup_core(i, &mut cpu).into()) - } - - let mut executable = Executable::new(cpu, core_instruction); - executable.execute(); - for i in 0.. executable.cpu.num_core() { - assert_eq!(executable.cpu_mut().core(i).register(2), 4, "Core {} not sum to 4", i); - } - } -} diff --git a/backend-simulators/pim/pim-simulator/src/lib/send_recv.rs b/backend-simulators/pim/pim-simulator/src/lib/send_recv.rs index c6322fd..6f68e0a 100644 --- a/backend-simulators/pim/pim-simulator/src/lib/send_recv.rs +++ b/backend-simulators/pim/pim-simulator/src/lib/send_recv.rs @@ -41,14 +41,16 @@ impl SendRecv { } } -pub fn handle_send_recv( - cpu: &mut CPU, - core_instructions: &mut [CoreInstruction], - send_recv: &mut SendRecv, +pub fn handle_send_recv<'a, 'b >( + cpu: &'b mut CPU<'a>, + core_instructions: & mut [CoreInstruction], + send_recv: & mut SendRecv, core_result: InstructionStatus, -) -> bool { - let transfer_memory = |cpu: &mut CPU, - core_instructions: &mut [CoreInstruction], +) -> bool +where 'a : 'b +{ + let transfer_memory = |cpu: &'b mut CPU<'a>, + core_instructions: & mut [CoreInstruction], sender: Option, receiver: Option| { if let Some(sender) = sender @@ -117,7 +119,7 @@ pub fn handle_send_recv( send_recv.sending[sender] = None; send_recv.receiving[receiver] = None; } - return transfered; + transfered } InstructionStatus::Reciving(instruction_data) => { let (core_idx, imm_core) = instruction_data.get_core_immcore(); @@ -146,7 +148,7 @@ pub fn handle_send_recv( send_recv.sending[sender] = None; send_recv.receiving[receiver] = None; } - return transfered; + transfered } _ => false, }