From 0e98f8582a5d1c3897b44e17b5bdeb0918559318 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 1 Feb 2022 18:31:47 -0800 Subject: [PATCH] add some more caching around the state file & geometry calculations able to process a simulation in ~2 seconds in the optimistic path --- examples/buffer_proto5.rs | 111 +++++++++++++++++++++----------------- src/driver.rs | 24 +++++++-- src/render.rs | 6 ++- 3 files changed, 86 insertions(+), 55 deletions(-) diff --git a/examples/buffer_proto5.rs b/examples/buffer_proto5.rs index 3e3a0af..033136e 100644 --- a/examples/buffer_proto5.rs +++ b/examples/buffer_proto5.rs @@ -134,7 +134,7 @@ struct Params { pre_time: f32, // how long between set and clock post_time: f32, // how long to wait after the clock - dump_frames: Option, + dump_frames: (u64, Option), } #[derive(Clone, Default, Serialize, Deserialize)] @@ -337,33 +337,57 @@ fn derive_geometries(p: GeomParams) -> Option { fn run_sim(id: u32, p: Params, g: Geometries) -> Results { info!("run_sim {}: {:?}", id, p); + 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; - // 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 = 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!("size: {:?}", g.dim); info!("ferro1: {:?}", g.ferro1_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)); - // 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)); + let base = format!("buffer5-{}", id); + let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um-{}ferromaj-{}:{}wraps-{}:{}cov-{:?}clk", + base, + base, + *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 = 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, region: &Torus, start: f32, duration: f32, amp: f32| { 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("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 { info!("bailing (dry run): {}", prefix); return Results::default(); @@ -470,8 +476,8 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results { let _ = std::fs::create_dir_all(&prefix); - driver.add_state_file(&*format!("{}/state.bc", prefix), 16000); - driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 32000, p.dump_frames); + let (frame_freq, frame_limit) = p.dump_frames; + driver.add_serializer_renderer(&*format!("{}/frame-", prefix), frame_freq, frame_limit); let meas_csv = format!("{}/meas.csv", prefix); let meas_sparse_csv = format!("{}/meas-sparse.csv", prefix); 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)] { let clock_domain = [ (25600.0, 5.0 * ns), - (6400.0, 5.0 * ns), // (1600.0, 5.0 * ns), // low relevance for large cores // (1600.0, 1.0 * ns), // very poor perf (0.05 m2_stable_m1_peak) (25600.0, 1.0 * ns), // (6400.0, 1.0 * ns), // low relevance for large cores // (51200.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), - - // (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) + (12800.0, 5.0 * ns), // TODO: RE-ENABLE // (6400.0, 25.0 * ns), // suspended because costly + (12800.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), // (6400.0, 100.0 * ns), @@ -566,8 +573,10 @@ fn main() { // 1680.0 * um ]; let wrap2_densities = [ + -0.05, -0.15, -0.3, + -0.5, // 0.3, // 0.2, // 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( &format!("out/buffer5-{}/.geom_cache", i), @@ -656,7 +671,7 @@ fn main() { pre_time: 1e-9, post_time, - dump_frames: Some(256000), + dump_frames: (256000, Some(257000)), }; let wraps1_choices: Vec<_> = (-120..120) @@ -712,7 +727,7 @@ fn main() { let mut params = base_params; params.geom.wraps1 = wraps1; params.geom.wraps2 = wraps2; - match derive_geometries(params.geom.clone()) { + match geom_cache.get_or_insert_from_supplier(params.geom.clone()) { Some(geoms) => { run_sim(i, params, geoms); }, diff --git a/src/driver.rs b/src/driver.rs index 015bacb..3dce2c5 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -147,12 +147,19 @@ impl Driver { } impl Deserialize<'a> + 'static> Driver { - 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); - if let Some(state) = ser.try_load() { - self.state = state.state; - } + let loaded = match ser.try_load() { + Some(state) => { + self.state = state.state; + true + }, + None => false, + }; self.add_renderer(ser, state_file, snapshot_frequency, None); + loaded } } @@ -192,7 +199,7 @@ impl Driver { 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) { can_step += 1; } @@ -242,6 +249,13 @@ impl Driver { self.step_multiple(1); } + /// Returns the number of timesteps needed to reach the end time + pub fn steps_until(&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(&mut self, sim_end_time: T) { let sim_end_time = sim_end_time.to_frame(self.state.timestep()); self.sim_end_time = Some(sim_end_time); diff --git a/src/render.rs b/src/render.rs index 2ed780a..0df03f7 100644 --- a/src/render.rs +++ b/src/render.rs @@ -561,6 +561,8 @@ impl Renderer for MultiRenderer { #[derive(Serialize, Deserialize)] pub struct SerializedFrame { pub state: S, + /// although not generally necessary to load the sim, saving the measurements is beneficial for + /// post-processing. pub measurements: Vec>, } @@ -588,8 +590,8 @@ impl SerializerRenderer { } } - /// Same as `new`, but cast to StaticSim before serializing. This tends to result in a smaller - /// file. + /// Same as `new`, but cast to StaticSim before serializing. This yields a file that's easier + /// for post-processing, and may be smaller in size. pub fn new_static(fmt_str: &str) -> Self { Self { fmt_str: fmt_str.into(),