//! Body Map Viewer workshop-gate benches (T-1178 / T-1154, brief appendix //! ②/③; tyre-implications.md §3.2). Two anti-extrapolation measurements the //! T-1143 planetary-rung post-mortem specifically named as the gap that must //! close before round 1 of the body-map-viewer workshop can start: //! //! - **T-1178 (②):** does the row-chunked `par_iter` throughput measured at //! 4,096 cells (`zoom_ladder_bench.rs`, 1.785 µs/cell District cutoff) //! HOLD at real step-canvas sizes (330K, 2.07M, 8.3M cells)? MEASURE, never //! extrapolate. //! - **T-1154 (③):** per-cell derive cost at block (128 m) and tile-adjacent //! (1–4 m) spacing — the ladder's un-costed bottom rungs //! (`atlas-zoom-ladder-t1143.md` §2: "not estimated"). //! //! ## Why this is a NEW file, not an extension of `zoom_ladder_bench.rs` //! //! `zoom_ladder_bench.rs` measures per-cell rate at the FIXED 4,096-cell //! shape (`grid_side = 64`, matching the D-226 window wire cap) — that shape //! is deliberate there (it's the served-window ceiling). This file measures //! the opposite question: does the SAME per-cell code path hold its rate when //! swept out to real canvas dimensions the served-window ceiling forbids. //! Different shape, different question, kept in its own file per the batch //! instruction (do not touch `server/src/atlas/mod.rs`; extend the bench or //! add a new file — this adds a new file to avoid entangling two //! differently-shaped measurement passes in one). //! //! ## The `n`-cap problem (why this cannot go through `AtlasLayerRequest`) //! //! `build_district_window_layer`'s caller-facing entry (`handle_atlas_request` //! / `clamp_window_n_v2`) hard-clamps `n` so `side² ≤ WIRE_CAP_CELLS = 4,096` //! — a REAL client can never request a 330K-cell window over the wire, by //! design (D-226 T-1124 §2). So "run it through the production path at //! 330K/8.3M cells" cannot mean "send an `AtlasLayerRequest` for that size" — //! no such request is legal. It means: call the actual //! `build_district_window_layer` function — same signature, same row-chunked //! `into_par_iter()` loop, same `derive_window_cell`/`scatter_row` internals, //! same `derive_at_metres` calls — with an `n` no wire request could carry, //! because `build_district_window_layer` itself has NO internal clamp (the //! clamp lives one layer up, in the request handler). Confirmed by direct //! read of `layer_proxy.rs:1515-1628` this session. This is exactly what the //! ticket anticipates: "If the production path caps window n such that you //! cannot request 330K cells through it directly, bench the underlying //! chunked loop at those counts and say exactly what you ran." //! //! ## Square vs. rectangular canvases //! //! `build_district_window_layer` only derives SQUARE `side×side` grids ('n' //! is a single extent). The real step-canvas shapes the ticket names are //! 16:9 rectangles (768×432, 1920×1080, 3840×2160) — not square. Two //! measurements are taken for each cell-count target: //! //! 1. **Square, through `build_district_window_layer` itself** (District //! granularity, `n = side`, real function call, unmodified, REAL //! `RiverNetwork` passed in) — the closest possible approach to "the //! actual production entry point," at the nearest square cell count to //! the target (e.g. side=576 → 331,776 cells, matching 768×432's 331,776 //! exactly). This path exercises the ACTUAL course-invention + //! riparian-cull machinery `build_district_window_layer` runs in //! production (`invent_courses_near_window`/`crop_courses_for_wire`) — //! confirmed non-empty at every measured shape (`layer.courses.len()` is //! printed and was 3/6/10 at 330K/2.07M/8.3M respectively on the //! synthetic gradient body centred at the world origin; see the results //! doc's H3 correction for exactly what this does and does not validate). //! //! 2. **Real 16:9 rectangle, via a row-chunked loop that mirrors //! `build_district_window_layer`'s internals cell-for-cell** (same //! `into_par_iter()` row chunking, same `derive_at_metres` call, same //! per-cell output quantization copied from `derive_window_cell`) but //! sized to the actual non-square canvas. This is necessarily a //! hand-written replica for the rectangular case (documented inline, //! diffed explicitly against the real function in the module doc above), //! since no production entry point derives a rectangle. Labelled //! "MEASURED (replica loop)" in the results table to distinguish it from //! "MEASURED (production fn)". //! //! **DISCLOSED GAP (PR #198 review, Hoshe H2):** [`rect_window_replica`] //! always calls `derive_at_metres` with an EMPTY `&[]` course slice — it //! has no `RiverNetwork`/`invent_courses_near_window` wiring at all, by //! construction (courses are invented ONCE per window, ahead of the //! per-cell loop, inside `build_district_window_layer` itself — //! replicating that machinery was out of scope for a bench loop whose job //! is the per-cell derive rate, not course invention). This means EVERY //! rectangular-canvas number in this file (the three named 16:9 shapes //! AND the 83K deep-step bench) **excludes the per-cell //! `river_course::near_perennial_water` riparian-test cost** production //! pays on every cell of a window with real nearby course geometry. //! `zoom_ladder_bench.rs`'s own `bench_course_cost_on_vs_off` measured //! that cost at District cap (n=64, real GJ1c geometry): **+0.09–0.21 ms //! against a ~5 ms baseline, under 5%** — small, but real, and this file's //! rectangular numbers do not include it. Full disclosure and the //! corrected "what converges with what" statement is in the results doc's //! H2/H3 section — read that section before citing any rectangular-canvas //! number here as courses-inclusive. It is not. //! //! **Convergence claim, corrected (H3):** the square production-fn path is //! courses-INCLUSIVE (light density: 3/6/10 courses at 330K/2.07M/8.3M) and //! the rectangular replica-loop path is courses-EMPTY (always `&[]`) — so //! their agreement at 331,776 ≈ 576² (~191 ns/cell either way) validates the //! ROW-CHUNKED LOOP MECHANICS (chunking granularity, dispatch overhead, //! per-cell derive cost) converging across two independently-written call //! sites, NOT a courses-empty-vs-courses-inclusive equivalence claim — the //! two paths differ in exactly one respect (courses present vs absent) and //! happen to land within noise of each other at this course DENSITY (3 out //! of 331,776 cells is far too sparse to move the aggregate ns/cell figure //! outside the run-to-run noise band, consistent with the <5% per-cell //! course-cost delta `zoom_ladder_bench.rs` measured directly). The //! courses-inclusive rate at REAL production course density (not this //! sparse an origin-window) is covered only by the separate GJ1c real-body //! cross-check bench below (18 courses in a 331,776-cell window, deliberately //! centred on real river geometry) — see that bench's own doc and the //! results doc for the exact scope of what each number does and does not //! include. //! //! Run: `cargo test --release --test bmv_gridunit_bench -- --ignored --nocapture` use std::time::Instant; use settled_reach_server::atlas::district_profile::{ derive_at_metres, BodyParams, ClimateConstants, }; use settled_reach_server::atlas::drainage; use settled_reach_server::atlas::features::TerrainAnalysis; use settled_reach_server::atlas::heightmap::{load_heightmap_png, BodyHeightmap}; use settled_reach_server::atlas::layer_proxy::{build_district_window_layer, WindowGranularity}; use settled_reach_server::atlas::river_course::{self, InventedCourse}; use settled_reach_server::atlas::scale; use settled_reach_server::seed::{SeedChain, SeedDomain}; // --------------------------------------------------------------------------- // Shared fixtures — same shape as zoom_ladder_bench.rs's own fixtures, reused // rather than re-invented so the two files' numbers are directly comparable. // --------------------------------------------------------------------------- fn bench_hm() -> BodyHeightmap { let (w, h) = (128u32, 64u32); let n = (w * h) as usize; let data = (0..n) .map(|i| { let r = (i / w as usize) as f32 / h as f32; let c = (i % w as usize) as f32 / w as f32; (r * 0.6 + c * 0.4).min(1.0) }) .collect(); BodyHeightmap { body_id: "bench".into(), width: w, height: h, data, sea_level: 0.3, } } fn bench_ta(hm: &BodyHeightmap) -> TerrainAnalysis { let dr = drainage::analyze(&hm.data, hm.width, hm.height, hm.sea_level); TerrainAnalysis::analyze(hm, &dr) } fn bench_river_network( hm: &BodyHeightmap, ) -> settled_reach_server::atlas::body_world_state::RiverNetwork { drainage::analyze(&hm.data, hm.width, hm.height, hm.sea_level).river_network } fn bench_params() -> BodyParams { BodyParams { hydrosphere: Some("ocean".into()), atmosphere: Some("breathable".into()), planet_class: Some("temperate".into()), body_radius_km: Some(6371.0), ..Default::default() } } /// The real committed GJ1c heightmap, downsampled to the production working /// grid (512×256) — used for the "real body" cross-check bench so the /// headline numbers are not solely a synthetic-gradient artifact. fn gj1c_fixture() -> (BodyHeightmap, TerrainAnalysis) { let src = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../wiki/star-systems/GJ-1/bodies/GJ1c/heightmap.png"); let heightmap = load_heightmap_png(&src, "GJ1c", 0.3).expect("decode committed GJ1c heightmap"); let small = heightmap.downsample(512, 256); let dr = drainage::analyze(&small.data, small.width, small.height, small.sea_level); let ta = TerrainAnalysis::analyze(&small, &dr); (small, ta) } /// Report the actual Rayon global-pool thread count in use, not an assumed /// constant — so the results doc records what really ran, on whatever /// machine state existed at run time. fn rayon_threads_report() -> String { format!( "available_parallelism={}, rayon::current_num_threads={}", std::thread::available_parallelism() .map(|n| n.get()) .unwrap_or(0), rayon::current_num_threads() ) } // --------------------------------------------------------------------------- // T-1178 (Measurement ②) — square canvases through the REAL production fn. // --------------------------------------------------------------------------- /// Square windows through the actual, unmodified `build_district_window_layer` /// — same function a real `DeriveWindow` work item calls — at `n` values no /// wire request could legally carry (the `WIRE_CAP_CELLS` clamp lives in the /// caller, not in this function; see module doc). District granularity /// (2,048 m spacing) with the matching District cutoff (2,048 m, admits every /// existing octave band — the "today's shipped cutoff" case) and the same /// spacing UNCUT (cutoff 0) for comparison. #[test] #[ignore] fn bench_square_window_production_fn_district_spacing() { let hm = bench_hm(); let ta = bench_ta(&hm); let rn = bench_river_network(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); println!("\n=== T-1178 square-window production-fn bench (District spacing) ==="); println!(" {}\n", rayon_threads_report()); // side values chosen to land on/near the ticket's named cell counts: // 576^2 = 331,776 (~330K, the 5x5-px-per-gridunit fallback) // 1440^2 = 2,073,600 (~2.07M, the 1920x1080 midpoint) // 2880^2 = 8,294,400 (~8.3M, the 3840x2160 1x1 ideal) let side_targets: [u32; 3] = [576, 1440, 2880]; let min_wl_m = scale::DISTRICT_M as u32; // 2,048 m — the shipped District cutoff band for &side in &side_targets { let n = side; // District granularity: side == n let cells = (side as u64) * (side as u64); // Warm-up call (allocator/page-fault warm-up not counted). let _ = build_district_window_layer( seed, "bench", ¶ms, &ta, &rn, (0, 0), n, &climate, WindowGranularity::District, min_wl_m, ); let t0 = Instant::now(); let layer = build_district_window_layer( seed, "bench", ¶ms, &ta, &rn, (0, 0), n, &climate, WindowGranularity::District, min_wl_m, ); let elapsed = t0.elapsed(); std::hint::black_box(layer.elev_q.len()); let ms = elapsed.as_secs_f64() * 1000.0; let ns_per_cell = elapsed.as_secs_f64() * 1e9 / cells as f64; println!( " side={side:>5} n={n:>5} cells={cells:>10} (target ~{}): \ {ms:>9.2} ms warm, {ns_per_cell:>7.1} ns/cell ({:.3} us/cell), \ courses_in_window={}", match cells { c if c < 500_000 => "330K", c if c < 4_000_000 => "2.07M", _ => "8.3M", }, ns_per_cell / 1000.0, layer.courses.len() ); } println!(); } /// Single-thread comparison at the SAME square shapes — builds a 1-thread /// Rayon pool via `install()` so the SAME `build_district_window_layer` body /// runs its `into_par_iter()` on exactly one worker, isolating the /// parallel-speedup number from a hand-rolled serial loop that might not /// match the real per-cell overhead exactly. #[test] #[ignore] fn bench_square_window_production_fn_district_spacing_single_thread() { let hm = bench_hm(); let ta = bench_ta(&hm); let rn = bench_river_network(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); println!( "\n=== T-1178 square-window production-fn bench, SINGLE THREAD (District spacing) ===\n" ); // 8.3M cells single-thread is the ~12s-class case the design doc // extrapolated (§7); 330K/2.07M included for the full comparison table. // Skipped: none — this is the case that must NOT be assumed cheap. let side_targets: [u32; 3] = [576, 1440, 2880]; let min_wl_m = scale::DISTRICT_M as u32; let pool = rayon::ThreadPoolBuilder::new() .num_threads(1) .build() .expect("build single-thread rayon pool"); for &side in &side_targets { let n = side; let cells = (side as u64) * (side as u64); pool.install(|| { let _ = build_district_window_layer( seed, "bench", ¶ms, &ta, &rn, (0, 0), n, &climate, WindowGranularity::District, min_wl_m, ); }); let t0 = Instant::now(); let layer = pool.install(|| { build_district_window_layer( seed, "bench", ¶ms, &ta, &rn, (0, 0), n, &climate, WindowGranularity::District, min_wl_m, ) }); let elapsed = t0.elapsed(); std::hint::black_box(layer.elev_q.len()); let ms = elapsed.as_secs_f64() * 1000.0; let ns_per_cell = elapsed.as_secs_f64() * 1e9 / cells as f64; println!( " side={side:>5} n={n:>5} cells={cells:>10} (1 thread): \ {ms:>9.2} ms, {ns_per_cell:>7.1} ns/cell ({:.3} us/cell)", ns_per_cell / 1000.0 ); } println!(); } /// Real-body cross-check: the same square sweep, but on the committed GJ1c /// heightmap/TerrainAnalysis (not the synthetic gradient) and with the real /// river network live (courses ON, window centred on real river geometry — /// not an empty network, and not a window that happens to cull every course /// out) — confirms the synthetic-fixture numbers above are not an artifact of /// a trivial gradient body or an empty river network's near-zero /// course-culling cost. Window centring follows `bench_course_cost_on_vs_off` /// (`zoom_ladder_bench.rs`)'s exact technique: convert a real river cell to /// world metres via the same `pixel_to_world_m`-equivalent formula, then to /// the covering `DistrictPos`, so the window is genuinely near GJ1c's rivers /// rather than at the arbitrary world origin (which measured courses_in_window=0 /// on a first attempt — corrected here). Run at the 330K shape only /// (real-body I/O + full sweep would duplicate the synthetic-fixture table /// for no new signal at the larger sizes — the per-cell RATE is what's being /// cross-checked, not re-measuring 8.3M twice). #[test] #[ignore] fn bench_square_window_production_fn_gj1c_real_body_crosscheck() { let (hm, ta) = gj1c_fixture(); let dr = drainage::analyze(&hm.data, hm.width, hm.height, hm.sea_level); let rn = dr.river_network.clone(); let params = BodyParams { hydrosphere: Some("ocean".into()), atmosphere: Some("breathable".into()), planet_class: Some("temperate".into()), body_radius_km: Some(6371.0), ..Default::default() }; let climate = ClimateConstants::default(); let seed = SeedChain::root(0xC0FFEE_u64).derive(SeedDomain::Body, 7); assert!( !rn.river_cells.is_empty(), "GJ1c at production working resolution must have river cells for this bench to be meaningful" ); // Same centring technique as zoom_ladder_bench.rs's bench_course_cost_on_vs_off. let river_cell = rn.river_cells[rn.river_cells.len() / 2]; let r_km = params.body_radius_km.unwrap(); let world_pos = ( river_cell.1 as f64 / ta.w as f64 * (std::f64::consts::TAU * r_km * 1000.0), (river_cell.0 as f64 / (ta.h - 1) as f64 - 0.5) * (std::f64::consts::PI * r_km * 1000.0), ); let center: (i32, i32) = ( (world_pos.0 / scale::DISTRICT_M as f64).floor() as i32, (world_pos.1 / scale::DISTRICT_M as f64).floor() as i32, ); println!("\n=== T-1178 GJ1c real-body cross-check (District spacing, courses ON) ==="); println!(" window centred at district {center:?} (river cell {river_cell:?})"); println!(" {}\n", rayon_threads_report()); let side = 576u32; // ~330K cells let n = side; let cells = (side as u64) * (side as u64); let min_wl_m = scale::DISTRICT_M as u32; let _ = build_district_window_layer( seed, "GJ1c", ¶ms, &ta, &rn, center, n, &climate, WindowGranularity::District, min_wl_m, ); let t0 = Instant::now(); let layer = build_district_window_layer( seed, "GJ1c", ¶ms, &ta, &rn, center, n, &climate, WindowGranularity::District, min_wl_m, ); let elapsed = t0.elapsed(); let ms = elapsed.as_secs_f64() * 1000.0; let ns_per_cell = elapsed.as_secs_f64() * 1e9 / cells as f64; println!( " side={side} n={n} cells={cells} courses_in_window={}: \ {ms:.2} ms, {ns_per_cell:.1} ns/cell ({:.3} us/cell)", layer.courses.len(), ns_per_cell / 1000.0 ); println!(); } // --------------------------------------------------------------------------- // T-1178 (Measurement ②) — real 16:9 rectangular canvases, replica loop. // --------------------------------------------------------------------------- /// Row-chunked derive over a REAL (non-square) canvas rectangle, mirroring /// `build_district_window_layer`'s internal loop shape cell-for-cell (see /// module doc for the explicit diff against the real function). Returns /// (elapsed, per_cell_ns). /// /// **Courses are FORCE-EMPTY here, disclosed (PR #198 review, Hoshe H2):** /// every call site below passes `&[]` for `nearby_courses` — there is no /// `RiverNetwork`, no `invent_courses_near_window` call, and no /// `river_course::near_perennial_water` riparian test running per cell. This /// is a real, measured gap versus production, not a rounding footnote: /// `zoom_ladder_bench.rs`'s `bench_course_cost_on_vs_off` measured the /// courses-on-vs-off delta directly at District cap (n=64, real GJ1c /// geometry) as **+0.09–0.21 ms against a ~5 ms baseline (under 5%)**. Every /// number produced by this function — the three 16:9 canvas benches AND the /// 83K deep-step bench — excludes that cost. It is EXCLUDED, not zero in /// production; readers citing a rectangular-canvas number from this file as /// "the real per-cell cost including courses" are citing it wrong. The /// courses-inclusive numbers live only in the square /// `build_district_window_layer`-backed benches above (which pass a real /// `RiverNetwork` and print `courses_in_window`). #[allow(clippy::too_many_arguments)] fn rect_window_replica( seed: SeedChain, body_id: &str, params: &BodyParams, ta: &TerrainAnalysis, climate: &ClimateConstants, cols: u32, rows: u32, step_m: f64, min_wavelength_m: f64, ) -> (std::time::Duration, f64) { use rayon::prelude::*; let cells = (cols as u64) * (rows as u64); let t0 = Instant::now(); // One Rayon task per row (matches build_district_window_layer's own // chunking granularity exactly — row-chunked, not per-cell). let row_results: Vec = (0..rows) .into_par_iter() .map(|row| { let mut row_acc: u64 = 0; for col in 0..cols { let wx = col as f64 * step_m; let wy = row as f64 * step_m; let prof = derive_at_metres( seed, body_id, params, ta, wx, wy, climate, min_wavelength_m, &[], ); // Mirror derive_window_cell's per-cell quantization cost // (six field casts/clamps) rather than reading one field — // this is the SAME output shape the real function produces, // just accumulated into a checksum instead of six Vec // scatters (allocation-identical scatter cost is a one-time // Vec::with_capacity, not a per-cell cost worth replicating // here; the per-cell COMPUTE is what's being measured). let morphology = prof.morphology_zone as u8; let elev_q = prof.elev_q.clamp(0, 100) as u8; let moisture_q = prof.moisture_q.clamp(0, 100) as u8; let vegetation = prof.vegetation_class as u8; let glaciation = prof.glaciation_grade as u8; row_acc ^= morphology as u64 ^ elev_q as u64 ^ moisture_q as u64 ^ vegetation as u64 ^ glaciation as u64; } std::hint::black_box(row_acc) }) .collect(); let checksum: u64 = row_results.into_iter().fold(0, |a, b| a ^ b); std::hint::black_box(checksum); let elapsed = t0.elapsed(); let ns_per_cell = elapsed.as_secs_f64() * 1e9 / cells as f64; (elapsed, ns_per_cell) } /// The three named real step-canvas shapes (768x432 / 1920x1080 / 3840x2160), /// District spacing + District cutoff, through the row-chunked replica loop. /// This is the DIRECT answer to "does 4,096-cell par_iter throughput hold at /// real canvas sizes" for the actual non-square shapes the workshop brief /// names, cross-checked against the square production-fn numbers above. #[test] #[ignore] fn bench_rect_canvas_district_spacing() { let hm = bench_hm(); let ta = bench_ta(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); let min_wl_m = scale::DISTRICT_M as f64; println!( "\n=== T-1178 real 16:9 canvas bench, replica row-chunked loop (District spacing) ===" ); println!(" {}\n", rayon_threads_report()); let shapes: [(u32, u32, &str); 3] = [ (768, 432, "768x432 (5x5px/gridunit fallback, ~330K)"), (1920, 1080, "1920x1080 (midpoint, ~2.07M)"), (3840, 2160, "3840x2160 (1x1 ideal, ~8.3M)"), ]; for (cols, rows, label) in shapes { let cells = (cols as u64) * (rows as u64); let (elapsed, ns_per_cell) = rect_window_replica( seed, "bench", ¶ms, &ta, &climate, cols, rows, min_wl_m, min_wl_m, ); let ms = elapsed.as_secs_f64() * 1000.0; println!( " {label}: cells={cells:>10} {ms:>9.2} ms warm, {ns_per_cell:>7.1} ns/cell \ ({:.3} us/cell)", ns_per_cell / 1000.0 ); } println!(); } /// Single-thread version of the same three rectangles (cutoff-matched) — /// completes the parallel-speedup comparison for the real canvas shapes. #[test] #[ignore] fn bench_rect_canvas_district_spacing_single_thread() { let hm = bench_hm(); let ta = bench_ta(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); let min_wl_m = scale::DISTRICT_M as f64; println!("\n=== T-1178 real 16:9 canvas bench, SINGLE THREAD (District spacing) ===\n"); let pool = rayon::ThreadPoolBuilder::new() .num_threads(1) .build() .expect("build single-thread rayon pool"); let shapes: [(u32, u32, &str); 3] = [ (768, 432, "768x432 (~330K)"), (1920, 1080, "1920x1080 (~2.07M)"), (3840, 2160, "3840x2160 (~8.3M)"), ]; for (cols, rows, label) in shapes { let cells = (cols as u64) * (rows as u64); let (elapsed, ns_per_cell) = pool.install(|| { rect_window_replica( seed, "bench", ¶ms, &ta, &climate, cols, rows, min_wl_m, min_wl_m, ) }); let ms = elapsed.as_secs_f64() * 1000.0; println!( " {label}: cells={cells:>10} {ms:>9.2} ms, {ns_per_cell:>7.1} ns/cell \ ({:.3} us/cell)", ns_per_cell / 1000.0 ); } println!(); } // --------------------------------------------------------------------------- // T-1154 (Measurement ③) — block (128 m) and tile-adjacent spacing. // --------------------------------------------------------------------------- /// Per-cell derive cost at Block (128 m) and Tile-adjacent (1 m, 4 m) /// spacing, with the matching octave cutoff active — the ladder rungs /// `atlas-zoom-ladder-t1143.md` §2 marks "not estimated". Uses the SAME /// 64x64 = 4,096-cell sweep shape as `zoom_ladder_bench.rs`'s District/ /// Quarter sweeps so the per-cell rate is directly comparable across every /// rung on one table. /// /// `MIN_WL_BANDS_M` (the request-facing quantized cutoff set, /// `layer_proxy.rs:451`) bottoms out at 1,024 m (Quarter's own band) — there /// is NO existing wire-facing band for Block or Tile. This bench calls /// `derive_at_metres` directly with a cutoff value no real window request can /// carry today (same "call the underlying function, not the wire path" /// discipline as the T-1178 benches above), matching each spacing to its OWN /// Nyquist floor (cutoff = spacing) the same way the existing District/ /// Quarter sweeps do. #[test] #[ignore] fn bench_block_and_tile_spacing_4096_cells() { let hm = bench_hm(); let ta = bench_ta(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); let grid_side = 64u32; // 4,096 cells — matches zoom_ladder_bench.rs's shape println!("\n=== T-1154 block/tile-spacing derive_at_metres benchmark (4,096-cell sweep) ==="); println!( "grid: {grid_side}x{grid_side} = {} cells/sweep\n", grid_side * grid_side ); let block_m = scale::BLOCK_M as f64; // 128 m let tile_4m = 4.0_f64; // coarsest "tile-adjacent" spacing named in the ticket let tile_1m = 1.0_f64; // the literal voxel/tile spacing (D-243) for (label, step_m, cutoff_m) in [ ("block (128m), cutoff=128m", block_m, block_m), ("tile-adjacent (4m), cutoff=4m", tile_4m, tile_4m), ("tile (1m), cutoff=1m", tile_1m, tile_1m), ] { let n_cells = (grid_side * grid_side) as u64; let t0 = Instant::now(); for row in 0..grid_side { for col in 0..grid_side { let wx = col as f64 * step_m; let wy = row as f64 * step_m; let prof = derive_at_metres(seed, "bench", ¶ms, &ta, wx, wy, &climate, cutoff_m, &[]); std::hint::black_box(prof.elev_q); } } let elapsed = t0.elapsed(); let per_cell_ns = elapsed.as_secs_f64() * 1e9 / n_cells as f64; println!( " {label:<32}: {:>8.2} ms total, {:>7.1} ns/cell ({:.3} us/cell)", elapsed.as_secs_f64() * 1000.0, per_cell_ns, per_cell_ns / 1000.0 ); } println!(); } /// The realistic deep-step canvas: at the ~10 px-per-1m-tile bottom-out on a /// 2,160-px SMALLER axis (a 1920x1080 viewport, portrait-safe on the smaller /// dimension per the brief's "viewport's smaller axis" convention), the /// world extent covered is `1080 px / 10 px-per-tile = 108 tiles = 108 m` on /// the smaller axis, `1920 / 10 = 192 m` on the larger — a 192m x 108m /// window at 1 m spacing. Re-stated against the ticket's own worked example /// (2160 px smaller axis, ~216m x ~384m) for the 3840x2160 canvas instead: /// `2160/10 = 216 m` (smaller axis), `3840/10 = 384 m` (larger axis) — EXACT /// geometry used below, matching the ticket's stated numbers precisely. /// /// At 1 m spacing that is a 216x384 CELL grid (1 world-metre per gridunit, /// 10 screen px per gridunit) = 82,944 cells — the ticket's "~83K cells" /// figure, confirmed exactly (216 * 384 = 82,944). #[test] #[ignore] fn bench_deep_step_realistic_canvas_83k_cells() { let hm = bench_hm(); let ta = bench_ta(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); // Geometry: 3840x2160 canvas, 10 px per 1m tile, smaller axis 2160. // world extent: 216 m (smaller/rows) x 384 m (larger/cols), 1 m spacing. let rows = 216u32; // world metres on the smaller (2160px/10) axis let cols = 384u32; // world metres on the larger (3840px/10) axis let cells = (rows as u64) * (cols as u64); assert_eq!( cells, 82_944, "geometry must match the ticket's stated ~83K cells exactly" ); let step_m = 1.0_f64; let cutoff_m = 1.0_f64; // Nyquist-matched to 1 m spacing println!("\n=== T-1154 deep-step realistic-canvas bench (216m x 384m @ 1m spacing) ==="); println!( " geometry: 3840x2160 canvas @ 10px/tile, smaller axis 2160 -> 216m, larger axis 3840 -> 384m" ); println!(" cells = 216 * 384 = {cells}"); println!(" {}\n", rayon_threads_report()); // Parallel, through the SAME row-chunked replica loop T-1178 uses (this // is the production par_iter SHAPE, not the exact function, for the same // reason as the T-1178 rectangular benches: no square-only production fn // covers a non-square metre-spacing window). let (elapsed_par, ns_per_cell_par) = rect_window_replica( seed, "bench", ¶ms, &ta, &climate, cols, rows, step_m, cutoff_m, ); println!( " PARALLEL (row-chunked): {:.2} ms, {:.1} ns/cell ({:.3} us/cell)", elapsed_par.as_secs_f64() * 1000.0, ns_per_cell_par, ns_per_cell_par / 1000.0 ); // Single-thread comparison. let pool = rayon::ThreadPoolBuilder::new() .num_threads(1) .build() .expect("build single-thread rayon pool"); let (elapsed_seq, ns_per_cell_seq) = pool.install(|| { rect_window_replica( seed, "bench", ¶ms, &ta, &climate, cols, rows, step_m, cutoff_m, ) }); println!( " SINGLE-THREAD: {:.2} ms, {:.1} ns/cell ({:.3} us/cell)", elapsed_seq.as_secs_f64() * 1000.0, ns_per_cell_seq, ns_per_cell_seq / 1000.0 ); println!( " speedup: {:.2}x\n", elapsed_seq.as_secs_f64() / elapsed_par.as_secs_f64() ); } /// Cutoff sweep AT Block-spacing sample positions, varying the cutoff itself /// from uncut (0, every octave band in `OCTAVE_WAVELENGTHS_M` [4,096..32,768] /// AND `VOXEL_OCTAVE_WAVELENGTHS_M` [128..1,024] survives) up through /// District-coarse (2,048m, truncates nothing extra vs. uncut — every /// `OCTAVE_WAVELENGTHS_M` entry is still ≥2,048) to Region-coarse (204,800m, /// truncates EVERY octave in both bands, `enveloped_fbm`'s "every octave cut" /// empty-sum guard fires). /// /// **Why "cutoff=128m (Block's own Nyquist floor)" shows ZERO delta vs. /// uncut** (confirmed by direct read of `enveloped_fbm`, /// `detail_scatter.rs:198-251`: `if wl < min_wavelength_m { skip }` — a /// cutoff only skips octaves STRICTLY FINER than itself. At Block's own /// floor (128m), every entry in BOTH octave arrays is `>= 128m` /// (`VOXEL_OCTAVE_WAVELENGTHS_M`'s finest is exactly 128m, `>=` not `<`), so /// nothing is skipped — Block sits at the bottom of the invented-detail /// octave stack, with nothing finer left to truncate. This is a genuine, /// verified finding (not a bench bug): **the cutoff mechanism has no /// truncation work left to do at Block spacing or finer** — every rung from /// Block down to Tile pays the SAME full per-cell octave-sum cost, because /// the const octave arrays bottom out at 128m and neither /// `MOSAIC_OCTAVE_WAVELENGTHS_M` (64/32/16/8m) nor any Tile-specific band is /// wired into `derive_at_metres`'s call graph (see the module doc's /// voxel_mosaic finding). The cutoff only pays off at COARSER rungs /// (District, Quarter, Region) where it truncates the fine end of the octave /// stack that those rungs' sample density can't resolve anyway. #[test] #[ignore] fn bench_block_cutoff_confirms_savings() { let hm = bench_hm(); let ta = bench_ta(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); let grid_side = 64u32; let block_m = scale::BLOCK_M as f64; let district_m = scale::DISTRICT_M as f64; let region_m = scale::REGION_M as f64; println!("\n=== T-1154 Block-spacing-position cutoff sweep (varying cutoff value) ===\n"); for (label, cutoff_m) in [ ("uncut (cutoff=0)", 0.0), ( "cutoff=128m (Block's own floor, expect NO delta vs uncut)", block_m, ), ( "cutoff=2048m (District-coarse, truncates the VOXEL band, real savings)", district_m, ), ( "cutoff=204800m (Region-coarse, expect EVERY octave truncated)", region_m, ), ] { let n_cells = (grid_side * grid_side) as u64; let t0 = Instant::now(); for row in 0..grid_side { for col in 0..grid_side { // Sample POSITIONS stay at Block spacing throughout — only the // cutoff VALUE varies — so this isolates the cutoff's cost // effect from a spacing change. let wx = col as f64 * block_m; let wy = row as f64 * block_m; let prof = derive_at_metres(seed, "bench", ¶ms, &ta, wx, wy, &climate, cutoff_m, &[]); std::hint::black_box(prof.elev_q); } } let elapsed = t0.elapsed(); let per_cell_ns = elapsed.as_secs_f64() * 1e9 / n_cells as f64; println!( " {label:<58}: {:>8.2} ms total, {:>7.1} ns/cell ({:.3} us/cell)", elapsed.as_secs_f64() * 1000.0, per_cell_ns, per_cell_ns / 1000.0 ); } println!(); } // --------------------------------------------------------------------------- // Interview-2 redirect: chunk (64 m) — the never-benched rung, now the // proposed deepest Atlas ladder rung (Jeroen, interview 2: "the actual tile // level rung seems unusable. maybe replace with 64?" — tile/voxel dropped // from the Atlas ladder; chunk becomes the bottom). Same discipline as the // original T-1154 benches above: call `derive_at_metres` directly (no // wire-facing cutoff band exists below Quarter's 1,024 m `MIN_WL_BANDS_M` // floor either), matched cutoff = spacing (Nyquist), 4,096-cell sweep for // direct comparability with the existing Block/Tile row above, plus a // realistic deep-step VIEWPORT canvas at chunk spacing (replacing the old // 216x384m/1m-spacing deep-step bench, which measured the now-dropped tile // rung). // --------------------------------------------------------------------------- /// Chunk (64 m) per-cell derive cost, matched to the existing Block/Tile /// 4,096-cell sweep shape (`bench_block_and_tile_spacing_4096_cells` above) /// so this row slots directly into the same comparison table. This is the /// ONE rung on the D-243 ladder nobody had measured before interview 2 (T-1154 /// tested Block 128m and Tile-adjacent 1m/4m; chunk's 64m spacing sits /// between them and was never run). `VOXEL_OCTAVE_WAVELENGTHS_M`'s finest /// entry is 128m (`detail_scatter.rs:46`), so per the SAME cutoff-mechanism /// finding `bench_block_cutoff_confirms_savings` already established for /// Block, a cutoff at 64m (finer than every entry in that array) should /// truncate nothing either — this bench CONFIRMS that expectation for chunk /// specifically rather than assuming it transfers from Block's own result. #[test] #[ignore] fn bench_chunk_spacing_4096_cells() { let hm = bench_hm(); let ta = bench_ta(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); let grid_side = 64u32; // 4,096 cells — matches the Block/Tile sweep above println!( "\n=== Interview-2: chunk (64m) spacing derive_at_metres benchmark (4,096-cell sweep) ===" ); println!( "grid: {grid_side}x{grid_side} = {} cells/sweep\n", grid_side * grid_side ); let chunk_m = scale::CHUNK_M as f64; // 64 m let block_m = scale::BLOCK_M as f64; // 128 m, for direct side-by-side for (label, step_m, cutoff_m) in [ ("chunk (64m), cutoff=64m", chunk_m, chunk_m), ("chunk (64m), UNCUT (cutoff=0)", chunk_m, 0.0), ( "block (128m), cutoff=128m [reference row]", block_m, block_m, ), ] { let n_cells = (grid_side * grid_side) as u64; let t0 = Instant::now(); for row in 0..grid_side { for col in 0..grid_side { let wx = col as f64 * step_m; let wy = row as f64 * step_m; let prof = derive_at_metres(seed, "bench", ¶ms, &ta, wx, wy, &climate, cutoff_m, &[]); std::hint::black_box(prof.elev_q); } } let elapsed = t0.elapsed(); let per_cell_ns = elapsed.as_secs_f64() * 1e9 / n_cells as f64; println!( " {label:<44}: {:>8.2} ms total, {:>7.1} ns/cell ({:.3} us/cell)", elapsed.as_secs_f64() * 1000.0, per_cell_ns, per_cell_ns / 1000.0 ); } println!(); } /// The NEW realistic deepest-step canvas — chunk (64 m) spacing replacing /// the dropped tile (1 m) rung. Jeroen's interview-2 ruling: the old /// 10px/tile bottom-out ("full 1920 screen at 10px/tile shows ~192x108m") is /// in-world viewport territory (Phase 5), not Atlas map content — chunk (64 /// m, D-243's "stream/derive unit") is the new floor. /// /// Display-band derivation for the new bottom-out, stated precisely (this is /// the number Tyre's amendment text needs): at 1x1 px-per-gridunit (the /// workshop's own ideal ratio, premise 5), a 3840x2160 canvas at 64 m /// spacing covers `2160 * 64 = 138,240 m` (~138.2 km) on the smaller axis and /// `3840 * 64 = 245,760 m` (~245.8 km) on the larger axis — i.e. the /// bottom-out is "1 screen px per 64m gridunit", NOT "10 px per chunk" (10 /// px/gridunit would need a canvas 10x larger in EXTENT for the same pixel /// budget, which no longer makes sense once chunk stands in for what tile's /// 10x margin was there to buy: legibility of a 1m ground feature at low /// pixel density; chunk itself IS the smallest legible Atlas content unit /// now, so it wants 1x1, not a magnification margin on top of 1x1). Full /// working: `canvas_px / gridunit_spacing_m = world_extent_m` per axis (the /// same arithmetic the old tile bottom-out used, just at 64m instead of 1m /// and without the 10x margin factor tile's own screen-legibility problem /// needed). This bench uses the FULL 3840x2160 canvas at 1x1 (matching every /// other rung's fixed-px-budget convention, per round 2 §(c) — chunk is the /// first deepest rung that does NOT need the display-ratio-sized-canvas /// exception the old tile rung required, precisely because it's not /// undersized relative to a legibility margin the way 1m/10px was). #[test] #[ignore] fn bench_chunk_deep_step_realistic_canvas() { let hm = bench_hm(); let ta = bench_ta(&hm); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(99).derive(SeedDomain::Body, 1); // Full 3840x2160 canvas, 1 gridunit per screen px, 64 m spacing. let cols = 3840u32; let rows = 2160u32; let cells = (rows as u64) * (cols as u64); let step_m = scale::CHUNK_M as f64; // 64 m let cutoff_m = step_m; // Nyquist-matched let world_w_km = cols as f64 * step_m / 1000.0; let world_h_km = rows as f64 * step_m / 1000.0; println!("\n=== Interview-2: chunk (64m) deep-step realistic-canvas bench (3840x2160 @ 1x1 px/gridunit) ==="); println!( " geometry: 3840x2160 canvas @ 64m/gridunit, 1x1 px-per-gridunit -> {world_w_km:.1} km x {world_h_km:.1} km world extent" ); println!(" cells = 3840 * 2160 = {cells}"); println!(" {}\n", rayon_threads_report()); let (elapsed_par, ns_per_cell_par) = rect_window_replica( seed, "bench", ¶ms, &ta, &climate, cols, rows, step_m, cutoff_m, ); println!( " PARALLEL (row-chunked): {:.2} ms, {:.1} ns/cell ({:.3} us/cell)", elapsed_par.as_secs_f64() * 1000.0, ns_per_cell_par, ns_per_cell_par / 1000.0 ); let pool = rayon::ThreadPoolBuilder::new() .num_threads(1) .build() .expect("build single-thread rayon pool"); let (elapsed_seq, ns_per_cell_seq) = pool.install(|| { rect_window_replica( seed, "bench", ¶ms, &ta, &climate, cols, rows, step_m, cutoff_m, ) }); println!( " SINGLE-THREAD: {:.2} ms, {:.1} ns/cell ({:.3} us/cell)", elapsed_seq.as_secs_f64() * 1000.0, ns_per_cell_seq, ns_per_cell_seq / 1000.0 ); println!( " speedup: {:.2}x\n", elapsed_seq.as_secs_f64() / elapsed_par.as_secs_f64() ); } // --------------------------------------------------------------------------- // S2 (ruled: before filing) — deep-step x high-river-density COURSES-INCLUSIVE // cost. The last zero-data-point cell: every courses-inclusive number // measured so far (Cross-check 1 in the results doc, 18 courses/331,776 // cells) is at District spacing. Nothing has measured courses-on cost at the // NEW deepest rung (chunk, 64m, per interview 2) or at Block (128m) — both // below District, where a real river window would have MORE edges in view // per unit area (finer spacing = smaller world extent per canvas, but a real // river network's edge density near a river is roughly constant per unit // ground area, so a narrower window can still contain a densely-braided // stretch). Builds real InventedCourse fixtures via the actual PUBLIC // invention pipeline (`river_course::build_edges` + `river_course::invent_course` // — both `pub`, unlike `layer_proxy::invent_courses_near_window` itself, // which is private to that module; this bench replicates its per-edge // invention loop using the same public primitives, same discipline as // `rect_window_replica` already replicates `build_district_window_layer`'s // internals elsewhere in this file). // --------------------------------------------------------------------------- /// Build a high-density `InventedCourse` set from the REAL GJ1c river /// network — every edge whose invented course falls within /// `inflate_m` of the given world-metre window, at the given station /// spacing/cutoff. This is the densest REAL course set available in this /// repo (GJ1c is the only body with a river network already wired into a /// bench fixture) rather than a synthetic worst case — real geometry is /// preferred per this workshop's own measurement discipline (T-1178's cross- /// check pattern: synthetic first, then confirm on real geometry). Returns /// the course list plus the count found, so callers can report density /// alongside cost. fn build_gj1c_courses_near_window( seed: SeedChain, ta: &TerrainAnalysis, params: &BodyParams, river_network: &settled_reach_server::atlas::body_world_state::RiverNetwork, win_x0: f64, win_y0: f64, win_x1: f64, win_y1: f64, station_spacing_m: f64, min_wavelength_m: f64, ) -> Vec { let edges = river_course::build_edges(river_network); let r_km = params.body_radius_km.expect("body_radius_km required"); // Inline the same pixel->world-metres formula the existing GJ1c // cross-check bench above already uses (district_profile::pixel_to_world_m // is `pub(crate)`, not reachable from an integration test — this is the // SAME formula, inlined, not a different one; consistent with how // `bench_square_window_production_fn_gj1c_real_body_crosscheck` and // zoom_ladder_bench.rs's `bench_course_cost_on_vs_off` already do this). let to_world = |row: u16, col: u16| -> (f64, f64) { ( col as f64 / ta.w as f64 * (std::f64::consts::TAU * r_km * 1000.0), (row as f64 / (ta.h - 1) as f64 - 0.5) * (std::f64::consts::PI * r_km * 1000.0), ) }; let mut courses = Vec::new(); for edge in &edges { let anchor_a = to_world(edge.upstream.0, edge.upstream.1); let anchor_b = to_world(edge.downstream.0, edge.downstream.1); let chord_m = ((anchor_a.0 - anchor_b.0).powi(2) + (anchor_a.1 - anchor_b.1).powi(2)).sqrt(); // Same 0.08 inflation fraction layer_proxy.rs's COURSE_BBOX_INFLATION_FRACTION // uses (that constant itself is private; the value is stated in its // own doc and reproduced here for the same bbox-cull purpose — a // bench-local approximation of the real cull, not a claim of exact // production parity for the cull step itself, which doesn't affect // measured PER-CELL cost once a course is in the list). let inflate_m = chord_m * 0.08; let (bx0, bx1) = ( anchor_a.0.min(anchor_b.0) - inflate_m, anchor_a.0.max(anchor_b.0) + inflate_m, ); let (by0, by1) = ( anchor_a.1.min(anchor_b.1) - inflate_m, anchor_a.1.max(anchor_b.1) + inflate_m, ); if bx1 < win_x0 || bx0 > win_x1 || by1 < win_y0 || by0 > win_y1 { continue; } courses.push(river_course::invent_course( seed, edge, ta, params, station_spacing_m, min_wavelength_m, )); } courses } /// S2: courses-on vs courses-off, at BOTH the new deepest rung (chunk, 64m) /// and Block (128m), over a window picked to maximize real river-edge /// density (the densest real region in the only river-network fixture this /// repo's benches have — GJ1c). Reports the delta as both absolute ms and /// percentage, matching `bench_course_cost_on_vs_off`'s own reporting shape /// (District's own courses-on-vs-off number: +0.09-0.21ms against a ~5ms /// baseline, under 5%) so this fills in the two remaining zero-data-point /// cells on the same comparison axis. #[test] #[ignore] fn bench_s2_courses_density_at_chunk_and_block() { let (hm, ta) = gj1c_fixture(); let dr = drainage::analyze(&hm.data, hm.width, hm.height, hm.sea_level); let rn = dr.river_network.clone(); let params = bench_params(); let climate = ClimateConstants::default(); let seed = SeedChain::root(0xC0FFEE_u64).derive(SeedDomain::Body, 7); assert!( !rn.river_cells.is_empty(), "GJ1c at production working resolution must have river cells for this bench to be meaningful" ); // Find the highest-density river region: scan river cells and pick the // one with the most OTHER river cells within a fixed pixel radius — a // proxy for confluence/braided density, maximizing edges-per-window // rather than picking an arbitrary river cell as the existing single // cross-check bench does. let radius_px = 8i64; // small radius = local confluence density, not just "near any river" let mut best_cell = rn.river_cells[0]; let mut best_count = -1i64; for &cell in &rn.river_cells { let mut count = 0i64; for &other in &rn.river_cells { let dr_ = cell.0 as i64 - other.0 as i64; let dc_ = cell.1 as i64 - other.1 as i64; if dr_ * dr_ + dc_ * dc_ <= radius_px * radius_px { count += 1; } } if count > best_count { best_count = count; best_cell = cell; } } let r_km = params.body_radius_km.expect("body_radius_km required"); let to_world = |row: u16, col: u16| -> (f64, f64) { ( col as f64 / ta.w as f64 * (std::f64::consts::TAU * r_km * 1000.0), (row as f64 / (ta.h - 1) as f64 - 0.5) * (std::f64::consts::PI * r_km * 1000.0), ) }; let center_world = to_world(best_cell.0, best_cell.1); println!("\n=== S2: courses-on vs courses-off density bench (chunk 64m + block 128m, densest GJ1c river region) ==="); println!( " densest river cell: {best_cell:?} ({best_count} river cells within {radius_px}px radius), world center {center_world:?}" ); for (label, step_m) in [ ("chunk (64m)", scale::CHUNK_M as f64), ("block (128m)", scale::BLOCK_M as f64), ] { // Realistic-shape window at this spacing: 64x64 cells (4,096, matching // this file's other 4,096-cell sweeps for direct comparability). let grid_side = 64u32; let half_extent_m = (grid_side as f64 / 2.0) * step_m; let win_x0 = center_world.0 - half_extent_m; let win_x1 = center_world.0 + half_extent_m; let win_y0 = center_world.1 - half_extent_m; let win_y1 = center_world.1 + half_extent_m; let courses = build_gj1c_courses_near_window( seed, &ta, ¶ms, &rn, win_x0, win_y0, win_x1, win_y1, step_m, step_m, ); let total_points: usize = courses.iter().map(|c| c.points.len()).sum(); let avg_points = if courses.is_empty() { 0.0 } else { total_points as f64 / courses.len() as f64 }; println!( "\n --- {label}: {grid_side}x{grid_side} window ({:.0}m x {:.0}m), courses_in_window={}, avg_points_per_course={:.1} (station_spacing_m={step_m}) ---", half_extent_m * 2.0, half_extent_m * 2.0, courses.len(), avg_points ); let n_cells = (grid_side * grid_side) as u64; let iterations = 200; // higher rep count — a single 4,096-cell sweep is sub-10ms, noisy at n=1 // Courses OFF. let t_off = Instant::now(); for _ in 0..iterations { for row in 0..grid_side { for col in 0..grid_side { let wx = win_x0 + col as f64 * step_m; let wy = win_y0 + row as f64 * step_m; let prof = derive_at_metres(seed, "GJ1c", ¶ms, &ta, wx, wy, &climate, step_m, &[]); std::hint::black_box(prof.elev_q); } } } let elapsed_off = t_off.elapsed(); // Courses ON. let t_on = Instant::now(); for _ in 0..iterations { for row in 0..grid_side { for col in 0..grid_side { let wx = win_x0 + col as f64 * step_m; let wy = win_y0 + row as f64 * step_m; let prof = derive_at_metres( seed, "GJ1c", ¶ms, &ta, wx, wy, &climate, step_m, &courses, ); std::hint::black_box(prof.elev_q); } } } let elapsed_on = t_on.elapsed(); let ms_off_per_sweep = elapsed_off.as_secs_f64() * 1000.0 / iterations as f64; let ms_on_per_sweep = elapsed_on.as_secs_f64() * 1000.0 / iterations as f64; let delta_ms = ms_on_per_sweep - ms_off_per_sweep; let delta_pct = 100.0 * delta_ms / ms_off_per_sweep; let ns_per_cell_off = elapsed_off.as_secs_f64() * 1e9 / (n_cells * iterations as u64) as f64; let ns_per_cell_on = elapsed_on.as_secs_f64() * 1e9 / (n_cells * iterations as u64) as f64; println!(" courses OFF: {ms_off_per_sweep:.4} ms/sweep ({ns_per_cell_off:.1} ns/cell)"); println!(" courses ON: {ms_on_per_sweep:.4} ms/sweep ({ns_per_cell_on:.1} ns/cell)"); println!( " delta: {delta_ms:+.4} ms/sweep ({delta_pct:+.2}%), {} courses in window", courses.len() ); } println!(); }