fix offset selection implementation to match the pim isa automatic code format for pim-simulator
This commit is contained in:
@@ -13,7 +13,7 @@ use pimcore::memory_manager::CoreMemory;
|
||||
use pimcore::tracing::TRACER;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{self, File, read_link};
|
||||
use std::fs::{self, File};
|
||||
use std::io::{BufReader, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -110,7 +110,7 @@ fn map_crossbars_to_cores<'c>(
|
||||
sym_link_files.sort_by_key(|&(num, _)| num);
|
||||
|
||||
for (_, symlink) in sym_link_files {
|
||||
let real_path = read_link(symlink).unwrap();
|
||||
let real_path = symlink.canonicalize().unwrap();
|
||||
let path_as_str = real_path.to_str().unwrap();
|
||||
assert!(
|
||||
global_crossbars.contains_key(path_as_str),
|
||||
@@ -162,6 +162,8 @@ fn get_crossbars(config: &Value, args: &Args) -> anyhow::Result<HashMap<String,
|
||||
res.insert(
|
||||
weight_file
|
||||
.path()
|
||||
.canonicalize()
|
||||
.context("Failed to resolve crossbar path")?
|
||||
.to_str()
|
||||
.context("file name not utf-8")?
|
||||
.to_string(),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::memory_manager::{CoreMemory, MemoryStorable};
|
||||
use anyhow::{Result, bail, ensure};
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Crossbar {
|
||||
max_width: usize,
|
||||
@@ -12,7 +11,12 @@ pub struct Crossbar {
|
||||
|
||||
impl Crossbar {
|
||||
pub fn new(width: usize, height: usize, memory: CoreMemory) -> Self {
|
||||
Self { max_width: width, max_height: height, memory, stored_bytes:0 }
|
||||
Self {
|
||||
max_width: width,
|
||||
max_height: height,
|
||||
memory,
|
||||
stored_bytes: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
@@ -27,27 +31,36 @@ impl Crossbar {
|
||||
self.stored_bytes
|
||||
}
|
||||
|
||||
pub fn execute_store<T>(&mut self, element: &[T]) -> Result<()> where
|
||||
T: MemoryStorable, {
|
||||
pub fn execute_store<T>(&mut self, element: &[T]) -> Result<()>
|
||||
where
|
||||
T: MemoryStorable,
|
||||
{
|
||||
self.memory.clear();
|
||||
let total_size = self.max_width * self.max_height;
|
||||
self.memory.set_capacity(total_size);
|
||||
let stored_size = std::mem::size_of_val(element);
|
||||
ensure!(stored_size <= total_size, "Storing more than crossbar can handle");
|
||||
self.stored_bytes=stored_size;
|
||||
ensure!(
|
||||
stored_size <= total_size,
|
||||
"Storing more than crossbar can handle"
|
||||
);
|
||||
self.stored_bytes = stored_size;
|
||||
self.memory.execute_store(0, element)
|
||||
}
|
||||
|
||||
pub fn load<T>(&self, size: usize) -> Result<Vec<&[T]>> where
|
||||
T: MemoryStorable, {
|
||||
if self.memory.get_len() < size
|
||||
//|| self.stored_bytes < size
|
||||
pub fn load<T>(&self, size: usize) -> Result<Vec<&[T]>>
|
||||
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);
|
||||
bail!(
|
||||
"Loading outside crossbar boundary [{} {}] < {}",
|
||||
self.stored_bytes,
|
||||
self.memory.get_len(),
|
||||
size
|
||||
);
|
||||
}
|
||||
self.memory.load_const(0, size)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::utility::AddressArg;
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
use anyhow::{Context, Result, ensure};
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use crate::{
|
||||
cpu::crossbar::Crossbar,
|
||||
@@ -10,14 +10,13 @@ use crate::{
|
||||
|
||||
pub mod crossbar;
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CPU<'a> {
|
||||
cores: Box<[Core<'a>]>,
|
||||
}
|
||||
|
||||
impl<'a> CPU<'a> {
|
||||
pub fn new(num_cores: impl TryToUsize, crossbars: Vec<Vec<&'a Crossbar>> ) -> Self {
|
||||
pub fn new(num_cores: impl TryToUsize, crossbars: Vec<Vec<&'a Crossbar>>) -> Self {
|
||||
let num_cores = num_cores.try_into().expect("num_cores can not be negative");
|
||||
assert!(crossbars.len() == num_cores + 1);
|
||||
let mut cores = Vec::new();
|
||||
@@ -30,25 +29,31 @@ impl<'a> CPU<'a> {
|
||||
}
|
||||
|
||||
pub fn host<'b>(&'b mut self) -> &'b mut Core<'a>
|
||||
where 'a : 'b
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
& mut self.cores[0]
|
||||
&mut self.cores[0]
|
||||
}
|
||||
|
||||
pub fn core<'b >(&'b mut self, index: impl TryToUsize) -> &'b mut Core<'a>
|
||||
where 'a : 'b
|
||||
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<'b, 'c >(&'b mut self, core: impl TryToUsize) -> (&'c mut Core<'a>, &'c mut Core<'a>)
|
||||
where 'a: 'b,
|
||||
'b: 'c
|
||||
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!(
|
||||
@@ -63,8 +68,12 @@ impl<'a> CPU<'a> {
|
||||
(host, core)
|
||||
}
|
||||
|
||||
pub fn get_multiple_cores<'b, const N: usize>(&'b mut self, indices: [usize; N]) -> [&'b mut Core<'a>; N]
|
||||
where 'a : 'b
|
||||
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()
|
||||
}
|
||||
@@ -78,7 +87,7 @@ pub struct Core<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Core<'a> {
|
||||
fn new(crossbars : Vec<&'a Crossbar>) -> Self {
|
||||
fn new(crossbars: Vec<&'a Crossbar>) -> Self {
|
||||
Self {
|
||||
crossbars,
|
||||
memory: CoreMemory::new(),
|
||||
@@ -139,7 +148,12 @@ impl<'a> Core<'a> {
|
||||
(memory, crossbars)
|
||||
}
|
||||
|
||||
pub fn memset(&mut self, address: impl AddressArg, size: impl TryToUsize, val: u8) -> Result<()> {
|
||||
pub fn memset(
|
||||
&mut self,
|
||||
address: impl AddressArg,
|
||||
size: impl TryToUsize,
|
||||
val: u8,
|
||||
) -> Result<()> {
|
||||
let address = address.to_address_usize()?;
|
||||
let size = size.try_into().context("size can not be negative")?;
|
||||
self.memory.memset(address, size, val)
|
||||
|
||||
@@ -278,9 +278,18 @@ impl InstructionDataBuilder {
|
||||
}
|
||||
|
||||
fn check_sanity(&self) {
|
||||
assert!(!(self.get_r2() != 0 && self.get_imm() != 0 && self.get_mbiw() != 0 && self.get_imm_core() != 0));
|
||||
assert!(!(self.get_ibiw() != 0 && self.get_offset_select() != 0 && self.get_imm_relu() != 0));
|
||||
assert!(!(self.get_obiw() != 0 && self.get_offset_value() != 0 && self.get_imm_group() != 0));
|
||||
assert!(
|
||||
!(self.get_r2() != 0
|
||||
&& self.get_imm() != 0
|
||||
&& self.get_mbiw() != 0
|
||||
&& self.get_imm_core() != 0)
|
||||
);
|
||||
assert!(
|
||||
!(self.get_ibiw() != 0 && self.get_offset_select() != 0 && self.get_imm_relu() != 0)
|
||||
);
|
||||
assert!(
|
||||
!(self.get_obiw() != 0 && self.get_offset_value() != 0 && self.get_imm_group() != 0)
|
||||
);
|
||||
}
|
||||
|
||||
pub fn build(&mut self) -> InstructionData {
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
type_traits::{FromFloat, UpcastDestTraits, UpcastSlice},
|
||||
},
|
||||
tracing::TRACER,
|
||||
utility::{add_offset_r1, add_offset_r2, add_offset_rd},
|
||||
utility::{AddressArg, add_offset_r1, add_offset_r2, add_offset_rd},
|
||||
};
|
||||
use aligned_vec::{AVec, ConstAlign};
|
||||
use anyhow::{Context, Result, ensure};
|
||||
@@ -58,7 +58,7 @@ pub static NAMES: LazyLock<HashMap<usize, &'static str>> = LazyLock::new(|| {
|
||||
add_name_simd!(hash, vtanh);
|
||||
add_name_simd!(hash, vsigm);
|
||||
add_name_simd!(hash, vsoftmax);
|
||||
add_name!(hash, vmv);
|
||||
add_name_simd!(hash, vmv);
|
||||
add_name!(hash, vrsu);
|
||||
add_name!(hash, vrsl);
|
||||
add_name!(hash, ld);
|
||||
@@ -189,6 +189,7 @@ static SIMD: LazyLock<HashMap<usize, HashMap<(usize, usize), InstructionType>>>
|
||||
add_simd_to_map!(storage, vtanh);
|
||||
add_simd_to_map!(storage, vsigm);
|
||||
add_simd_to_map!(storage, vsoftmax);
|
||||
add_simd_to_map!(storage, vmv);
|
||||
add_simd_to_map!(storage, mvmul);
|
||||
storage
|
||||
});
|
||||
@@ -273,7 +274,10 @@ where
|
||||
"Stored crossbar bytes do not describe an integral number of columns"
|
||||
);
|
||||
let crossbar_elem_width = crossbar_stored_bytes / bytes_per_column;
|
||||
ensure!(crossbar_elem_width != 0, "Crossbar contains no stored columns");
|
||||
ensure!(
|
||||
crossbar_elem_width != 0,
|
||||
"Crossbar contains no stored columns"
|
||||
);
|
||||
|
||||
let loads = memory
|
||||
.reserve_load(r1_val, crossbar_height * size_of::<F>())?
|
||||
@@ -742,7 +746,41 @@ where
|
||||
|
||||
#[inline(never)]
|
||||
pub fn vmv(cores: &mut CPU, data: InstructionData) -> Result<InstructionStatus> {
|
||||
todo!()
|
||||
panic!("You are calling a placeholder, the real call is the generic version");
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub(super) fn vmv_impl<F, T>(cores: &mut CPU, data: InstructionData) -> Result<InstructionStatus>
|
||||
where
|
||||
F: Copy + MemoryStorable,
|
||||
{
|
||||
let (core_indx, rd, r1, r2, imm_len, _, _) = data.get_core_rd_r1_r2_immlen_offset();
|
||||
let core = cores.core(core_indx);
|
||||
let source = core.register(r1).to_address_usize()?;
|
||||
let destination = core.register(rd);
|
||||
let stride: usize = core
|
||||
.register(r2)
|
||||
.try_into()
|
||||
.context("vmv stride can not be negative")?;
|
||||
let (element_count, _) = vector_lengths::<F>(imm_len)?;
|
||||
let stride_bytes = stride
|
||||
.checked_mul(size_of::<F>())
|
||||
.context("vmv byte stride overflow")?;
|
||||
let mut result = Vec::with_capacity(element_count);
|
||||
for index in 0..element_count {
|
||||
let offset = index
|
||||
.checked_mul(stride_bytes)
|
||||
.context("vmv source offset overflow")?;
|
||||
let address = source
|
||||
.checked_add(offset)
|
||||
.context("vmv source address overflow")?;
|
||||
result.push(
|
||||
core.reserve_load(address, size_of::<F>())?
|
||||
.execute_load::<F>()?[0][0],
|
||||
);
|
||||
}
|
||||
core.execute_store(destination, &result)?;
|
||||
Ok(InstructionStatus::Completed)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
@@ -827,7 +865,7 @@ pub fn lmv(cores: &mut CPU, data: InstructionData) -> Result<InstructionStatus>
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn isa_send(functor : usize) -> bool{
|
||||
pub fn isa_send(functor: usize) -> bool {
|
||||
(send as *const () as usize) == functor
|
||||
}
|
||||
|
||||
@@ -837,7 +875,7 @@ pub fn send(cores: &mut CPU, data: InstructionData) -> Result<InstructionStatus>
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn isa_recv(functor : usize) -> bool{
|
||||
pub fn isa_recv(functor: usize) -> bool {
|
||||
(recv as *const () as usize) == functor
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ use crate::{
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use std::mem::swap;
|
||||
pub mod helper;
|
||||
pub mod instruction_data;
|
||||
pub mod isa;
|
||||
pub mod helper;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Instruction {
|
||||
@@ -41,7 +41,8 @@ impl Instruction {
|
||||
}
|
||||
|
||||
pub fn execute<'a, 'b>(&'b self, cpu: &mut CPU<'a>) -> InstructionStatus
|
||||
where 'a : 'b
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
(self.functor)(cpu, self.data)
|
||||
.with_context(|| format!("Instruction: {}", functor_to_name(self.functor as usize)))
|
||||
|
||||
@@ -78,7 +78,11 @@ impl CoreMemory {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reserve_load(&mut self, address: impl TryToUsize, size: impl TryToUsize) -> Result<&mut Self>
|
||||
pub fn reserve_load(
|
||||
&mut self,
|
||||
address: impl TryToUsize,
|
||||
size: impl TryToUsize,
|
||||
) -> Result<&mut Self>
|
||||
where {
|
||||
let address = address.try_into().context("address can not be negative")?;
|
||||
let size = size.try_into().context("size can not be negative")?;
|
||||
@@ -87,7 +91,8 @@ where {
|
||||
size,
|
||||
};
|
||||
if self.memory.len() < address + size {
|
||||
self.memory.resize(min((address + size) * 2, u32::MAX as usize), 0);
|
||||
self.memory
|
||||
.resize(min((address + size) * 2, u32::MAX as usize), 0);
|
||||
}
|
||||
self.load_requests.push(load_request);
|
||||
Ok(self)
|
||||
@@ -105,14 +110,24 @@ where {
|
||||
for (load_index, load_request) in load_requests.drain(..).enumerate() {
|
||||
let LoadRequest { index, size } = load_request;
|
||||
let memory_slice = &memory[index..index + size];
|
||||
let memory_slice = unsafe { slice_from_u8(memory_slice) }
|
||||
.with_context(|| format!("Load number: {} Accessing from {} to {}", load_index, index, index + size))?;
|
||||
let memory_slice = unsafe { slice_from_u8(memory_slice) }.with_context(|| {
|
||||
format!(
|
||||
"Load number: {} Accessing from {} to {}",
|
||||
load_index,
|
||||
index,
|
||||
index + size
|
||||
)
|
||||
})?;
|
||||
res.push(memory_slice);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn load_const<T>(&self, address: impl TryToUsize, size: impl TryToUsize) -> Result<Vec<&[T]>>
|
||||
pub fn load_const<T>(
|
||||
&self,
|
||||
address: impl TryToUsize,
|
||||
size: impl TryToUsize,
|
||||
) -> Result<Vec<&[T]>>
|
||||
where
|
||||
T: MemoryStorable,
|
||||
{
|
||||
@@ -125,7 +140,7 @@ where {
|
||||
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))?;
|
||||
.with_context(|| format!("Accessing from {} to {}", address, address + size))?;
|
||||
res.push(memory_slice);
|
||||
Ok(res)
|
||||
}
|
||||
@@ -155,7 +170,12 @@ where {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn memset(&mut self, address: impl TryToUsize, size: impl TryToUsize, val: u8) -> Result<()> {
|
||||
pub fn memset(
|
||||
&mut self,
|
||||
address: impl TryToUsize,
|
||||
size: impl TryToUsize,
|
||||
val: u8,
|
||||
) -> Result<()> {
|
||||
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, .. } = self;
|
||||
@@ -174,11 +194,11 @@ where {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_len(&self) ->usize {
|
||||
pub fn get_len(&self) -> usize {
|
||||
self.memory.len()
|
||||
}
|
||||
|
||||
pub(crate) fn clear(&mut self) {
|
||||
pub(crate) fn clear(&mut self) {
|
||||
self.memory.clear();
|
||||
}
|
||||
}
|
||||
@@ -257,7 +277,11 @@ mod test {
|
||||
let mut data = [0_f32; 2];
|
||||
data[0] = loads[0][0] + loads[1][0];
|
||||
core_memory.execute_store(4, &data[0..1]).unwrap();
|
||||
let loads: &[f32] = core_memory.reserve_load(0, 16).unwrap().execute_load().unwrap()[0];
|
||||
let loads: &[f32] = core_memory
|
||||
.reserve_load(0, 16)
|
||||
.unwrap()
|
||||
.execute_load()
|
||||
.unwrap()[0];
|
||||
println!("{:?}", loads);
|
||||
assert!(loads[0] == 5_f32 && loads[1] == 12_f32 && loads[2] == 7_f32 && loads[3] == 15_f32)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fmt::Debug,
|
||||
@@ -9,32 +7,32 @@ use std::{
|
||||
use anyhow::Context;
|
||||
|
||||
pub trait FromFloat {
|
||||
fn from_f32(val :f32) -> Self;
|
||||
fn from_f64(val :f64) -> Self;
|
||||
fn from_f32(val: f32) -> Self;
|
||||
fn from_f64(val: f64) -> Self;
|
||||
}
|
||||
|
||||
impl FromFloat for f32 {
|
||||
fn from_f32(val :f32) -> Self {
|
||||
fn from_f32(val: f32) -> Self {
|
||||
val
|
||||
}
|
||||
|
||||
fn from_f64(val :f64) -> Self {
|
||||
fn from_f64(val: f64) -> Self {
|
||||
val as f32
|
||||
}
|
||||
}
|
||||
|
||||
impl FromFloat for f64 {
|
||||
fn from_f32(val :f32) -> Self {
|
||||
fn from_f32(val: f32) -> Self {
|
||||
val as f64
|
||||
}
|
||||
|
||||
fn from_f64(val :f64) -> Self {
|
||||
val
|
||||
fn from_f64(val: f64) -> Self {
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasTanh {
|
||||
fn tanh(self) -> Self ;
|
||||
fn tanh(self) -> Self;
|
||||
}
|
||||
|
||||
impl HasTanh for f32 {
|
||||
@@ -50,7 +48,7 @@ impl HasTanh for f64 {
|
||||
}
|
||||
|
||||
pub trait HasSigm {
|
||||
fn sigm(self) -> Self ;
|
||||
fn sigm(self) -> Self;
|
||||
}
|
||||
|
||||
impl HasSigm for f32 {
|
||||
@@ -91,34 +89,36 @@ impl HasExp for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub trait TryToUsize: TryInto<usize, Error = Self::TryError>
|
||||
where std::result::Result<usize, Self::TryError> : Context<usize, Self::TryError>
|
||||
pub trait TryToUsize: TryInto<usize, Error = Self::TryError>
|
||||
where
|
||||
std::result::Result<usize, Self::TryError>: Context<usize, Self::TryError>,
|
||||
{
|
||||
type TryError: Debug + Send + Sync + 'static + std::error::Error;
|
||||
}
|
||||
|
||||
impl<T, E> TryToUsize for T
|
||||
where
|
||||
impl<T, E> TryToUsize for T
|
||||
where
|
||||
T: TryInto<usize, Error = E>,
|
||||
E: Debug + Send + Sync + 'static + std::error::Error,
|
||||
std::result::Result<usize, E> : Context<usize, E>
|
||||
std::result::Result<usize, E>: Context<usize, E>,
|
||||
{
|
||||
type TryError = E;
|
||||
}
|
||||
|
||||
|
||||
pub trait FromUsize {
|
||||
fn from_usize(v: usize) -> Self;
|
||||
}
|
||||
|
||||
impl FromUsize for f32 {
|
||||
fn from_usize(v: usize) -> Self { v as f32 }
|
||||
fn from_usize(v: usize) -> Self {
|
||||
v as f32
|
||||
}
|
||||
}
|
||||
|
||||
impl FromUsize for f64 {
|
||||
fn from_usize(v: usize) -> Self { v as f64 }
|
||||
fn from_usize(v: usize) -> Self {
|
||||
v as f64
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UpcastDestTraits<T>:
|
||||
|
||||
@@ -250,7 +250,10 @@ fn detect_deadlock(cores_instructions: &[CoreInstructions]) -> Option<DeadlockIn
|
||||
let (this_core, target_core) = data.get_core_immcore();
|
||||
|
||||
if isa_recv(functor_address) {
|
||||
states.insert(this_core, CoreState::ReceivingFrom(target_core, data.imm_len()));
|
||||
states.insert(
|
||||
this_core,
|
||||
CoreState::ReceivingFrom(target_core, data.imm_len()),
|
||||
);
|
||||
} else if isa_send(functor_address) {
|
||||
states.insert(this_core, CoreState::SendingTo(target_core, data.imm_len()));
|
||||
} else {
|
||||
@@ -274,8 +277,7 @@ fn detect_deadlock(cores_instructions: &[CoreInstructions]) -> Option<DeadlockIn
|
||||
wait_for.insert(core_id, *target_core);
|
||||
}
|
||||
}
|
||||
CoreState::Working | CoreState::Halted => {
|
||||
}
|
||||
CoreState::Working | CoreState::Halted => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,16 +41,17 @@ impl SendRecv {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_send_recv<'a, 'b >(
|
||||
pub fn handle_send_recv<'a, 'b>(
|
||||
cpu: &'b mut CPU<'a>,
|
||||
core_instructions: & mut [CoreInstructions],
|
||||
send_recv: & mut SendRecv,
|
||||
core_instructions: &mut [CoreInstructions],
|
||||
send_recv: &mut SendRecv,
|
||||
core_result: InstructionStatus,
|
||||
) -> (bool, usize)
|
||||
where 'a : 'b
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
let transfer_memory = |cpu: &'b mut CPU<'a>,
|
||||
core_instructions: & mut [CoreInstructions],
|
||||
core_instructions: &mut [CoreInstructions],
|
||||
sender: Option<SendRecvInfo>,
|
||||
receiver: Option<SendRecvInfo>| {
|
||||
if let Some(sender) = sender
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
use std::fs::File;
|
||||
|
||||
use crate::{
|
||||
@@ -19,58 +18,41 @@ impl Trace {
|
||||
/////////////////Scalar/register Instructions//////////////////
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn pre_sldi(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
pub fn pre_sldi(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
}
|
||||
pub fn post_sldi(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_sldi(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_sld(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_sld(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_sld(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_sld(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_sadd(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_sadd(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_sadd(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_sadd(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_ssub(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_ssub(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_ssub(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_ssub(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_smul(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_smul(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_smul(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_smul(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_saddi(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_saddi(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_saddi(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_saddi(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_smuli(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_smuli(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
|
||||
pub fn post_smuli(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_smuli(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
///////////////////Matrix/vector Instructions////////////////////
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn pre_setbw(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_setbw(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_setbw(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_setbw(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_mvm<F, M, T>(&mut self, cores: &mut CPU, data: InstructionData)
|
||||
where
|
||||
@@ -80,7 +62,7 @@ impl Trace {
|
||||
M: UpcastDestTraits<M> + MemoryStorable + FromFloat,
|
||||
F: UpcastDestTraits<F> + MemoryStorable,
|
||||
{
|
||||
self.mvm_impl::<F,M,T>(cores, data, "Pre");
|
||||
self.mvm_impl::<F, M, T>(cores, data, "Pre");
|
||||
}
|
||||
|
||||
pub fn post_mvm<F, M, T>(&mut self, cores: &mut CPU, data: InstructionData)
|
||||
@@ -91,11 +73,15 @@ impl Trace {
|
||||
M: UpcastDestTraits<M> + MemoryStorable + FromFloat,
|
||||
F: UpcastDestTraits<F> + MemoryStorable,
|
||||
{
|
||||
self.mvm_impl::<F,M,T>(cores, data, "Post");
|
||||
self.mvm_impl::<F, M, T>(cores, data, "Post");
|
||||
}
|
||||
|
||||
pub fn mvm_impl<F, M, T>(&mut self, cores: &mut CPU, data: InstructionData, prefix : &'static str)
|
||||
where
|
||||
pub fn mvm_impl<F, M, T>(
|
||||
&mut self,
|
||||
cores: &mut CPU,
|
||||
data: InstructionData,
|
||||
prefix: &'static str,
|
||||
) where
|
||||
[F]: UpcastSlice<T> + UpcastSlice<M>,
|
||||
[M]: UpcastSlice<T>,
|
||||
T: UpcastDestTraits<T> + MemoryStorable,
|
||||
@@ -267,39 +253,27 @@ impl Trace {
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/////Communication/synchronization Instructions/////////////////
|
||||
/////////////////////////////////////////////////////////////////
|
||||
pub fn pre_ld(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_ld(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_ld(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_ld(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_st(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_st(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_st(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_st(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_lldi(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_lldi(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_lldi(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_lldi(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_lmv(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_lmv(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_lmv(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_lmv(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_send(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_send(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_send(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_send(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn pre_recv(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn pre_recv(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
|
||||
pub fn post_recv(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
}
|
||||
pub fn post_recv(&mut self, cores: &mut CPU, data: InstructionData) {}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ use crate::Executable;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{LazyLock, Mutex};
|
||||
|
||||
|
||||
#[cfg(not(any(feature = "tracing", feature = "profile_time")))]
|
||||
pub struct Trace {}
|
||||
|
||||
@@ -28,5 +27,4 @@ impl Trace {
|
||||
pub fn init(&mut self, num_core: usize, path: PathBuf) {}
|
||||
}
|
||||
|
||||
|
||||
pub static TRACER: LazyLock<Mutex<Trace>> = LazyLock::new(|| Trace::new().into());
|
||||
|
||||
@@ -8,7 +8,7 @@ pub mod profile_analysis;
|
||||
pub mod profile_isa;
|
||||
|
||||
pub struct Trace {
|
||||
instruction_times: HashMap<String, Vec<(u128,u128)>>,
|
||||
instruction_times: HashMap<String, Vec<(u128, u128)>>,
|
||||
core_start_time: HashMap<usize, Option<Instant>>,
|
||||
start_time: Instant,
|
||||
}
|
||||
@@ -51,7 +51,7 @@ impl Trace {
|
||||
Self {
|
||||
instruction_times,
|
||||
core_start_time: HashMap::new(),
|
||||
start_time: Instant::now()
|
||||
start_time: Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -145,17 +145,15 @@ pub fn print_textual_report(stats: &[InstructionStats]) {
|
||||
println!("{table}");
|
||||
}
|
||||
|
||||
|
||||
pub fn generate_interactive_report(
|
||||
timings: &HashMap<String, Vec<(u128, u128)>>,
|
||||
instructions_to_plot: &[&str], // <-- NEW: Only plot these
|
||||
file_path: &str,
|
||||
) {
|
||||
|
||||
use plotly::common::{Mode, Marker, Line};
|
||||
use plotly::layout::{Axis, Layout};
|
||||
use plotly::{Plot, Scatter};
|
||||
use std::collections::HashMap;
|
||||
use plotly::common::{Line, Marker, Mode};
|
||||
use plotly::layout::{Axis, Layout};
|
||||
use plotly::{Plot, Scatter};
|
||||
use std::collections::HashMap;
|
||||
let mut plot = Plot::new();
|
||||
|
||||
for &instruction_name in instructions_to_plot {
|
||||
@@ -163,8 +161,9 @@ use std::collections::HashMap;
|
||||
if let Some(times) = timings.get(instruction_name) {
|
||||
let x_axis: Vec<f64> = times.iter().map(|&(ts, _)| ts as f64).collect();
|
||||
let y_axis: Vec<f64> = times.iter().map(|&(_, dur)| dur as f64).collect();
|
||||
|
||||
let text_array: Vec<String> = times.iter()
|
||||
|
||||
let text_array: Vec<String> = times
|
||||
.iter()
|
||||
.map(|&(_, dur)| format_time(dur as f64))
|
||||
.collect();
|
||||
|
||||
@@ -181,7 +180,9 @@ use std::collections::HashMap;
|
||||
}
|
||||
|
||||
let layout = Layout::new()
|
||||
.title(plotly::common::Title::new("Simulator Timeline: Top Offenders"))
|
||||
.title(plotly::common::Title::new(
|
||||
"Simulator Timeline: Top Offenders",
|
||||
))
|
||||
.x_axis(Axis::new().title(plotly::common::Title::new("Absolute Time (ns)")))
|
||||
.y_axis(Axis::new().title(plotly::common::Title::new("Execution Duration")));
|
||||
|
||||
@@ -189,4 +190,3 @@ use std::collections::HashMap;
|
||||
plot.write_html(file_path);
|
||||
println!("🌐 Interactive timeline saved to {}", file_path);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,11 @@ impl Trace {
|
||||
start_time,
|
||||
} = self;
|
||||
let now = Instant::now();
|
||||
instruction_times
|
||||
.get_mut(name)
|
||||
.unwrap()
|
||||
.push((now.duration_since(*start_time).as_nanos(), now.duration_since(core_start_time[&core_indx].unwrap()).as_nanos()));
|
||||
instruction_times.get_mut(name).unwrap().push((
|
||||
now.duration_since(*start_time).as_nanos(),
|
||||
now.duration_since(core_start_time[&core_indx].unwrap())
|
||||
.as_nanos(),
|
||||
));
|
||||
self.core_start_time.insert(core_indx, None);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ pub struct Trace {
|
||||
out_files: Vec<File>,
|
||||
}
|
||||
|
||||
|
||||
impl Trace {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@@ -25,4 +24,3 @@ impl Trace {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -283,7 +283,6 @@ impl Trace {
|
||||
M: UpcastDestTraits<M> + MemoryStorable + FromFloat,
|
||||
F: UpcastDestTraits<F> + MemoryStorable,
|
||||
{
|
||||
|
||||
let (core_indx, rd, r1, mbiw, relu, group) = data.get_core_rd_r1_mbiw_immrelu_immgroup();
|
||||
let file: &mut File = self
|
||||
.out_files
|
||||
@@ -337,7 +336,7 @@ impl Trace {
|
||||
);
|
||||
pretty_print::print_slice::<_, F>(file, loads[0], 30);
|
||||
writeln!(file, "\tCrossbar[{}:{}](B): ", 0, crossbar_byte_size);
|
||||
pretty_print::print_slice::<_,F>(file, matrix, 30);
|
||||
pretty_print::print_slice::<_, F>(file, matrix, 30);
|
||||
writeln!(
|
||||
file,
|
||||
"\tLocal[{}:{}](out): ",
|
||||
@@ -409,11 +408,11 @@ impl Trace {
|
||||
.unwrap();
|
||||
writeln!(file, "{} Memory:", prefix);
|
||||
write!(file, "\tLocal[{}:{}](A): ", r1_final, r1_final + byte_len);
|
||||
pretty_print::print_slice::<_,f32>(file, loads[0], 30);
|
||||
write!(file, "\tLocal[{}:{}](B): ", r2_final , r2_final + byte_len);
|
||||
pretty_print::print_slice::<_,f32>(file, loads[1], 30);
|
||||
write!(file, "\tLocal[{}:{}](out): ", rd_final, rd_final+ byte_len);
|
||||
pretty_print::print_slice::<_,f32>(file, loads[2], 30);
|
||||
pretty_print::print_slice::<_, f32>(file, loads[0], 30);
|
||||
write!(file, "\tLocal[{}:{}](B): ", r2_final, r2_final + byte_len);
|
||||
pretty_print::print_slice::<_, f32>(file, loads[1], 30);
|
||||
write!(file, "\tLocal[{}:{}](out): ", rd_final, rd_final + byte_len);
|
||||
pretty_print::print_slice::<_, f32>(file, loads[2], 30);
|
||||
if prefix == "Post" {
|
||||
writeln!(file, "\n###############################################\n");
|
||||
}
|
||||
@@ -1027,9 +1026,9 @@ impl Trace {
|
||||
let core_memory = core.load::<u8>(rd_val, imm_len).unwrap();
|
||||
writeln!(file, "{} Memory:", prefix);
|
||||
writeln!(file, "\tHost[{}:{}]: ", r1_val, r1_val + imm_len as usize,);
|
||||
pretty_print::print_slice::<_,f32>(file, global_memory[0], 30);
|
||||
pretty_print::print_slice::<_, f32>(file, global_memory[0], 30);
|
||||
writeln!(file, "\tLocal[{}:{}]: ", rd_val, rd_val + imm_len as usize,);
|
||||
pretty_print::print_slice::<_,f32>(file, core_memory[0], 30);
|
||||
pretty_print::print_slice::<_, f32>(file, core_memory[0], 30);
|
||||
|
||||
if prefix == "Post" {
|
||||
writeln!(file, "\n###############################################\n");
|
||||
@@ -1079,9 +1078,9 @@ impl Trace {
|
||||
let global_memory = host.load::<u8>(rd_val, imm_len).unwrap();
|
||||
writeln!(file, "{} Memory:", prefix);
|
||||
writeln!(file, "\tLocal[{}:{}]: ", r1_val, r1_val + imm_len as usize,);
|
||||
pretty_print::print_slice::<_,f32>(file, core_memory[0], 30);
|
||||
pretty_print::print_slice::<_, f32>(file, core_memory[0], 30);
|
||||
writeln!(file, "\tHost[{}:{}]: ", rd_val, rd_val + imm_len as usize,);
|
||||
pretty_print::print_slice::<_,f32>(file, global_memory[0], 30);
|
||||
pretty_print::print_slice::<_, f32>(file, global_memory[0], 30);
|
||||
|
||||
if prefix == "Post" {
|
||||
writeln!(file, "\n###############################################\n");
|
||||
@@ -1096,7 +1095,6 @@ impl Trace {
|
||||
self.st_impl(cores, data, "Pre");
|
||||
}
|
||||
|
||||
|
||||
pub fn pre_lldi(&mut self, cores: &mut CPU, data: InstructionData) {
|
||||
let (core, rd, imm) = data.get_core_rd_imm();
|
||||
let file: &mut File = self
|
||||
@@ -1136,8 +1134,7 @@ impl Trace {
|
||||
// Ok(InstructionStatus::Completed)
|
||||
}
|
||||
|
||||
fn lmv_impl (&mut self, cores: &mut CPU, data: InstructionData, prefix: &'static str) {
|
||||
|
||||
fn lmv_impl(&mut self, cores: &mut CPU, data: InstructionData, prefix: &'static str) {
|
||||
let (core, rd, r1, _, imm_len, offset_select, offset_value) =
|
||||
data.get_core_rd_r1_r2_immlen_offset();
|
||||
let file: &mut File = self
|
||||
@@ -1169,14 +1166,17 @@ impl Trace {
|
||||
let r1_val = add_offset_r1(r1_val, offset_select, offset_value);
|
||||
let rd_val = add_offset_rd(rd_val, offset_select, offset_value);
|
||||
let core_memory = core
|
||||
.reserve_load(r1_val, imm_len).unwrap()
|
||||
.reserve_load(rd_val, imm_len).unwrap()
|
||||
.execute_load::<u8>().unwrap();
|
||||
.reserve_load(r1_val, imm_len)
|
||||
.unwrap()
|
||||
.reserve_load(rd_val, imm_len)
|
||||
.unwrap()
|
||||
.execute_load::<u8>()
|
||||
.unwrap();
|
||||
writeln!(file, "{} Memory:", prefix);
|
||||
writeln!(file, "\tLocal[{}:{}]: ", r1_val, r1_val + imm_len as usize,);
|
||||
pretty_print::print_slice::<_,f32>(file, core_memory[0], 30);
|
||||
pretty_print::print_slice::<_, f32>(file, core_memory[0], 30);
|
||||
writeln!(file, "\tLocal[{}:{}]: ", rd_val, rd_val + imm_len as usize,);
|
||||
pretty_print::print_slice::<_,f32>(file, core_memory[1], 30);
|
||||
pretty_print::print_slice::<_, f32>(file, core_memory[1], 30);
|
||||
|
||||
if prefix == "Post" {
|
||||
writeln!(file, "\n###############################################\n");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use anyhow::{Result,Context};
|
||||
use anyhow::{Context, Result};
|
||||
use std::{fmt::Debug, mem::transmute};
|
||||
|
||||
|
||||
pub trait AddressArg {
|
||||
fn to_address_usize(self) -> Result<usize>;
|
||||
}
|
||||
@@ -36,42 +35,56 @@ impl AddressArg for i64 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn address_to_usize(address: i32) -> usize {
|
||||
address as u32 as usize
|
||||
}
|
||||
|
||||
fn add_offset_impl(address: usize, offset_select : i32, offset_value : i32, id:i32) -> usize{
|
||||
assert!(offset_select == 1 || offset_select == 2 || offset_select == 4 || offset_value == 0, "offset_select not a bit field");
|
||||
let offset_value = (offset_select & id) * offset_value;
|
||||
if offset_value > 0 {
|
||||
address + offset_value as usize
|
||||
} else {
|
||||
address - offset_value as usize
|
||||
}
|
||||
fn add_offset_impl(address: usize, offset_select: i32, offset_value: i32, id: i32) -> usize {
|
||||
assert!(
|
||||
(0..=7).contains(&offset_select),
|
||||
"offset_select is not a 3-bit field"
|
||||
);
|
||||
if offset_select & id == 0 {
|
||||
address
|
||||
} else {
|
||||
address
|
||||
.checked_add_signed(offset_value as isize)
|
||||
.expect("address offset overflow")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn add_offset_rd(address: i32, offset_select : i32, offset_value : i32) -> usize
|
||||
{
|
||||
let address = address_to_usize(address);
|
||||
add_offset_impl(address, offset_select, offset_value, 4)
|
||||
}
|
||||
|
||||
pub fn add_offset_r1(address: i32, offset_select : i32, offset_value : i32) -> usize
|
||||
{
|
||||
pub fn add_offset_rd(address: i32, offset_select: i32, offset_value: i32) -> usize {
|
||||
let address = address_to_usize(address);
|
||||
add_offset_impl(address, offset_select, offset_value, 1)
|
||||
}
|
||||
|
||||
pub fn add_offset_r2(address: i32, offset_select : i32, offset_value : i32) -> usize
|
||||
{
|
||||
pub fn add_offset_r1(address: i32, offset_select: i32, offset_value: i32) -> usize {
|
||||
let address = address_to_usize(address);
|
||||
add_offset_impl(address, offset_select, offset_value, 2)
|
||||
}
|
||||
|
||||
|
||||
pub fn pack_float_in_i32(val : impl TryInto<f32>) -> i32 {
|
||||
let val = val.try_into().unwrap_or_else( |x| panic!("Cannot parse into f32"));
|
||||
f32::to_bits(val).cast_signed()
|
||||
pub fn add_offset_r2(address: i32, offset_select: i32, offset_value: i32) -> usize {
|
||||
let address = address_to_usize(address);
|
||||
add_offset_impl(address, offset_select, offset_value, 4)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{add_offset_r1, add_offset_r2, add_offset_rd};
|
||||
|
||||
#[test]
|
||||
fn offset_select_uses_rd_rs1_rs2_bit_order() {
|
||||
assert_eq!(add_offset_rd(100, 1, 7), 107);
|
||||
assert_eq!(add_offset_r1(100, 2, 7), 107);
|
||||
assert_eq!(add_offset_r2(100, 4, 7), 107);
|
||||
assert_eq!(add_offset_rd(100, 6, 7), 100);
|
||||
assert_eq!(add_offset_r1(100, 7, -7), 93);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pack_float_in_i32(val: impl TryInto<f32>) -> i32 {
|
||||
let val = val
|
||||
.try_into()
|
||||
.unwrap_or_else(|x| panic!("Cannot parse into f32"));
|
||||
f32::to_bits(val).cast_signed()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use pimcore::{
|
||||
memory_manager::CoreMemory,
|
||||
};
|
||||
|
||||
fn simple_read(path: &Path) -> Vec<f32> {
|
||||
fn simple_read(path: &Path) -> Vec<f32> {
|
||||
if !path.exists() {
|
||||
panic!("{:?} not exists", path)
|
||||
}
|
||||
@@ -19,9 +19,7 @@ fn simple_read(path: &Path) -> Vec<f32> {
|
||||
}
|
||||
|
||||
/// mvmul Test
|
||||
fn mvmul_f32(err: &str)
|
||||
where
|
||||
{
|
||||
fn mvmul_f32(err: &str) {
|
||||
let matrix = simple_read(Path::new("tests/B.txt"));
|
||||
let mut crossbar = Crossbar::new(1024 * size_of::<f32>(), 1024, CoreMemory::new());
|
||||
crossbar.execute_store(&matrix).unwrap();
|
||||
@@ -36,7 +34,9 @@ where
|
||||
inst_builder.make_inst(sldi, idata_build.set_rdimm(1, 0).build());
|
||||
inst_builder.make_inst(
|
||||
sldi,
|
||||
idata_build.set_rdimm(3, 1024 * size_of::<f32>() as i32).build(),
|
||||
idata_build
|
||||
.set_rdimm(3, 1024 * size_of::<f32>() as i32)
|
||||
.build(),
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
setbw,
|
||||
@@ -48,7 +48,7 @@ where
|
||||
mvmul,
|
||||
idata_build
|
||||
.set_rdr1(3, 1)
|
||||
.set_mbiw_immrelu_immgroup(8*size_of::<f32>() as i32, 0, 0)
|
||||
.set_mbiw_immrelu_immgroup(8 * size_of::<f32>() as i32, 0, 0)
|
||||
.build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
@@ -59,8 +59,11 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<f32>(1024 * size_of::<f32>(), 1024*size_of::<f32>()).unwrap()[0].iter().zip(
|
||||
simple_read(Path::new("tests/X.txt")) ).all(|(&a,b) : (&f32, f32)| {a-b < 0.001}),
|
||||
.load::<f32>(1024 * size_of::<f32>(), 1024 * size_of::<f32>())
|
||||
.unwrap()[0]
|
||||
.iter()
|
||||
.zip(simple_read(Path::new("tests/X.txt")))
|
||||
.all(|(&a, b): (&f32, f32)| { a - b < 0.001 }),
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
@@ -69,6 +72,4 @@ where
|
||||
#[test]
|
||||
fn mvmul_big_test() {
|
||||
mvmul_f32("mvmul_f32");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ use std::{
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use pimcore::{
|
||||
cpu::crossbar::Crossbar,
|
||||
json_to_instruction::json_to_executor,
|
||||
memory_manager::CoreMemory,
|
||||
cpu::crossbar::Crossbar, json_to_instruction::json_to_executor, memory_manager::CoreMemory,
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
@@ -95,9 +93,14 @@ fn json_folder_tester() {
|
||||
.map(|core_crossbars| core_crossbars.iter().collect())
|
||||
.collect();
|
||||
|
||||
let mut executable = json_to_executor::json_to_executor(config, &mut core_readers, crossbars);
|
||||
let mut executable =
|
||||
json_to_executor::json_to_executor(config, &mut core_readers, crossbars);
|
||||
let memory = fs::read(folder.join("memory.bin")).unwrap();
|
||||
executable.cpu_mut().host().execute_store(0, &memory).unwrap();
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.execute_store(0, &memory)
|
||||
.unwrap();
|
||||
executable.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,26 +7,17 @@ use pimcore::{
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Function not found for the requested size") ]
|
||||
#[should_panic(expected = "Function not found for the requested size")]
|
||||
fn wrong_size_place_holder() {
|
||||
let cpu = common::empty_cpu(0);
|
||||
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(
|
||||
setbw,
|
||||
idata_build
|
||||
.set_ibiw_obiw(55, 55)
|
||||
.build(),
|
||||
);
|
||||
inst_builder.make_inst(setbw, idata_build.set_ibiw_obiw(55, 55).build());
|
||||
inst_builder.make_inst(
|
||||
vvadd,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 2)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 2).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
@@ -39,97 +30,88 @@ fn unsupported_8_bit_vectors_do_not_alias_f32() {
|
||||
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(
|
||||
setbw,
|
||||
idata_build.set_ibiw_obiw(8, 8).build(),
|
||||
);
|
||||
inst_builder.make_inst(setbw, idata_build.set_ibiw_obiw(8, 8).build());
|
||||
inst_builder.make_inst(
|
||||
vvadd,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 2)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 2).set_imm_len(8).build(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn place_holder(inst : InstructionType) {
|
||||
fn place_holder(inst: InstructionType) {
|
||||
let mut cpu = common::empty_cpu(0);
|
||||
let mut idata_build = InstructionDataBuilder::new();
|
||||
idata_build.set_core_indx(0).fix_core_indx();
|
||||
inst(&mut cpu, idata_build.build()).unwrap();
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vvadd_placeholder() {
|
||||
place_holder(vvadd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vvsub_placeholder() {
|
||||
place_holder(vvsub);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vvmul_placeholder() {
|
||||
place_holder(vvmul);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vvdmul_placeholder() {
|
||||
place_holder(vvdmul);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vvmax_placeholder() {
|
||||
place_holder(vvmax);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vavg_placeholder() {
|
||||
place_holder(vavg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vrelu_placeholder() {
|
||||
place_holder(vrelu);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vtanh_placeholder() {
|
||||
place_holder(vtanh);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn vsigm_placeholder() {
|
||||
place_holder(vsigm);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version") ]
|
||||
#[should_panic(expected = "You are calling a placeholder, the real call is the generic version")]
|
||||
fn mvmul_placeholder() {
|
||||
place_holder(mvmul);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic ]
|
||||
#[should_panic]
|
||||
fn vvsll_why_inst() {
|
||||
place_holder(vvsll);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic ]
|
||||
#[should_panic]
|
||||
fn vvsra_why_inst() {
|
||||
place_holder(vvsra);
|
||||
}
|
||||
|
||||
@@ -53,10 +53,7 @@ where
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
vvadd,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 2)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 2).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
@@ -67,7 +64,8 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>()).unwrap()[0],
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![
|
||||
10.0.into(),
|
||||
12.0.into(),
|
||||
@@ -86,17 +84,22 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
)
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -157,10 +160,7 @@ where
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
vvsub,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 2)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 2).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
@@ -171,7 +171,8 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>()).unwrap()[0],
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![
|
||||
(-8.0).into(),
|
||||
(-8.0).into(),
|
||||
@@ -190,17 +191,22 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
)
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -261,10 +267,7 @@ where
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
vvmul,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 2)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 2).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
@@ -275,7 +278,8 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>()).unwrap()[0],
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![
|
||||
(9.0).into(),
|
||||
(20.0).into(),
|
||||
@@ -294,17 +298,22 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
)
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -365,10 +374,7 @@ where
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
vvdmul,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 2)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 2).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
@@ -379,10 +385,9 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), size_of::<T>()).unwrap()[0],
|
||||
vec![
|
||||
(492.0).into(),
|
||||
],
|
||||
.load::<T>(16 * size_of::<F>(), size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![(492.0).into(),],
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
@@ -391,17 +396,19 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(16 * size_of::<F>() + size_of::<T>(), 4 * size_of::<i32>())
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -462,10 +469,7 @@ where
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
vvmax,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 2)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 2).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
@@ -476,16 +480,17 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>()).unwrap()[0],
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![
|
||||
9.0.into(),
|
||||
10.0.into(),
|
||||
11.0.into(),
|
||||
12.0.into(),
|
||||
13.0.into(),
|
||||
14.0.into(),
|
||||
15.0.into(),
|
||||
16.0.into(),
|
||||
9.0.into(),
|
||||
10.0.into(),
|
||||
11.0.into(),
|
||||
12.0.into(),
|
||||
13.0.into(),
|
||||
14.0.into(),
|
||||
15.0.into(),
|
||||
16.0.into(),
|
||||
],
|
||||
"Wrong result for {}",
|
||||
err
|
||||
@@ -495,17 +500,22 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
)
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -577,10 +587,9 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), size_of::<T>()).unwrap()[0],
|
||||
vec![
|
||||
7.5.into(),
|
||||
],
|
||||
.load::<T>(16 * size_of::<F>(), size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![7.5.into(),],
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
@@ -589,17 +598,19 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(16 * size_of::<F>() + size_of::<T>(), 4 * size_of::<i32>())
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -656,10 +667,7 @@ where
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
vrelu,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 1)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 1).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
@@ -670,16 +678,17 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), 8*size_of::<T>()).unwrap()[0],
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![
|
||||
0.0.into(),
|
||||
2.0.into(),
|
||||
11.0.into(),
|
||||
0.0.into(),
|
||||
13.0.into(),
|
||||
0.0.into(),
|
||||
7.0.into(),
|
||||
0.0.into(),
|
||||
0.0.into(),
|
||||
2.0.into(),
|
||||
11.0.into(),
|
||||
0.0.into(),
|
||||
13.0.into(),
|
||||
0.0.into(),
|
||||
7.0.into(),
|
||||
0.0.into(),
|
||||
],
|
||||
"Wrong result for {}",
|
||||
err
|
||||
@@ -689,17 +698,22 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + 8*size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
)
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -756,32 +770,32 @@ where
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
vtanh,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 1)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 1).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
executable.execute();
|
||||
|
||||
// Check result correct
|
||||
|
||||
|
||||
assert!(
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), 8*size_of::<T>()).unwrap()[0].iter().zip(
|
||||
vec![
|
||||
T::from(0.1).tanh(),
|
||||
T::from(0.2).tanh(),
|
||||
T::from(0.3).tanh(),
|
||||
T::from(0.4).tanh(),
|
||||
T::from(0.5).tanh(),
|
||||
T::from(0.6).tanh(),
|
||||
T::from(0.7).tanh(),
|
||||
T::from(0.8).tanh(),
|
||||
]).all(|(&a,b) : (&T, T)| {a-b < 0.001.into()}),
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>())
|
||||
.unwrap()[0]
|
||||
.iter()
|
||||
.zip(vec![
|
||||
T::from(0.1).tanh(),
|
||||
T::from(0.2).tanh(),
|
||||
T::from(0.3).tanh(),
|
||||
T::from(0.4).tanh(),
|
||||
T::from(0.5).tanh(),
|
||||
T::from(0.6).tanh(),
|
||||
T::from(0.7).tanh(),
|
||||
T::from(0.8).tanh(),
|
||||
])
|
||||
.all(|(&a, b): (&T, T)| { a - b < 0.001.into() }),
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
@@ -790,17 +804,22 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + 8*size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
)
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -815,7 +834,6 @@ fn vtanh_test() {
|
||||
vtanh_test_generic::<f64, f64>("vtanh<f64,f64>");
|
||||
}
|
||||
|
||||
|
||||
/// vsigm Test
|
||||
fn vsigm_test_generic<F, T>(err: &str)
|
||||
where
|
||||
@@ -858,32 +876,32 @@ where
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
vsigm,
|
||||
idata_build
|
||||
.set_rdr1r2(3, 1, 1)
|
||||
.set_imm_len(8)
|
||||
.build(),
|
||||
idata_build.set_rdr1r2(3, 1, 1).set_imm_len(8).build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
let mut executable = Executable::new(cpu, core_instruction);
|
||||
executable.execute();
|
||||
|
||||
// Check result correct
|
||||
|
||||
|
||||
assert!(
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(16 * size_of::<F>(), 8*size_of::<T>()).unwrap()[0].iter().zip(
|
||||
vec![
|
||||
T::from(0.1).sigm(),
|
||||
T::from(0.2).sigm(),
|
||||
T::from(0.3).sigm(),
|
||||
T::from(0.4).sigm(),
|
||||
T::from(0.5).sigm(),
|
||||
T::from(0.6).sigm(),
|
||||
T::from(0.7).sigm(),
|
||||
T::from(0.8).sigm(),
|
||||
]).all(|(&a,b) : (&T, T)| {a-b < 0.001.into()}),
|
||||
.load::<T>(16 * size_of::<F>(), 8 * size_of::<T>())
|
||||
.unwrap()[0]
|
||||
.iter()
|
||||
.zip(vec![
|
||||
T::from(0.1).sigm(),
|
||||
T::from(0.2).sigm(),
|
||||
T::from(0.3).sigm(),
|
||||
T::from(0.4).sigm(),
|
||||
T::from(0.5).sigm(),
|
||||
T::from(0.6).sigm(),
|
||||
T::from(0.7).sigm(),
|
||||
T::from(0.8).sigm(),
|
||||
])
|
||||
.all(|(&a, b): (&T, T)| { a - b < 0.001.into() }),
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
@@ -892,17 +910,22 @@ where
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 16 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 16 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&buff,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
16 * size_of::<F>() + 8*size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(
|
||||
16 * size_of::<F>() + 8 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
)
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -917,10 +940,8 @@ fn vsigm_test() {
|
||||
vsigm_test_generic::<f64, f64>("vsigm<f64,f64>");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// mvmul Test
|
||||
fn mvmul_test_generic<F,M, T>(err: &str, relu:i32)
|
||||
fn mvmul_test_generic<F, M, T>(err: &str, relu: i32)
|
||||
where
|
||||
F: From<f32> + std::fmt::Debug + PartialEq<F> + MemoryStorable,
|
||||
M: From<f32> + std::fmt::Debug + PartialEq<M> + MemoryStorable,
|
||||
@@ -948,12 +969,7 @@ where
|
||||
crossbar.execute_store(&matrix).unwrap();
|
||||
let mut cpu = pimcore::cpu::CPU::new(0, vec![vec![&crossbar]]);
|
||||
let (memory, _) = cpu.host().get_memory_crossbar();
|
||||
let vector: [F; _] = [
|
||||
1.0.into(),
|
||||
2.0.into(),
|
||||
3.0.into(),
|
||||
4.0.into(),
|
||||
];
|
||||
let vector: [F; _] = [1.0.into(), 2.0.into(), 3.0.into(), 4.0.into()];
|
||||
memory.execute_store(0, &vector).unwrap();
|
||||
|
||||
let mut inst_builder = InstructionsBuilder::new();
|
||||
@@ -974,7 +990,7 @@ where
|
||||
mvmul,
|
||||
idata_build
|
||||
.set_rdr1(3, 1)
|
||||
.set_mbiw_immrelu_immgroup(8*size_of::<M>() as i32, relu, 0)
|
||||
.set_mbiw_immrelu_immgroup(8 * size_of::<M>() as i32, relu, 0)
|
||||
.build(),
|
||||
);
|
||||
let core_instruction = vec![inst_builder.build().into()];
|
||||
@@ -982,54 +998,50 @@ where
|
||||
executable.execute();
|
||||
|
||||
// Check result correct
|
||||
if relu == 0 {
|
||||
assert_eq!(
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(4 * size_of::<F>(), 4*size_of::<T>()).unwrap()[0],
|
||||
vec![
|
||||
90.0.into(),
|
||||
(-24.0).into(),
|
||||
110.0.into(),
|
||||
120.0.into(),
|
||||
],
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
else {
|
||||
assert_eq!(
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(4 * size_of::<F>(), 4*size_of::<T>()).unwrap()[0],
|
||||
vec![
|
||||
90.0.into(),
|
||||
0.0.into(),
|
||||
110.0.into(),
|
||||
120.0.into(),
|
||||
],
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
if relu == 0 {
|
||||
assert_eq!(
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(4 * size_of::<F>(), 4 * size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![90.0.into(), (-24.0).into(), 110.0.into(), 120.0.into(),],
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
} else {
|
||||
assert_eq!(
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<T>(4 * size_of::<F>(), 4 * size_of::<T>())
|
||||
.unwrap()[0],
|
||||
vec![90.0.into(), 0.0.into(), 110.0.into(), 120.0.into(),],
|
||||
"Wrong result for {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
// Check first part equal
|
||||
assert_eq!(
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<F>(0, 4 * size_of::<F>()).unwrap()[0],
|
||||
.load::<F>(0, 4 * size_of::<F>())
|
||||
.unwrap()[0],
|
||||
&vector,
|
||||
"Altered first part for {}",
|
||||
err
|
||||
);
|
||||
//Check that later is 0
|
||||
assert_eq!(
|
||||
executable.cpu_mut().host().load::<i32>(
|
||||
4 * size_of::<F>() + 4*size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
).unwrap()[0],
|
||||
executable
|
||||
.cpu_mut()
|
||||
.host()
|
||||
.load::<i32>(
|
||||
4 * size_of::<F>() + 4 * size_of::<T>(),
|
||||
4 * size_of::<i32>()
|
||||
)
|
||||
.unwrap()[0],
|
||||
[0, 0, 0, 0],
|
||||
"Altered first part for {}",
|
||||
err
|
||||
@@ -1038,22 +1050,21 @@ where
|
||||
|
||||
#[test]
|
||||
fn mvmul_test() {
|
||||
mvmul_test_generic::<f32,f32,f32>("mvmul<f32,f32,f32>",0);
|
||||
mvmul_test_generic::<f32,f32,f64>("mvmul<f32,f32,f64>",0);
|
||||
mvmul_test_generic::<f32,f64,f32>("mvmul<f32,f64,f32>",0);
|
||||
mvmul_test_generic::<f32,f64,f64>("mvmul<f32,f64,f64>",0);
|
||||
mvmul_test_generic::<f64,f32,f32>("mvmul<f64,f32,f32>",0);
|
||||
mvmul_test_generic::<f64,f32,f64>("mvmul<f64,f32,f64>",0);
|
||||
mvmul_test_generic::<f64,f64,f32>("mvmul<f64,f64,f32>",0);
|
||||
mvmul_test_generic::<f64,f64,f64>("mvmul<f64,f64,f64>",0);
|
||||
|
||||
mvmul_test_generic::<f32,f32,f32>("mvmul<f32,f32,f32>",1);
|
||||
mvmul_test_generic::<f32,f32,f64>("mvmul<f32,f32,f64>",1);
|
||||
mvmul_test_generic::<f32,f64,f32>("mvmul<f32,f64,f32>",1);
|
||||
mvmul_test_generic::<f32,f64,f64>("mvmul<f32,f64,f64>",1);
|
||||
mvmul_test_generic::<f64,f32,f32>("mvmul<f64,f32,f32>",1);
|
||||
mvmul_test_generic::<f64,f32,f64>("mvmul<f64,f32,f64>",1);
|
||||
mvmul_test_generic::<f64,f64,f32>("mvmul<f64,f64,f32>",1);
|
||||
mvmul_test_generic::<f64,f64,f64>("mvmul<f64,f64,f64>",1);
|
||||
mvmul_test_generic::<f32, f32, f32>("mvmul<f32,f32,f32>", 0);
|
||||
mvmul_test_generic::<f32, f32, f64>("mvmul<f32,f32,f64>", 0);
|
||||
mvmul_test_generic::<f32, f64, f32>("mvmul<f32,f64,f32>", 0);
|
||||
mvmul_test_generic::<f32, f64, f64>("mvmul<f32,f64,f64>", 0);
|
||||
mvmul_test_generic::<f64, f32, f32>("mvmul<f64,f32,f32>", 0);
|
||||
mvmul_test_generic::<f64, f32, f64>("mvmul<f64,f32,f64>", 0);
|
||||
mvmul_test_generic::<f64, f64, f32>("mvmul<f64,f64,f32>", 0);
|
||||
mvmul_test_generic::<f64, f64, f64>("mvmul<f64,f64,f64>", 0);
|
||||
|
||||
mvmul_test_generic::<f32, f32, f32>("mvmul<f32,f32,f32>", 1);
|
||||
mvmul_test_generic::<f32, f32, f64>("mvmul<f32,f32,f64>", 1);
|
||||
mvmul_test_generic::<f32, f64, f32>("mvmul<f32,f64,f32>", 1);
|
||||
mvmul_test_generic::<f32, f64, f64>("mvmul<f32,f64,f64>", 1);
|
||||
mvmul_test_generic::<f64, f32, f32>("mvmul<f64,f32,f32>", 1);
|
||||
mvmul_test_generic::<f64, f32, f64>("mvmul<f64,f32,f64>", 1);
|
||||
mvmul_test_generic::<f64, f64, f32>("mvmul<f64,f64,f32>", 1);
|
||||
mvmul_test_generic::<f64, f64, f64>("mvmul<f64,f64,f64>", 1);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
mod common;
|
||||
|
||||
use pimcore::{
|
||||
Executable, CoreInstructionsBuilder,
|
||||
CoreInstructionsBuilder, Executable,
|
||||
instruction_set::{InstructionsBuilder, instruction_data::InstructionDataBuilder, isa::*},
|
||||
};
|
||||
|
||||
@@ -158,7 +158,12 @@ fn simple_send_recv_test() {
|
||||
let mut inst_builder = InstructionsBuilder::new();
|
||||
let mut idata_build = InstructionDataBuilder::new();
|
||||
idata_build.set_core_indx(1).fix_core_indx();
|
||||
inst_builder.make_inst(sldi, idata_build.set_rdimm(1, 3*size_of::<f32>() as i32).build());
|
||||
inst_builder.make_inst(
|
||||
sldi,
|
||||
idata_build
|
||||
.set_rdimm(1, 3 * size_of::<f32>() as i32)
|
||||
.build(),
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
send,
|
||||
idata_build
|
||||
@@ -188,15 +193,11 @@ fn simple_send_recv_test() {
|
||||
|
||||
assert_eq!(
|
||||
res.unwrap()[0],
|
||||
[
|
||||
4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0
|
||||
],
|
||||
[4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0],
|
||||
"send_recv failed to store"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 1 -> 3
|
||||
// 2 -> 3
|
||||
// 3 <- 2
|
||||
@@ -210,53 +211,54 @@ fn simple_send_recv_test() {
|
||||
fn multiple_send_recv_test() {
|
||||
let mut cpu = common::empty_cpu(4);
|
||||
let mut core_instruction_builder = CoreInstructionsBuilder::new(4);
|
||||
let buff: [f32; _] = [
|
||||
1.0, 1.0, 1.0, 1.0, 1.0
|
||||
];
|
||||
let buff: [f32; _] = [1.0, 1.0, 1.0, 1.0, 1.0];
|
||||
cpu.core(1).execute_store(0, &buff).unwrap();
|
||||
let buff: [f32; _] = [
|
||||
2.0, 2.0, 2.0, 2.0, 2.0
|
||||
];
|
||||
let buff: [f32; _] = [2.0, 2.0, 2.0, 2.0, 2.0];
|
||||
cpu.core(2).execute_store(0, &buff).unwrap();
|
||||
let buff: [f32; _] = [
|
||||
3.0, 3.0, 3.0, 3.0, 3.0
|
||||
];
|
||||
let buff: [f32; _] = [3.0, 3.0, 3.0, 3.0, 3.0];
|
||||
cpu.core(3).execute_store(0, &buff).unwrap();
|
||||
let buff: [f32; _] = [
|
||||
4.0, 4.0, 4.0, 4.0, 4.0
|
||||
];
|
||||
let buff: [f32; _] = [4.0, 4.0, 4.0, 4.0, 4.0];
|
||||
cpu.core(4).execute_store(0, &buff).unwrap();
|
||||
|
||||
let send_inst = |inst_builder: &mut InstructionsBuilder, from: i32, to: i32| {
|
||||
let mut idata_build = InstructionDataBuilder::new();
|
||||
idata_build.set_core_indx(from).fix_core_indx();
|
||||
inst_builder.make_inst(sldi, idata_build.set_rdimm(1, from*size_of::<f32>() as i32).build());
|
||||
inst_builder.make_inst(
|
||||
send,
|
||||
idata_build
|
||||
.set_r1(1)
|
||||
.set_imm_core(to)
|
||||
.set_imm_len(size_of::<f32>() as i32)
|
||||
.build(),
|
||||
);
|
||||
let mut idata_build = InstructionDataBuilder::new();
|
||||
idata_build.set_core_indx(from).fix_core_indx();
|
||||
inst_builder.make_inst(
|
||||
sldi,
|
||||
idata_build
|
||||
.set_rdimm(1, from * size_of::<f32>() as i32)
|
||||
.build(),
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
send,
|
||||
idata_build
|
||||
.set_r1(1)
|
||||
.set_imm_core(to)
|
||||
.set_imm_len(size_of::<f32>() as i32)
|
||||
.build(),
|
||||
);
|
||||
};
|
||||
|
||||
let recv_inst = |inst_builder: &mut InstructionsBuilder, to: i32, from: i32| {
|
||||
let mut idata_build = InstructionDataBuilder::new();
|
||||
idata_build.set_core_indx(to).fix_core_indx();
|
||||
inst_builder.make_inst(sldi, idata_build.set_rdimm(1, from*size_of::<f32>() as i32).build());
|
||||
inst_builder.make_inst(
|
||||
recv,
|
||||
idata_build
|
||||
.set_rd(1)
|
||||
.set_imm_core(from)
|
||||
.set_imm_len(size_of::<f32>() as i32)
|
||||
.build(),
|
||||
);
|
||||
let mut idata_build = InstructionDataBuilder::new();
|
||||
idata_build.set_core_indx(to).fix_core_indx();
|
||||
inst_builder.make_inst(
|
||||
sldi,
|
||||
idata_build
|
||||
.set_rdimm(1, from * size_of::<f32>() as i32)
|
||||
.build(),
|
||||
);
|
||||
inst_builder.make_inst(
|
||||
recv,
|
||||
idata_build
|
||||
.set_rd(1)
|
||||
.set_imm_core(from)
|
||||
.set_imm_len(size_of::<f32>() as i32)
|
||||
.build(),
|
||||
);
|
||||
};
|
||||
let mut inst_builder = InstructionsBuilder::new();
|
||||
|
||||
|
||||
// 1 -> 3
|
||||
send_inst(&mut inst_builder, 1, 3);
|
||||
core_instruction_builder.set_core(1, inst_builder.build());
|
||||
@@ -289,7 +291,7 @@ fn multiple_send_recv_test() {
|
||||
|
||||
assert_eq!(
|
||||
res.unwrap()[0],
|
||||
[ 1.0, 2.0, 3.0, 4.0 ],
|
||||
[1.0, 2.0, 3.0, 4.0],
|
||||
"send_recv failed to store"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user