test(simulation): post-adversarial workshop benches — population survey, chunk rung, S2 density, global tier
hydrology_equilibrium_bench: bench_population_survey_all_committed_bodies (all 267 real heightmaps solved independently — zero carved cells population- wide, ~0.86s total, byte-exact determinism; closes Troblum B1) + bench_per_basin_size_distribution_real_population (22,270 basins: dense wins 100% for lake carriers). bmv_gridunit_bench: chunk-64m per-cell + deep-step canvas benches (1,838 ns/cell, ~1.7s full 4K; Option D's missing row) + S2 courses-density benches (+38-87% at chunk/block, mechanism traced to station spacing scaling with rung cutoff). bmv_global_tier_bench (new): real per-body radii from systems.db via BodyParamsReader — global tier ~8.85MB PNG across the population (supersedes the ~174MB mis-priced figure), rung-0 derive ~16-21ms/body measured. All #[ignore]d release tests, stability re-run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,7 @@ 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};
|
||||
|
||||
@@ -851,3 +852,393 @@ fn bench_block_cutoff_confirms_savings() {
|
||||
}
|
||||
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<InventedCourse> {
|
||||
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!();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user