//! Zoom-ladder derivation benchmarks (T-1149, design doc §2/§7/§8 step 1). //! //! Measures `derive_at_metres` per-cell cost at district spacing (2,048 m) and //! quarter spacing (512 m), with and without a `min_wavelength_m` octave //! cutoff — the exact numbers the design doc flags as UNBUILT/UNMEASURED //! (§7: "Octave-cutoff derive (min_wavelength_m-bearing) ... not measured"). //! //! Manual `Instant`-based timing, matching every other bench in this repo //! (`shadowcast_bench.rs`, `perf_bench.rs`) and the same technique //! `aliveness_probe --render` used to produce the ~1.2–1.4 µs/district //! release figure the design doc cites — no criterion dependency exists here. //! //! Run: `cargo test --release --test zoom_ladder_bench -- --ignored --nocapture` //! (debug numbers are ~5x slower and not representative of the design doc's //! release-build figures; run `--release` for numbers worth recording). use std::time::Instant; use settled_reach_server::atlas::district_profile::{ derive_at_metres, derive_orbital_at_metres, BodyParams, ClimateConstants, }; use settled_reach_server::atlas::drainage; use settled_reach_server::atlas::features::TerrainAnalysis; use settled_reach_server::atlas::heightmap::BodyHeightmap; use settled_reach_server::atlas::layer_proxy::{ build_district_window_layer, WindowGranularity, DISTRICT_WINDOW_MAX_N_REGION, WIRE_CAP_CELLS, }; use settled_reach_server::atlas::scale; use settled_reach_server::seed::{SeedChain, SeedDomain}; fn bench_hm() -> BodyHeightmap { // Same shape as district_profile.rs's own test_hm/window_test_hm fixtures // — a smooth gradient, deterministic, no PNG I/O. 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_params() -> BodyParams { BodyParams { hydrosphere: Some("ocean".into()), atmosphere: Some("breathable".into()), planet_class: Some("temperate".into()), body_radius_km: Some(6371.0), ..Default::default() } } /// Time `n_cells` sequential `derive_at_metres` calls on a spacing-`step_m` /// grid starting at world origin, with the given octave cutoff. Returns /// (total_elapsed, per_cell_ns). fn time_derive_sweep( seed: SeedChain, body_id: &str, params: &BodyParams, ta: &TerrainAnalysis, climate: &ClimateConstants, grid_side: u32, step_m: f64, min_wavelength_m: f64, ) -> (std::time::Duration, f64) { 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, body_id, params, ta, wx, wy, climate, min_wavelength_m); // Prevent the optimizer from hoisting the call out of the loop. std::hint::black_box(prof.elev_q); } } let elapsed = t0.elapsed(); let per_cell_ns = elapsed.as_secs_f64() * 1e9 / n_cells as f64; (elapsed, per_cell_ns) } #[test] #[ignore] fn bench_derive_at_metres_district_and_quarter_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 grid_side = 64u32; // 4,096 cells per sweep — matches the D-226 window cap println!("\n=== T-1149 zoom-ladder derive_at_metres benchmark ==="); println!( "grid: {grid_side}x{grid_side} = {} cells/sweep\n", grid_side * grid_side ); let district_m = scale::DISTRICT_M as f64; let quarter_m = scale::QUARTER_M as f64; // District spacing (2,048 m), cutoff 0 — today's uncut behavior. let (elapsed, per_cell_ns) = time_derive_sweep( seed, "bench", ¶ms, &ta, &climate, grid_side, district_m, 0.0, ); println!( "district spacing, cutoff=0: {:>8.2} ms total, {:>7.1} ns/cell ({:.3} µs/cell)", elapsed.as_secs_f64() * 1000.0, per_cell_ns, per_cell_ns / 1000.0 ); // District spacing, cutoff 2,048 m — truncates every OCTAVE_WAVELENGTHS_M // entry below the district's own spacing (finest is 4,096 m, so this // cutoff is BELOW that — confirms the cutoff plumbing at district scale // without changing which octaves survive, since 2,048 < 4,096 admits all // of them; recorded for the design doc's requested (district, cutoff // 2048) combination regardless). let (elapsed, per_cell_ns) = time_derive_sweep( seed, "bench", ¶ms, &ta, &climate, grid_side, district_m, 2_048.0, ); println!( "district spacing, cutoff=2048m: {:>8.2} ms total, {:>7.1} ns/cell ({:.3} µs/cell)", elapsed.as_secs_f64() * 1000.0, per_cell_ns, per_cell_ns / 1000.0 ); // Quarter spacing (512 m), cutoff 512 m — the T-1150 Option B rung: full // reclassification at quarter spacing with the matching octave cutoff. let (elapsed, per_cell_ns) = time_derive_sweep( seed, "bench", ¶ms, &ta, &climate, grid_side, quarter_m, 512.0, ); println!( "quarter spacing, cutoff=512m: {:>8.2} ms total, {:>7.1} ns/cell ({:.3} µs/cell)", elapsed.as_secs_f64() * 1000.0, per_cell_ns, per_cell_ns / 1000.0 ); println!(); } /// Time `n_cells` sequential `derive_orbital_at_metres` calls — the /// region-baseline-blend-only path (T-1152, design doc §2/§4/§9 R1), no /// `invent_primitives` call at any point. Mirrors `time_derive_sweep`'s shape /// exactly so the two numbers are directly comparable. fn time_orbital_sweep( seed: SeedChain, body_id: &str, params: &BodyParams, ta: &TerrainAnalysis, climate: &ClimateConstants, grid_side: u32, step_m: f64, ) -> (std::time::Duration, f64) { 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_orbital_at_metres(seed, body_id, params, ta, wx, wy, climate); std::hint::black_box(prof.elev_q); } } let elapsed = t0.elapsed(); let per_cell_ns = elapsed.as_secs_f64() * 1e9 / n_cells as f64; (elapsed, per_cell_ns) } /// T-1152 / design doc §9 R1: "MEASURE FIRST" — per-cell cost of the /// orbital-mode region-baseline-blend-only path (no `invent_primitives`) at /// coarse (region-scale, ≥205 km) spacings, plus a realistic full-orbital-frame /// extrapolation (1600×900 canvas). This is the number the design doc's §4/§7 /// planetary-rung cost story rested on as an UNMEASURED extrapolation — /// this test replaces "extrapolated from the uncut per-cell rate" with an /// actually-measured orbital-path rate. #[test] #[ignore] fn bench_derive_orbital_at_metres_region_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 grid_side = 64u32; // 4,096 cells/sweep, same shape as the district/quarter sweeps above println!("\n=== T-1152 orbital-rung derive_orbital_at_metres benchmark ==="); println!( "grid: {grid_side}x{grid_side} = {} cells/sweep\n", grid_side * grid_side ); let region_m = scale::REGION_M as f64; // Region spacing (204,800 m) — the coarsest named rung short of the // planet-wide elastic seam (D-243). let (elapsed, per_cell_ns) = time_orbital_sweep(seed, "bench", ¶ms, &ta, &climate, grid_side, region_m); println!( "orbital, region spacing (204.8km): {:>8.2} ms total, {:>7.1} ns/cell ({:.3} µs/cell)", elapsed.as_secs_f64() * 1000.0, per_cell_ns, per_cell_ns / 1000.0 ); // Same spacing, for direct comparison: the FULL derive_at_metres path // (invent_primitives included) at the SAME region spacing — quantifies // exactly what skipping invention buys, at the spacing where it matters. let (elapsed_full, per_cell_ns_full) = time_derive_sweep( seed, "bench", ¶ms, &ta, &climate, grid_side, region_m, 0.0, ); println!( "district-mode (full derive_at_metres) at region spacing: {:>8.2} ms total, {:>7.1} ns/cell ({:.3} µs/cell)", elapsed_full.as_secs_f64() * 1000.0, per_cell_ns_full, per_cell_ns_full / 1000.0 ); println!( "orbital speedup vs. full derive at the same spacing: {:.2}x\n", per_cell_ns_full / per_cell_ns ); // Realistic full-orbital-frame estimate: a 1600x900 canvas at // ~1-2 px/cell equivalents (design doc §4's worked example resolution // class). Single-thread extrapolation from the MEASURED per-cell rate — // labelled as an extrapolation, not claimed as independently measured at // full canvas size (the parallel/chunked throughput is a SEPARATE // measurement, T-1151's row-chunked par_iter, already landed and reused // unchanged by the orbital rung's serving path — see the ticket report). for (label, px_per_cell) in [("1 px/cell", 1u32), ("2 px/cell", 2u32)] { let cols = 1600 / px_per_cell; let rows = 900 / px_per_cell; let cells = (cols as u64) * (rows as u64); let est_ms = cells as f64 * per_cell_ns / 1e6; println!( "full-canvas 1600x900 @ {label} ({cols}x{rows} = {cells} cells): \ {est_ms:.1} ms single-thread (EXTRAPOLATED from the measured per-cell rate above)" ); } println!(); } /// **T-1152 R1 — the number that actually governs interactive latency**, as /// opposed to the full-canvas single-shot extrapolation above (which the /// design doc's own carrier ruling makes moot — Jeroen's ruling is /// progressive capped-density TILING, never a whole-canvas one-shot derive). /// This measures a single served Region-granularity window tile through the /// REAL production path (`build_district_window_layer`, including its /// row-chunked `par_iter`, T-1151) at the wire-size cap — the same function /// `serve_district_window`/`run_work_item`'s `DeriveWindow` arm calls, not a /// hand-rolled sweep. This is the measured (not extrapolated) parallel /// number the design doc's §7 flagged as missing ("no chunked-par_iter /// benchmark has been run"). #[test] #[ignore] fn bench_served_region_window_tile_at_wire_cap() { 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); println!("\n=== T-1152 served Region-window-tile benchmark (real production path) ==="); // The largest n the server will ever actually derive at Region // granularity is DISTRICT_WINDOW_MAX_N_REGION, clamped further by // clamp_window_n_v2 to the WIRE_CAP_CELLS ceiling — use the SAME // capped n a real client's oversized request would resolve to. let n = DISTRICT_WINDOW_MAX_N_REGION; // Warm-up call (first call on a body pays no extra cost here since ta is // already built — this just avoids counting one-time allocator warm-up // noise in the timed sample). let _ = build_district_window_layer( seed, "bench", ¶ms, &ta, (0, 0), n, &climate, WindowGranularity::Region, 0, ); let iterations = 20; let t0 = Instant::now(); let mut last_side = 0usize; for _ in 0..iterations { let layer = build_district_window_layer( seed, "bench", ¶ms, &ta, (0, 0), n, &climate, WindowGranularity::Region, 0, ); last_side = (layer.morphology.len() as f64).sqrt().round() as usize; std::hint::black_box(layer.elev_q.len()); } let elapsed = t0.elapsed(); let per_call_ms = elapsed.as_secs_f64() * 1000.0 / iterations as f64; println!( "n={n} (DISTRICT_WINDOW_MAX_N_REGION), derived {last_side}x{last_side} region cells \ ({} cells, WIRE_CAP_CELLS={WIRE_CAP_CELLS}):", last_side * last_side ); println!( " {iterations} calls, {:.2} ms total, {per_call_ms:.3} ms/call \ (row-chunked par_iter, {} Rayon threads available)", elapsed.as_secs_f64() * 1000.0, std::thread::available_parallelism() .map(|n| n.get()) .unwrap_or(0) ); println!( " compare: shipped district n=64 cap measures ~5 ms/call (design doc §7, MEASURED)\n" ); }