implement vmv in pim-simulator
Validate Operations / validate-operations (push) Has been cancelled

fix offset selection implementation to match the pim isa
automatic code format for pim-simulator
This commit is contained in:
NiccoloN
2026-07-31 17:24:19 +02:00
parent a0131c6f7a
commit 9ca1a0ed9f
23 changed files with 584 additions and 497 deletions
@@ -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);
}
+206 -195
View File
@@ -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"
);
}