Files
settled-reach/server/tests/zoom_ladder_bench.rs
T
jpmschweitzer d356b09926 feat(simulation): T-1152 server half — WindowGranularity enum, derive_orbital_at_metres, Region rung on the same carrier
R1 measured first: a capped Region tile through the real production path
(build_district_window_layer + T-1151 par_iter) at the 64x64 wire cap
costs 0.40-0.48ms — faster than the shipped district n=64 window, so
Jeroen's progressive capped-density tiling ruling is comfortably
interactive on-demand. Raw orbital derive ~0.9µs/cell (~2.3x faster than
full derive; region_baseline dominates, not invent_primitives).

R5 redesign: WindowGranularity enum (Quarter/District/Region), serde
named-variant per the RoadNodeKind precedent, spacing from D-243 scale::
constants — the single source of truth. Additive serde-default
window_granularity_v2 request field (None = legacy u32 path; v2 wins when
Some); DistrictWindowLayer.granularity_v2 always echoed. Legacy u32 echo
for Region uses reserved WINDOW_GRANULARITY_REGION_KEY = u32::MAX (never
a legal input) so the old slot cannot lie about aliasing. Cache and
coalescing keys carry the enum itself (Ord by declaration order, D-010).

n stays district-extent at every rung; Region's cell grid is a DIVISION
(round(n/100), min 1) with its own per-axis ceiling
DISTRICT_WINDOW_MAX_N_REGION=6400 and a bounded halving-loop clamp (no
closed form under the rounding division — the client mirror must
replicate the loop).

derive_orbital_at_metres: bilinear envelope reads + region_baseline
temperature, NO invent_primitives (proven by test — slope_q pinned 0),
routed through the shared build_district_profile classification tail so
the existing colorizer family renders orbital cells unchanged. R2
stepped-categorical behavior documented at the function, not implied.

Region aliasing + clamp/echo tests mirror the T-1150 discipline. 1813
lib tests green; clippy clean; fixture regenerated (254->278 bytes, new
echoed field).
2026-07-22 10:35:37 +02:00

341 lines
13 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 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.21.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", &params, &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", &params, &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", &params, &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", &params, &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", &params, &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",
&params,
&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",
&params,
&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"
);
}