driver: lay some scaffolding to allow us to optimize the stimulus in future
This commit is contained in:
@@ -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);
|
||||||
|
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user