driver: lay some scaffolding to allow us to optimize the stimulus in future

This commit is contained in:
2022-08-18 22:19:50 -07:00
parent ffda00b796
commit 35dbdffda7
2 changed files with 96 additions and 16 deletions

View File

@@ -43,7 +43,7 @@ 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::{CurlVectorField, Exp, Gated, ModulatedVectorField, Shifted, StimExt as _, StimuliVec}; use coremem::stim::{CurlVectorField, Exp, Gated, ModulatedVectorField, Shifted, StimExt as _};
use coremem::Driver; use coremem::Driver;
type R = real::R32; type R = real::R32;
@@ -248,7 +248,6 @@ fn main() {
}) })
.collect(); .collect();
assert_eq!(stim.len(), 5); assert_eq!(stim.len(), 5);
let stim = StimuliVec::from_vec(stim);
let wire_mat = IsomorphicConductor::new(1e6f32.cast::<R>()); let wire_mat = IsomorphicConductor::new(1e6f32.cast::<R>());
@@ -304,7 +303,10 @@ fn main() {
let duration = Seconds(params.clock_phase_duration * (num_cycles + 3) as f32); let duration = Seconds(params.clock_phase_duration * (num_cycles + 3) as f32);
// let stim = DynStimuli::from_vec(stim.map(MapIntoBoxStimulus).into_vec()); // let stim = DynStimuli::from_vec(stim.map(MapIntoBoxStimulus).into_vec());
let mut driver = driver.with_stimulus(stim); let mut driver = driver.with_concrete_stimulus();
for s in stim {
driver.add_stimulus(s);
}
let prefix = "out/applications/multi_core_inverter/20-4ns-1e7A/"; let prefix = "out/applications/multi_core_inverter/20-4ns-1e7A/";
let _ = std::fs::create_dir_all(&prefix); let _ = std::fs::create_dir_all(&prefix);

View File

@@ -6,8 +6,9 @@ use crate::real::Real;
use crate::render::{self, MultiRenderer, Renderer}; use crate::render::{self, MultiRenderer, Renderer};
use crate::sim::AbstractSim; use crate::sim::AbstractSim;
use crate::sim::units::{Frame, Time}; use crate::sim::units::{Frame, Time};
use crate::stim::{Stimulus, DynStimuli}; use crate::stim::{DynStimuli, Stimulus, StimuliVec};
use coremem_cross::compound::list; use coremem_cross::compound::list;
use coremem_cross::step::SimMeta;
use log::{info, trace}; use log::{info, trace};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -17,7 +18,7 @@ use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
use std::time::Instant; use std::time::Instant;
use threadpool::ThreadPool; use threadpool::ThreadPool;
pub struct Driver<S, Stim=DynStimuli> { pub struct Driver<S, Stim=DriverStimulusDynVec> {
state: S, state: S,
renderer: Arc<MultiRenderer<S>>, renderer: Arc<MultiRenderer<S>>,
// TODO: use Rayon's thread pool? // TODO: use Rayon's thread pool?
@@ -56,26 +57,32 @@ impl<S: AbstractSim, Stim> Driver<S, Stim> {
pub fn add_measurement<Meas: AbstractMeasurement<S> + 'static>(&mut self, m: Meas) { pub fn add_measurement<Meas: AbstractMeasurement<S> + 'static>(&mut self, m: Meas) {
self.measurements.push(Arc::new(m)); self.measurements.push(Arc::new(m));
} }
pub fn add_stimulus<SNew>(&mut self, s: SNew)
where Stim: Pushable<SNew>
{
self.stimuli.push(s)
}
} }
impl<S: AbstractSim> Driver<S, DynStimuli> { impl<S: AbstractSim> Driver<S, DriverStimulusDynVec> {
pub fn new(state: S) -> Self { pub fn new(state: S) -> Self {
Self::new_with_stim(state, DynStimuli::default()) Self::new_with_stim(state, DriverStimulusDynVec::default())
}
pub fn add_stimulus<Stim: Stimulus + 'static>(&mut self, s: Stim) {
self.stimuli.push(Box::new(s))
} }
} }
impl<S: AbstractSim> Driver<S, list::Empty> { impl<S: AbstractSim> Driver<S, list::Empty> {
pub fn new_unboxed_stim(state: S) -> Self { pub fn new_list_stim(state: S) -> Self {
Self::new_with_stim(state, list::Empty::default()) Self::new_with_stim(state, list::Empty::default())
} }
} }
impl<S: AbstractSim, Stim> Driver<S, Stim> { impl<S: AbstractSim, Stim> Driver<S, Stim> {
pub fn with_add_stimulus<E>(self, s: E) -> Driver<S, list::Prepended<E, Stim>> /// add a stimulus onto a list of non-monomorphized stimuli.
where Stim: list::Prependable /// this necessarily must return a new Self.
/// (well, with enough tuning we could actually Box just the first reference...
pub fn with_add_stimulus<E>(self, s: E) -> Driver<S, list::Appended<Stim, E>>
where Stim: list::Appendable<E>
{ {
Driver { Driver {
state: self.state, state: self.state,
@@ -83,7 +90,7 @@ impl<S: AbstractSim, Stim> Driver<S, Stim> {
render_pool: self.render_pool, render_pool: self.render_pool,
render_channel: self.render_channel, render_channel: self.render_channel,
measurements: self.measurements, measurements: self.measurements,
stimuli: self.stimuli.prepend(s), stimuli: self.stimuli.append(s),
sim_end_time: self.sim_end_time, sim_end_time: self.sim_end_time,
diag: self.diag, diag: self.diag,
last_diag_time: self.last_diag_time, last_diag_time: self.last_diag_time,
@@ -102,6 +109,9 @@ impl<S: AbstractSim, Stim> Driver<S, Stim> {
last_diag_time: self.last_diag_time, last_diag_time: self.last_diag_time,
} }
} }
pub fn with_concrete_stimulus<T>(self) -> Driver<S, DriverStimulusVec<T>> {
self.with_stimulus(DriverStimulusVec::<T>::default())
}
} }
impl<S: AbstractSim, Stim> Driver<S, Stim> { impl<S: AbstractSim, Stim> Driver<S, Stim> {
@@ -199,7 +209,7 @@ where
impl<S, Stim> Driver<S, Stim> impl<S, Stim> Driver<S, Stim>
where where
S: AbstractSim + Clone + Default + Send + 'static, S: AbstractSim + Clone + Default + Send + 'static,
Stim: Stimulus, Stim: DriverStimulus,
{ {
fn render(&mut self) { fn render(&mut self) {
self.diag.instrument_render_prep(|| { self.diag.instrument_render_prep(|| {
@@ -238,7 +248,8 @@ where
} }
trace!("step begin"); trace!("step begin");
self.diag.instrument_step(can_step as u64, || { self.diag.instrument_step(can_step as u64, || {
self.state.step_multiple(can_step, &self.stimuli); let stim = self.stimuli.optimized_for(self.state.meta());
self.state.step_multiple(can_step, stim.as_ref());
}); });
trace!("step end"); trace!("step end");
if self.last_diag_time.elapsed().as_secs_f64() >= 5.0 { if self.last_diag_time.elapsed().as_secs_f64() >= 5.0 {
@@ -290,3 +301,70 @@ where
self.sim_end_time = None; self.sim_end_time = None;
} }
} }
pub enum ValueOrRef<'a, T> {
Value(T),
Ref(&'a T),
}
impl<'a, T> AsRef<T> for ValueOrRef<'a, T> {
fn as_ref(&self) -> &T {
match self {
ValueOrRef::Value(x) => &x,
ValueOrRef::Ref(x) => x,
}
}
}
/// gives an opportunity to optimize a Stimulus for a specific setting
/// before passing it off to the simulation.
pub trait DriverStimulus {
type Optimized: Stimulus;
fn optimized_for<'a>(
&'a self, meta: SimMeta<f32>
) -> ValueOrRef<'a, Self::Optimized>;
}
pub trait Pushable<T> {
fn push(&mut self, t: T);
}
pub struct DriverStimulusVec<T>(StimuliVec<T>);
impl<T> Default for DriverStimulusVec<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T: Stimulus> DriverStimulus for DriverStimulusVec<T> {
type Optimized = StimuliVec<T>;
fn optimized_for<'a>(
&'a self, _meta: SimMeta<f32>
) -> ValueOrRef<'a, Self::Optimized> {
ValueOrRef::Ref(&self.0)
}
}
impl<T> Pushable<T> for DriverStimulusVec<T> {
fn push(&mut self, t: T) {
self.0.push(t)
}
}
#[derive(Default)]
pub struct DriverStimulusDynVec(DynStimuli);
impl DriverStimulus for DriverStimulusDynVec {
type Optimized = DynStimuli;
fn optimized_for<'a>(
&'a self, _meta: SimMeta<f32>
) -> ValueOrRef<'a, Self::Optimized> {
ValueOrRef::Ref(&self.0)
}
}
impl<T: Stimulus + 'static> Pushable<T> for DriverStimulusDynVec {
fn push(&mut self, t: T) {
self.0.push(Box::new(t))
}
}