app: multi_core_inverter: de-virtualize the stimuli

this gets like a 5% perf gain.
there are obviously cleaner ways to do it (e.g. use a ListVisitor),
but this is only a proof of concept.

given the low perf difference, i'll likely revert this or explore other
options.
This commit is contained in:
2022-08-13 03:51:52 -07:00
parent bbb8b2b9ae
commit 434dc2cbd5

View File

@@ -36,13 +36,14 @@
//! $ pushd crates/coremem; cargo run --release --bin viewer ../../out/applications/multi_core_inverter/0/ ; popd //! $ pushd crates/coremem; cargo run --release --bin viewer ../../out/applications/multi_core_inverter/0/ ; popd
//! ``` //! ```
use coremem::cross::compound::list::{self, Prependable};
use coremem::geom::{Coord as _, Meters, Torus}; use coremem::geom::{Coord as _, Meters, Torus};
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor}; use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor};
use coremem::meas; use coremem::meas;
use coremem::real::{self, Real as _}; use coremem::real::{self, Real as _};
use coremem::sim::spirv::{self, SpirvSim}; use coremem::sim::spirv::{self, SpirvSim};
use coremem::sim::units::Seconds; use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Exp, Gated, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Exp, Gated, Shifted};
use coremem::Driver; use coremem::Driver;
type R = real::R32; type R = real::R32;
@@ -60,6 +61,52 @@ enum DriveType {
Float, Float,
} }
struct HoldHigh;
struct ReleaseHigh;
struct HoldLow;
struct ReleaseLow;
struct Float;
impl HoldHigh {
fn stim<P: Prependable>(
&self, prev: P, p: Params, cycle: u32, r: Torus
) -> list::Prepended<HoldStim, P> {
prev.prepend(control_signal_hold(p, r, cycle, DriveType::HoldHigh))
}
}
impl ReleaseHigh {
fn stim<P: Prependable>(
&self, prev: P, p: Params, cycle: u32, r: Torus
) -> list::Prepended<ReleaseStim, P> {
prev.prepend(control_signal_release(p, r, cycle, DriveType::ReleaseHigh))
}
}
impl HoldLow {
fn stim<P: Prependable>(
&self, prev: P, p: Params, cycle: u32, r: Torus
) -> list::Prepended<HoldStim, P> {
prev.prepend(control_signal_hold(p, r, cycle, DriveType::HoldLow))
}
}
impl ReleaseLow {
fn stim<P: Prependable>(
&self, prev: P, p: Params, cycle: u32, r: Torus
) -> list::Prepended<ReleaseStim, P> {
prev.prepend(control_signal_release(p, r, cycle, DriveType::ReleaseLow))
}
}
impl Float {
fn stim<P>(
&self, prev: P, _p: Params, _cycle: u32, _r: Torus
) -> P {
prev
}
}
impl DriveType { impl DriveType {
fn direction(&self) -> i32 { fn direction(&self) -> i32 {
use DriveType::*; use DriveType::*;
@@ -83,6 +130,40 @@ impl DriveType {
} }
} }
#[derive(Copy, Clone)]
struct Params {
input_magnitude: f32,
clock_phase_duration: f32,
clock_decay: f32, // exp decay half-life
}
type HoldStim = CurlStimulus<Torus, Gated<f32>>;
type ReleaseStim = CurlStimulus<Torus, Shifted<Gated<Exp<f32>>>>;
fn control_signal_hold(params: Params, region: Torus, cycle: u32, ty: DriveType) -> HoldStim {
let area = region.cross_section();
let amp = ty.direction() as f32 * params.input_magnitude / area;
let start = params.clock_phase_duration * cycle as f32;
// simple square wave:
let wave = Gated::new(amp, start, start + params.clock_phase_duration);
CurlStimulus::new(
region.clone(),
wave.clone(),
)
}
fn control_signal_release(params: Params, region: Torus, cycle: u32, ty: DriveType) -> ReleaseStim {
let area = region.cross_section();
let amp = ty.direction() as f32 * params.input_magnitude / area;
let start = params.clock_phase_duration * cycle as f32;
// decaying exponential wave:
let wave = Exp::new_at(amp, start, params.clock_decay);
CurlStimulus::new(
region.clone(),
wave.clone(),
)
}
fn main() { fn main() {
coremem::init_logging(); coremem::init_logging();
// coremem::init_debug(); // coremem::init_debug();
@@ -91,9 +172,11 @@ fn main() {
let ps = |n| n as f32 * 1e-12; let ps = |n| n as f32 * 1e-12;
let feat_size = um(10); let feat_size = um(10);
let input_magnitude = 1.0e9; let params = Params {
let clock_phase_duration = ps(4000); input_magnitude: 1.0e9,
let clock_decay = ps(250); // exp decay half-life clock_phase_duration: ps(4000),
clock_decay: ps(250),
};
// 's' = core (ferromagnetic part) // 's' = core (ferromagnetic part)
let s_major = um(160); let s_major = um(160);
@@ -123,83 +206,56 @@ fn main() {
let s = |n| Torus::new_xy(Meters::new(sx(n), sy, sz), s_major, s_minor); let s = |n| Torus::new_xy(Meters::new(sx(n), sy, sz), s_major, s_minor);
// coupling(n) is the wire which couples core n into core n+1 // coupling(n) is the wire which couples core n into core n+1
let coupling = |n| Torus::new_xz(Meters::new(couplingx(n), sy, sz), coupling_major, coupling_minor); let coupling = |n| Torus::new_xz(Meters::new(couplingx(n), sy, sz), coupling_major, coupling_minor);
let control_signal = |driver: &mut Driver<Sim>, region: &Torus, cycle: u32, ty: DriveType| {
let area = region.cross_section();
let amp = ty.direction() as f32 * input_magnitude / area;
let start = clock_phase_duration * cycle as f32;
if ty.is_hold() {
// simple square wave:
let wave = Gated::new(amp, start, start + clock_phase_duration);
let stim = CurlStimulus::new(
region.clone(),
wave.clone(),
);
driver.add_stimulus(stim);
} else if ty.is_release() {
// decaying exponential wave:
let wave = Exp::new_at(amp, start, clock_decay);
let stim = CurlStimulus::new(
region.clone(),
wave.clone(),
);
driver.add_stimulus(stim);
} // else: Float
// sine wave (untested):
// let wave = Sinusoid1::from_wavelength(direction as f32 * input_magnitude / area, clock_phase_duration * 2.0)
// .half_cycle()
// .shifted(clock_phase_duration * cycle as f32);
};
//////// define the control signals/transitions //////// define the control signals/transitions
// each row N denotes the drive currents at clock cycle N. // each row N denotes the drive currents at clock cycle N.
// each col M denotes the drive current at core M. // each col M denotes the drive current at core M.
use DriveType::*;
// let s0_init_state = HoldHigh; // logic high // let s0_init_state = HoldHigh; // logic high
let s0_init_state = HoldLow; // logic low let s0_init_state = HoldLow; // logic low
let s0_rel_state = ReleaseLow; let s0_rel_state = ReleaseLow;
let drive_map = [ let drive_map = (
// charge each device to '1' // charge each device to '1'
[s0_init_state,HoldHigh, HoldHigh, HoldHigh, HoldHigh], (s0_init_state,HoldHigh, HoldHigh, HoldHigh, HoldHigh),
// this is when we'd ordinarily open S0 for write // this is when we'd ordinarily open S0 for write
[s0_rel_state, HoldHigh, HoldHigh, HoldHigh, HoldHigh], (s0_rel_state, HoldHigh, HoldHigh, HoldHigh, HoldHigh),
// this is when S0 would ordinarily receive a write // this is when S0 would ordinarily receive a write
[Float, HoldHigh, HoldHigh, HoldHigh, HoldHigh], (Float, HoldHigh, HoldHigh, HoldHigh, HoldHigh),
// open S1 for write // open S1 for write
[Float, ReleaseHigh, HoldHigh, HoldHigh, HoldHigh], (Float, ReleaseHigh, HoldHigh, HoldHigh, HoldHigh),
// write S0' => S1 // write S0' => S1
[HoldLow, Float, HoldHigh, HoldHigh, HoldHigh], (HoldLow, Float, HoldHigh, HoldHigh, HoldHigh),
// open S2 for write // open S2 for write
[HoldLow, Float, ReleaseHigh, HoldHigh, HoldHigh], (HoldLow, Float, ReleaseHigh, HoldHigh, HoldHigh),
// write S1' => S2 // write S1' => S2
[HoldLow, HoldLow, Float, HoldHigh, HoldHigh], (HoldLow, HoldLow, Float, HoldHigh, HoldHigh),
// open S3 for write // open S3 for write
[HoldLow, HoldLow, Float, ReleaseHigh, HoldHigh], (HoldLow, HoldLow, Float, ReleaseHigh, HoldHigh),
// write S2' => S3; RESET S0 // write S2' => S3; RESET S0
[HoldHigh, HoldLow, HoldLow, Float, HoldHigh], (HoldHigh, HoldLow, HoldLow, Float, HoldHigh),
// open S4 for write // open S4 for write
[HoldHigh, HoldLow, HoldLow, Float, ReleaseHigh], (HoldHigh, HoldLow, HoldLow, Float, ReleaseHigh),
// write S3' => S4; RESET S1 // write S3' => S4; RESET S1
[HoldHigh, HoldHigh, HoldLow, HoldLow, Float], (HoldHigh, HoldHigh, HoldLow, HoldLow, Float),
// open S0 for write // open S0 for write
[ReleaseHigh, HoldHigh, HoldLow, HoldLow, Float], (ReleaseHigh, HoldHigh, HoldLow, HoldLow, Float),
// write S4' => output; RESET S2 // write S4' => output; RESET S2
[Float, HoldHigh, HoldHigh, HoldLow, HoldLow], (Float, HoldHigh, HoldHigh, HoldLow, HoldLow),
// open S1 for write // open S1 for write
[Float, ReleaseHigh, HoldHigh, HoldLow, HoldLow], (Float, ReleaseHigh, HoldHigh, HoldLow, HoldLow),
]; );
let num_cores = 5;
let num_cycles = 14;
let wire_mat = IsomorphicConductor::new(1e6f32.cast::<R>()); let wire_mat = IsomorphicConductor::new(1e6f32.cast::<R>());
// let ferro_mat = wire_mat; // let ferro_mat = wire_mat;
let ferro_mat = Ferroxcube3R1MH::new(); let ferro_mat = Ferroxcube3R1MH::new();
let num_cores = drive_map[0].len();
let last_core = num_cores - 1; let last_core = num_cores - 1;
let mut driver = Driver::new(Sim::new( let mut driver = Driver::new(Sim::new(
@@ -246,17 +302,96 @@ fn main() {
} }
let cycles = drive_map.len() as u32; let duration = Seconds(params.clock_phase_duration * (num_cycles + 3) as f32);
let duration = Seconds(clock_phase_duration * (cycles + 3) as f32);
for cycle in 0..cycles { let stim = list::Empty::default();
for core in 0..num_cores {
// current polarity of the drive wires is inverted in this model v.s. the blog article, let stim = drive_map.0.0.stim(stim, params, 0, ctl(0));
// so invert our currents in order to achieve the magnetic states of the article. let stim = drive_map.0.1.stim(stim, params, 0, ctl(1));
let sig = drive_map[cycle as usize][core as usize]; let stim = drive_map.0.2.stim(stim, params, 0, ctl(2));
control_signal(&mut driver, &ctl(core), cycle, sig); let stim = drive_map.0.3.stim(stim, params, 0, ctl(3));
} let stim = drive_map.0.4.stim(stim, params, 0, ctl(4));
}
let stim = drive_map.1.0.stim(stim, params, 1, ctl(0));
let stim = drive_map.1.1.stim(stim, params, 1, ctl(1));
let stim = drive_map.1.2.stim(stim, params, 1, ctl(2));
let stim = drive_map.1.3.stim(stim, params, 1, ctl(3));
let stim = drive_map.1.4.stim(stim, params, 1, ctl(4));
let stim = drive_map.2.0.stim(stim, params, 2, ctl(0));
let stim = drive_map.2.1.stim(stim, params, 2, ctl(1));
let stim = drive_map.2.2.stim(stim, params, 2, ctl(2));
let stim = drive_map.2.3.stim(stim, params, 2, ctl(3));
let stim = drive_map.2.4.stim(stim, params, 2, ctl(4));
let stim = drive_map.3.0.stim(stim, params, 3, ctl(0));
let stim = drive_map.3.1.stim(stim, params, 3, ctl(1));
let stim = drive_map.3.2.stim(stim, params, 3, ctl(2));
let stim = drive_map.3.3.stim(stim, params, 3, ctl(3));
let stim = drive_map.3.4.stim(stim, params, 3, ctl(4));
let stim = drive_map.4.0.stim(stim, params, 4, ctl(0));
let stim = drive_map.4.1.stim(stim, params, 4, ctl(1));
let stim = drive_map.4.2.stim(stim, params, 4, ctl(2));
let stim = drive_map.4.3.stim(stim, params, 4, ctl(3));
let stim = drive_map.4.4.stim(stim, params, 4, ctl(4));
let stim = drive_map.5.0.stim(stim, params, 5, ctl(0));
let stim = drive_map.5.1.stim(stim, params, 5, ctl(1));
let stim = drive_map.5.2.stim(stim, params, 5, ctl(2));
let stim = drive_map.5.3.stim(stim, params, 5, ctl(3));
let stim = drive_map.5.4.stim(stim, params, 5, ctl(4));
let stim = drive_map.6.0.stim(stim, params, 6, ctl(0));
let stim = drive_map.6.1.stim(stim, params, 6, ctl(1));
let stim = drive_map.6.2.stim(stim, params, 6, ctl(2));
let stim = drive_map.6.3.stim(stim, params, 6, ctl(3));
let stim = drive_map.6.4.stim(stim, params, 6, ctl(4));
let stim = drive_map.7.0.stim(stim, params, 7, ctl(0));
let stim = drive_map.7.1.stim(stim, params, 7, ctl(1));
let stim = drive_map.7.2.stim(stim, params, 7, ctl(2));
let stim = drive_map.7.3.stim(stim, params, 7, ctl(3));
let stim = drive_map.7.4.stim(stim, params, 7, ctl(4));
let stim = drive_map.8.0.stim(stim, params, 8, ctl(0));
let stim = drive_map.8.1.stim(stim, params, 8, ctl(1));
let stim = drive_map.8.2.stim(stim, params, 8, ctl(2));
let stim = drive_map.8.3.stim(stim, params, 8, ctl(3));
let stim = drive_map.8.4.stim(stim, params, 8, ctl(4));
let stim = drive_map.9.0.stim(stim, params, 9, ctl(0));
let stim = drive_map.9.1.stim(stim, params, 9, ctl(1));
let stim = drive_map.9.2.stim(stim, params, 9, ctl(2));
let stim = drive_map.9.3.stim(stim, params, 9, ctl(3));
let stim = drive_map.9.4.stim(stim, params, 9, ctl(4));
let stim = drive_map.10.0.stim(stim, params, 10, ctl(0));
let stim = drive_map.10.1.stim(stim, params, 10, ctl(1));
let stim = drive_map.10.2.stim(stim, params, 10, ctl(2));
let stim = drive_map.10.3.stim(stim, params, 10, ctl(3));
let stim = drive_map.10.4.stim(stim, params, 10, ctl(4));
let stim = drive_map.11.0.stim(stim, params, 11, ctl(0));
let stim = drive_map.11.1.stim(stim, params, 11, ctl(1));
let stim = drive_map.11.2.stim(stim, params, 11, ctl(2));
let stim = drive_map.11.3.stim(stim, params, 11, ctl(3));
let stim = drive_map.11.4.stim(stim, params, 11, ctl(4));
let stim = drive_map.12.0.stim(stim, params, 12, ctl(0));
let stim = drive_map.12.1.stim(stim, params, 12, ctl(1));
let stim = drive_map.12.2.stim(stim, params, 12, ctl(2));
let stim = drive_map.12.3.stim(stim, params, 12, ctl(3));
let stim = drive_map.12.4.stim(stim, params, 12, ctl(4));
let stim = drive_map.13.0.stim(stim, params, 13, ctl(0));
let stim = drive_map.13.1.stim(stim, params, 13, ctl(1));
let stim = drive_map.13.2.stim(stim, params, 13, ctl(2));
let stim = drive_map.13.3.stim(stim, params, 13, ctl(3));
let stim = drive_map.13.4.stim(stim, params, 13, ctl(4));
assert_eq!(num_cycles, 14);
assert_eq!(num_cores, 5);
let mut driver = driver.with_stimulus(stim);
let prefix = "out/applications/multi_core_inverter/13/"; let prefix = "out/applications/multi_core_inverter/13/";
let _ = std::fs::create_dir_all(&prefix); let _ = std::fs::create_dir_all(&prefix);