add some more caching around the state file & geometry calculations
able to process a simulation in ~2 seconds in the optimistic path
This commit is contained in:
@@ -134,7 +134,7 @@ struct Params {
|
|||||||
pre_time: f32, // how long between set and clock
|
pre_time: f32, // how long between set and clock
|
||||||
post_time: f32, // how long to wait after the clock
|
post_time: f32, // how long to wait after the clock
|
||||||
|
|
||||||
dump_frames: Option<u64>,
|
dump_frames: (u64, Option<u64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||||
@@ -337,33 +337,57 @@ fn derive_geometries(p: GeomParams) -> Option<Geometries> {
|
|||||||
|
|
||||||
fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
|
fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
|
||||||
info!("run_sim {}: {:?}", id, p);
|
info!("run_sim {}: {:?}", id, p);
|
||||||
|
|
||||||
let m_to_um = |m: f32| (m * 1e6).round() as u32;
|
let m_to_um = |m: f32| (m * 1e6).round() as u32;
|
||||||
let feat_vol = p.geom.feat_size * p.geom.feat_size * p.geom.feat_size;
|
let feat_vol = p.geom.feat_size * p.geom.feat_size * p.geom.feat_size;
|
||||||
|
|
||||||
// mu_r=881.33, starting at H=25 to H=75.
|
|
||||||
let ferro_mat = mat::Ferroxcube3R1MH::new();
|
|
||||||
// let ferro_mat = mat::db::conductor(wire_conductivity);
|
|
||||||
let wire_mat = mat::IsomorphicConductor::new(p.wire_conductivity);
|
|
||||||
|
|
||||||
let mut driver: SpirvDriver<Mat> = Driver::new_spirv(g.dim, p.geom.feat_size);
|
|
||||||
driver.set_steps_per_stim(1000);
|
|
||||||
driver.fill_region(&g.ferro1_region, ferro_mat);
|
|
||||||
driver.fill_region(&g.ferro2_region, ferro_mat);
|
|
||||||
driver.fill_region(&g.set1_region, wire_mat);
|
|
||||||
driver.fill_region(&g.set2_region, wire_mat);
|
|
||||||
driver.fill_region(&g.coupling_region, wire_mat);
|
|
||||||
|
|
||||||
info!("boundary: {}um; {}um", m_to_um(p.geom.boundary_xy), m_to_um(p.geom.boundary_z));
|
info!("boundary: {}um; {}um", m_to_um(p.geom.boundary_xy), m_to_um(p.geom.boundary_z));
|
||||||
info!("size: {:?}", g.dim);
|
info!("size: {:?}", g.dim);
|
||||||
info!("ferro1: {:?}", g.ferro1_region.center());
|
info!("ferro1: {:?}", g.ferro1_region.center());
|
||||||
info!("ferro2: {:?}", g.ferro2_region.center());
|
info!("ferro2: {:?}", g.ferro2_region.center());
|
||||||
driver.add_classical_boundary(Meters::new(p.geom.boundary_xy, p.geom.boundary_xy, p.geom.boundary_z));
|
|
||||||
|
|
||||||
// assert!(driver.test_region_filled(&g.ferro1_region, ferro_mat));
|
let base = format!("buffer5-{}", id);
|
||||||
// assert!(driver.test_region_filled(&g.ferro2_region, ferro_mat));
|
let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um-{}ferromaj-{}:{}wraps-{}:{}cov-{:?}clk",
|
||||||
// assert!(driver.test_region_filled(&g.set1_region, wire_mat));
|
base,
|
||||||
// assert!(driver.test_region_filled(&g.set2_region, wire_mat));
|
base,
|
||||||
// assert!(driver.test_region_filled(&g.coupling_region, wire_mat));
|
*g.dim.to_index(p.geom.feat_size),
|
||||||
|
(p.peak_set_current * 1e3).round() as i64,
|
||||||
|
(p.set_duration * 1e12).round() as i64,
|
||||||
|
(p.peak_clock_current * 1e3).round() as i64,
|
||||||
|
(p.clock_duration * 1e12).round() as i64,
|
||||||
|
(p.geom.feat_size * 1e6).round() as i64,
|
||||||
|
p.geom.ferro_major,
|
||||||
|
p.geom.wraps1,
|
||||||
|
p.geom.wraps2,
|
||||||
|
p.geom.wrap1_coverage,
|
||||||
|
p.geom.wrap2_coverage,
|
||||||
|
p.clock_type,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut driver: SpirvDriver<Mat> = Driver::new_spirv(g.dim, p.geom.feat_size);
|
||||||
|
driver.set_steps_per_stim(1000);
|
||||||
|
if !driver.add_state_file(&*format!("{}/state.bc", prefix), 16000) {
|
||||||
|
// mu_r=881.33, starting at H=25 to H=75.
|
||||||
|
let ferro_mat = mat::Ferroxcube3R1MH::new();
|
||||||
|
// let ferro_mat = mat::db::conductor(wire_conductivity);
|
||||||
|
let wire_mat = mat::IsomorphicConductor::new(p.wire_conductivity);
|
||||||
|
|
||||||
|
driver.fill_region(&g.ferro1_region, ferro_mat);
|
||||||
|
driver.fill_region(&g.ferro2_region, ferro_mat);
|
||||||
|
driver.fill_region(&g.set1_region, wire_mat);
|
||||||
|
driver.fill_region(&g.set2_region, wire_mat);
|
||||||
|
driver.fill_region(&g.coupling_region, wire_mat);
|
||||||
|
|
||||||
|
driver.add_classical_boundary(Meters::new(p.geom.boundary_xy, p.geom.boundary_xy, p.geom.boundary_z));
|
||||||
|
|
||||||
|
// assert!(driver.test_region_filled(&g.ferro1_region, ferro_mat));
|
||||||
|
// assert!(driver.test_region_filled(&g.ferro2_region, ferro_mat));
|
||||||
|
// assert!(driver.test_region_filled(&g.set1_region, wire_mat));
|
||||||
|
// assert!(driver.test_region_filled(&g.set2_region, wire_mat));
|
||||||
|
// assert!(driver.test_region_filled(&g.coupling_region, wire_mat));
|
||||||
|
} else {
|
||||||
|
info!("loaded state file: skipping geometry calculations");
|
||||||
|
}
|
||||||
|
|
||||||
let add_drive_sine_pulse = |driver: &mut SpirvDriver<Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
|
let add_drive_sine_pulse = |driver: &mut SpirvDriver<Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
|
||||||
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0)
|
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0)
|
||||||
@@ -445,24 +469,6 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
|
|||||||
driver.add_measurement(meas::Current::new("couplingtop", g.coupling_wire_top.clone()));
|
driver.add_measurement(meas::Current::new("couplingtop", g.coupling_wire_top.clone()));
|
||||||
driver.add_measurement(meas::Current::new("couplingbot", g.coupling_wire_bot.clone()));
|
driver.add_measurement(meas::Current::new("couplingbot", g.coupling_wire_bot.clone()));
|
||||||
|
|
||||||
let base = format!("buffer5-{}", id);
|
|
||||||
let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um-{}ferromaj-{}:{}wraps-{}:{}cov-{:?}clk",
|
|
||||||
base,
|
|
||||||
base,
|
|
||||||
*driver.size(),
|
|
||||||
(p.peak_set_current * 1e3).round() as i64,
|
|
||||||
(p.set_duration * 1e12).round() as i64,
|
|
||||||
(p.peak_clock_current * 1e3).round() as i64,
|
|
||||||
(p.clock_duration * 1e12).round() as i64,
|
|
||||||
(p.geom.feat_size * 1e6).round() as i64,
|
|
||||||
p.geom.ferro_major,
|
|
||||||
p.geom.wraps1,
|
|
||||||
p.geom.wraps2,
|
|
||||||
p.geom.wrap1_coverage,
|
|
||||||
p.geom.wrap2_coverage,
|
|
||||||
p.clock_type,
|
|
||||||
);
|
|
||||||
|
|
||||||
if p.dry_run {
|
if p.dry_run {
|
||||||
info!("bailing (dry run): {}", prefix);
|
info!("bailing (dry run): {}", prefix);
|
||||||
return Results::default();
|
return Results::default();
|
||||||
@@ -470,8 +476,8 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
|
|||||||
|
|
||||||
let _ = std::fs::create_dir_all(&prefix);
|
let _ = std::fs::create_dir_all(&prefix);
|
||||||
|
|
||||||
driver.add_state_file(&*format!("{}/state.bc", prefix), 16000);
|
let (frame_freq, frame_limit) = p.dump_frames;
|
||||||
driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 32000, p.dump_frames);
|
driver.add_serializer_renderer(&*format!("{}/frame-", prefix), frame_freq, frame_limit);
|
||||||
let meas_csv = format!("{}/meas.csv", prefix);
|
let meas_csv = format!("{}/meas.csv", prefix);
|
||||||
let meas_sparse_csv = format!("{}/meas-sparse.csv", prefix);
|
let meas_sparse_csv = format!("{}/meas-sparse.csv", prefix);
|
||||||
driver.add_csv_renderer(&*meas_csv, 400, None);
|
driver.add_csv_renderer(&*meas_csv, 400, None);
|
||||||
@@ -526,23 +532,24 @@ fn main() {
|
|||||||
// for (wrap1_cov, wrap2_cov) in [(0.8, 0.8), (0.8, 0.25), (0.25, 0.8)] {
|
// for (wrap1_cov, wrap2_cov) in [(0.8, 0.8), (0.8, 0.25), (0.25, 0.8)] {
|
||||||
let clock_domain = [
|
let clock_domain = [
|
||||||
(25600.0, 5.0 * ns),
|
(25600.0, 5.0 * ns),
|
||||||
(6400.0, 5.0 * ns),
|
|
||||||
// (1600.0, 5.0 * ns), // low relevance for large cores
|
// (1600.0, 5.0 * ns), // low relevance for large cores
|
||||||
// (1600.0, 1.0 * ns), // very poor perf (0.05 m2_stable_m1_peak)
|
// (1600.0, 1.0 * ns), // very poor perf (0.05 m2_stable_m1_peak)
|
||||||
(25600.0, 1.0 * ns),
|
(25600.0, 1.0 * ns),
|
||||||
// (6400.0, 1.0 * ns), // low relevance for large cores
|
// (6400.0, 1.0 * ns), // low relevance for large cores
|
||||||
// (51200.0, 1.0 * ns),
|
// (51200.0, 1.0 * ns),
|
||||||
(102400.0, 1.0 * ns),
|
(102400.0, 1.0 * ns),
|
||||||
// (409600.0, 1.0 * ns), // I(set1) shows significant underdamping => bad m2_stable_m1_peak
|
|
||||||
|
|
||||||
(12800.0, 5.0 * ns),
|
|
||||||
(51200.0, 5.0 * ns),
|
(51200.0, 5.0 * ns),
|
||||||
|
(12800.0, 5.0 * ns),
|
||||||
// (400.0, 25.0 * ns), // poor perf (0.28 m2_stable_m1_peak)
|
|
||||||
// (1600.0, 25.0 * ns), // mediocre perf (0.65 m2_stable_m1_peak)
|
|
||||||
// TODO: RE-ENABLE
|
// TODO: RE-ENABLE
|
||||||
// (6400.0, 25.0 * ns), // suspended because costly
|
// (6400.0, 25.0 * ns), // suspended because costly
|
||||||
|
(12800.0, 25.0 * ns), // suspended because costly
|
||||||
// (25600.0, 25.0 * ns), // suspended because costly
|
// (25600.0, 25.0 * ns), // suspended because costly
|
||||||
|
// (6400.0, 5.0 * ns), // low relevance for large cores (for >= 9mm rad, <0.5 m2_stable_m1_peak)
|
||||||
|
|
||||||
|
// (409600.0, 1.0 * ns), // I(set1) shows significant underdamping => bad m2_stable_m1_peak
|
||||||
|
// (400.0, 25.0 * ns), // poor perf (0.28 m2_stable_m1_peak)
|
||||||
|
// (1600.0, 25.0 * ns), // mediocre perf (0.65 m2_stable_m1_peak)
|
||||||
|
|
||||||
// (1600.0, 100.0 * ns),
|
// (1600.0, 100.0 * ns),
|
||||||
// (6400.0, 100.0 * ns),
|
// (6400.0, 100.0 * ns),
|
||||||
@@ -566,8 +573,10 @@ fn main() {
|
|||||||
// 1680.0 * um
|
// 1680.0 * um
|
||||||
];
|
];
|
||||||
let wrap2_densities = [
|
let wrap2_densities = [
|
||||||
|
-0.05,
|
||||||
-0.15,
|
-0.15,
|
||||||
-0.3,
|
-0.3,
|
||||||
|
-0.5,
|
||||||
// 0.3,
|
// 0.3,
|
||||||
// 0.2,
|
// 0.2,
|
||||||
// 0.15,
|
// 0.15,
|
||||||
@@ -613,6 +622,12 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
info!(
|
||||||
|
"evaluating {} variants ({} time increments of {} primitives)",
|
||||||
|
variants.len(),
|
||||||
|
post_times.len(),
|
||||||
|
variants.len() / post_times.len(),
|
||||||
|
);
|
||||||
|
|
||||||
let mut geom_cache = DiskCache::new_with_supplier(
|
let mut geom_cache = DiskCache::new_with_supplier(
|
||||||
&format!("out/buffer5-{}/.geom_cache", i),
|
&format!("out/buffer5-{}/.geom_cache", i),
|
||||||
@@ -656,7 +671,7 @@ fn main() {
|
|||||||
pre_time: 1e-9,
|
pre_time: 1e-9,
|
||||||
post_time,
|
post_time,
|
||||||
|
|
||||||
dump_frames: Some(256000),
|
dump_frames: (256000, Some(257000)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let wraps1_choices: Vec<_> = (-120..120)
|
let wraps1_choices: Vec<_> = (-120..120)
|
||||||
@@ -712,7 +727,7 @@ fn main() {
|
|||||||
let mut params = base_params;
|
let mut params = base_params;
|
||||||
params.geom.wraps1 = wraps1;
|
params.geom.wraps1 = wraps1;
|
||||||
params.geom.wraps2 = wraps2;
|
params.geom.wraps2 = wraps2;
|
||||||
match derive_geometries(params.geom.clone()) {
|
match geom_cache.get_or_insert_from_supplier(params.geom.clone()) {
|
||||||
Some(geoms) => {
|
Some(geoms) => {
|
||||||
run_sim(i, params, geoms);
|
run_sim(i, params, geoms);
|
||||||
},
|
},
|
||||||
|
@@ -147,12 +147,19 @@ impl<S: SampleableSim + Send + Sync + Serialize + 'static> Driver<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'static> Driver<S> {
|
impl<S: SampleableSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'static> Driver<S> {
|
||||||
pub fn add_state_file(&mut self, state_file: &str, snapshot_frequency: u64) {
|
/// instruct the driver to periodically save the simulation state to the provided path.
|
||||||
|
/// also attempts to load an existing state file, returning `true` on success.
|
||||||
|
pub fn add_state_file(&mut self, state_file: &str, snapshot_frequency: u64) -> bool {
|
||||||
let ser = render::SerializerRenderer::new(state_file);
|
let ser = render::SerializerRenderer::new(state_file);
|
||||||
if let Some(state) = ser.try_load() {
|
let loaded = match ser.try_load() {
|
||||||
self.state = state.state;
|
Some(state) => {
|
||||||
}
|
self.state = state.state;
|
||||||
|
true
|
||||||
|
},
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
self.add_renderer(ser, state_file, snapshot_frequency, None);
|
self.add_renderer(ser, state_file, snapshot_frequency, None);
|
||||||
|
loaded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +199,7 @@ impl<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
|
|||||||
self.render();
|
self.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut can_step = at_most;
|
let mut can_step = at_most; // TODO: typo?? should be `0`, or `1`?
|
||||||
while can_step < at_most && !self.renderer.any_work_for_frame(start_step + can_step as u64) {
|
while can_step < at_most && !self.renderer.any_work_for_frame(start_step + can_step as u64) {
|
||||||
can_step += 1;
|
can_step += 1;
|
||||||
}
|
}
|
||||||
@@ -242,6 +249,13 @@ impl<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
|
|||||||
self.step_multiple(1);
|
self.step_multiple(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of timesteps needed to reach the end time
|
||||||
|
pub fn steps_until<T: Time>(&mut self, sim_end_time: T) -> u64 {
|
||||||
|
let sim_end_step = sim_end_time.to_frame(self.state.timestep());
|
||||||
|
let start_step = self.state.step_no();
|
||||||
|
sim_end_step.saturating_sub(start_step)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn step_until<T: Time>(&mut self, sim_end_time: T) {
|
pub fn step_until<T: Time>(&mut self, sim_end_time: T) {
|
||||||
let sim_end_time = sim_end_time.to_frame(self.state.timestep());
|
let sim_end_time = sim_end_time.to_frame(self.state.timestep());
|
||||||
self.sim_end_time = Some(sim_end_time);
|
self.sim_end_time = Some(sim_end_time);
|
||||||
|
@@ -561,6 +561,8 @@ impl<S: SampleableSim> Renderer<S> for MultiRenderer<S> {
|
|||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SerializedFrame<S=StaticSim> {
|
pub struct SerializedFrame<S=StaticSim> {
|
||||||
pub state: S,
|
pub state: S,
|
||||||
|
/// although not generally necessary to load the sim, saving the measurements is beneficial for
|
||||||
|
/// post-processing.
|
||||||
pub measurements: Vec<Box<dyn AbstractMeasurement>>,
|
pub measurements: Vec<Box<dyn AbstractMeasurement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,8 +590,8 @@ impl SerializerRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `new`, but cast to StaticSim before serializing. This tends to result in a smaller
|
/// Same as `new`, but cast to StaticSim before serializing. This yields a file that's easier
|
||||||
/// file.
|
/// for post-processing, and may be smaller in size.
|
||||||
pub fn new_static(fmt_str: &str) -> Self {
|
pub fn new_static(fmt_str: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
fmt_str: fmt_str.into(),
|
fmt_str: fmt_str.into(),
|
||||||
|
Reference in New Issue
Block a user