Files
settled-reach/server/tests/bmv_global_tier_bench.rs
T

345 lines
15 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.
//! Body Map Viewer workshop — global-tier byte-cost recheck (Jeroen's
//! post-ratification correction to the ladder top).
//!
//! Jeroen's correction: GLOBAL is rung 0, the body-surface opener, with a
//! **VARIABLE canvas = the body's own region grid** (one gridunit PER
//! REGION, `regions_per_equator × regions_per_equator/2`, D-243's elastic
//! seam) — NOT a fixed 3840×2160 District-spacing canvas the way the round-2
//! cache-tier spec's ~174 MB figure assumed. REGION is rung 1, the largest
//! FIXED-size rung (viewport-sized, evictable like every other sub-global
//! rung). This file recomputes the always-keep global-tier byte budget
//! against the CORRECT rung-0 shape, using REAL per-body radii read from
//! `systems.db` via [`settled_reach_server::atlas::body_params_reader::BodyParamsReader`]
//! (never raw `sqlite3` — the project's asset-pipeline rule) — not an
//! assumed Earth-class uniform radius, since region-grid size is the ONE
//! per-body-floating quantity in the whole D-243 ladder (the elastic seam)
//! and the whole point of this recheck is that assuming Earth-class for
//! every body was the error being corrected.
//!
//! Run: `cargo test --release --test bmv_global_tier_bench -- --ignored --nocapture`
use std::path::PathBuf;
use std::time::Instant;
use settled_reach_server::atlas::body_params_reader::BodyParamsReader;
use settled_reach_server::atlas::district_profile::{
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::scale;
use settled_reach_server::seed::{SeedChain, SeedDomain};
/// Same body-discovery walk the T-1177 population survey bench
/// (`hydrology_equilibrium_bench.rs::bench_population_survey_all_committed_bodies`)
/// already established — every committed `heightmap.png`'s parent directory
/// name is a real body_id. Reused here (not re-invented) so this bench's
/// population is exactly the same 267-body set the hydrology survey already
/// covers, for direct comparability.
fn discover_body_ids() -> Vec<String> {
let wiki_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../wiki/star-systems");
let mut ids = Vec::new();
fn walk(dir: &std::path::Path, out: &mut Vec<String>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
walk(&path, out);
} else if path.file_name().and_then(|n| n.to_str()) == Some("heightmap.png") {
if let Some(body_id) = path
.parent()
.and_then(|p| p.file_name())
.and_then(|n| n.to_str())
{
out.push(body_id.to_string());
}
}
}
}
walk(&wiki_root, &mut ids);
ids.sort();
ids
}
/// The global/rung-0 canvas cell count for a body of the given radius:
/// `regions_per_equator(R) × (regions_per_equator(R) / 2)` — one gridunit
/// PER REGION (Jeroen's ruling), pole-to-pole being half the equatorial
/// count per [`scale::regions_per_equator`]'s own doc.
fn rung0_cells(body_radius_km: f64) -> u64 {
let cols = scale::regions_per_equator(body_radius_km) as u64;
let rows = (cols / 2).max(1);
cols * rows
}
/// T-1179's measured PNG-per-field rate: 638,382 bytes / 331,776 cells at
/// district spacing (the only body+field-set this workshop measured a real
/// encode on) = 1.924 bytes/cell PNG-encoded, six dense fields
/// (morphology/elev_q/temp_dc/moisture_q/vegetation/glaciation). Applied
/// here as the SAME field-set/encoding assumption the round-2 cache-tier
/// spec used for the (wrong-shape) 174 MB estimate — this bench corrects the
/// CANVAS SHAPE, not the per-cell wire-cost model, so the two numbers are
/// comparable apples-to-apples on the encoding axis and differ only on the
/// canvas-shape axis Jeroen actually corrected.
const PNG_BYTES_PER_CELL: f64 = 638_382.0 / 331_776.0;
#[test]
#[ignore]
fn bench_global_tier_bytes_real_population() {
let systems_db = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("data/systems.db");
let reader = BodyParamsReader::open(&systems_db)
.expect("open read-only systems.db (asset-pipeline golden rule: read-only snapshot)");
let body_ids = discover_body_ids();
assert!(
body_ids.len() > 200,
"expected the real committed body population (~267), found {}",
body_ids.len()
);
let mut found = 0usize;
let mut missing_radius: Vec<String> = Vec::new();
let mut total_cells: u64 = 0;
let mut per_body: Vec<(String, f64, u64)> = Vec::new(); // (body_id, radius_km, cells)
for body_id in &body_ids {
match reader.read_body_params(body_id) {
Ok(params) => {
if let Some(r_km) = params.body_radius_km {
let cells = rung0_cells(r_km);
total_cells += cells;
per_body.push((body_id.clone(), r_km, cells));
found += 1;
} else {
missing_radius.push(body_id.clone());
}
}
Err(e) => {
missing_radius.push(format!("{body_id} ({e})"));
}
}
}
per_body.sort_by(|a, b| b.2.cmp(&a.2)); // largest region-grid first
let total_bytes_raw6 = total_cells as f64 * 6.0; // 6 raw bytes/cell, DistrictWindowLayer's own documented figure
let total_bytes_png = total_cells as f64 * PNG_BYTES_PER_CELL;
println!(
"\n=== Global-tier (rung 0) byte-cost recheck: REAL population, REAL per-body radii ==="
);
println!(
" bodies discovered: {}, radius found: {found}, missing/unreadable: {}",
body_ids.len(),
missing_radius.len()
);
if !missing_radius.is_empty() {
println!(
" missing radius (excluded from total, listed for audit): {:?}",
&missing_radius[..missing_radius.len().min(10)]
);
if missing_radius.len() > 10 {
println!(" ... and {} more", missing_radius.len() - 10);
}
}
println!("\n total rung-0 cells across population: {total_cells}");
println!(
" average cells/body: {:.0}",
total_cells as f64 / found.max(1) as f64
);
println!(
"\n total bytes, raw 6 B/cell (DistrictWindowLayer's documented rate): {:.2} MB",
total_bytes_raw6 / 1_048_576.0
);
println!(
" total bytes, PNG-per-field ({:.3} B/cell, T-1179's measured rate): {:.2} MB",
PNG_BYTES_PER_CELL,
total_bytes_png / 1_048_576.0
);
println!("\n Top 10 bodies by rung-0 cell count (largest global canvases):");
for (body_id, r_km, cells) in per_body.iter().take(10) {
let cols = scale::regions_per_equator(*r_km);
println!(
" {body_id:>12} radius={r_km:>8.1}km regions_per_equator={cols:>4} cells={cells:>7} ({:.1} KB PNG)",
*cells as f64 * PNG_BYTES_PER_CELL / 1024.0
);
}
println!("\n Bottom 5 bodies by rung-0 cell count (smallest global canvases):");
for (body_id, r_km, cells) in per_body.iter().rev().take(5) {
let cols = scale::regions_per_equator(*r_km);
println!(
" {body_id:>12} radius={r_km:>8.1}km regions_per_equator={cols:>4} cells={cells:>7} ({:.1} KB PNG)",
*cells as f64 * PNG_BYTES_PER_CELL / 1024.0
);
}
// Earth-class reference point (R=6371km), for direct comparison against
// the brief appendix's own "~195x98 Earth-sized" framing.
let earth_cols = scale::regions_per_equator(6371.0);
let earth_rows = (earth_cols / 2).max(1);
println!(
"\n Reference: Earth-class (R=6371km) regions_per_equator={earth_cols}, rows={earth_rows}, cells={}",
earth_cols as u64 * earth_rows as u64
);
println!();
}
// ---------------------------------------------------------------------------
// Rung-0 (GLOBAL opener) derive cost — MEASURED, not extrapolated (Tyre's
// bracket request). The existing `bench_derive_orbital_at_metres_region_spacing`
// (zoom_ladder_bench.rs) measures `derive_orbital_at_metres`'s per-cell rate
// at a fixed 4,096-cell (64x64) sweep — that number is real, but scaling it
// up to a whole rung-0 canvas by multiplication is exactly the kind of
// "EXTRAPOLATED from the measured per-cell rate" label that bench's own
// full-canvas rows already carry (explicitly disclosed there, not measured).
// This bench instead runs the REAL per-body canvas shape (the actual
// regions_per_equator(R) x regions_per_equator(R)/2 grid, real per-body
// radius) end-to-end for a representative sample of real bodies, so the
// rung-0 derive-cost figure is measured at the shape it will actually be
// served at, not inferred from a differently-shaped sweep.
// ---------------------------------------------------------------------------
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)
}
/// Real rung-0 canvas derive cost at three representative real body sizes
/// from the population (smallest, Earth-class-nearest, largest), single
/// call per cell through the actual `derive_orbital_at_metres` function —
/// no square-sweep proxy shape, the real `cols x rows` extent each body's
/// canvas would actually be.
#[test]
#[ignore]
fn bench_rung0_derive_cost_real_canvas_shapes() {
let hm = bench_hm();
let ta = bench_ta(&hm);
let params = BodyParams {
hydrosphere: Some("ocean".into()),
atmosphere: Some("breathable".into()),
planet_class: Some("temperate".into()),
body_radius_km: Some(6371.0), // overridden per-case below
..Default::default()
};
let climate = ClimateConstants::default();
let seed = SeedChain::root(99).derive(SeedDomain::Body, 1);
let region_m = scale::REGION_M as f64;
println!("\n=== Rung-0 (GLOBAL opener) derive cost — REAL canvas shapes, MEASURED not extrapolated ===\n");
// Representative cases from the real population survey
// (bmv_global_tier_bench.rs::bench_global_tier_bytes_real_population):
// smallest (GJ784c-m1, a moon), Earth-class reference, largest (GJ325Ac).
let cases: [(&str, f64); 3] = [
("GJ784c-m1 (smallest, moon)", 733.9),
("Earth-class reference", 6371.0),
("GJ325Ac (largest)", 7317.6),
];
// Per-body average cell count across the real population (from the
// sibling bench in this file): 18,073 cells/body, 267 bodies.
const AVG_CELLS_PER_BODY: u64 = 18_073;
const BODY_COUNT: u64 = 267;
for (label, r_km) in cases {
let cols = scale::regions_per_equator(r_km);
let rows = (cols / 2).max(1);
let cells = (cols as u64) * (rows as u64);
let mut body_params = params.clone();
body_params.body_radius_km = Some(r_km);
let t0 = Instant::now();
for row in 0..rows {
for col in 0..cols {
let wx = col as f64 * region_m;
let wy = row as f64 * region_m;
let prof =
derive_orbital_at_metres(seed, "bench", &body_params, &ta, wx, wy, &climate);
std::hint::black_box(prof.elev_q);
}
}
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!(
" {label:<28}: radius={r_km:>8.1}km cols={cols:>4} rows={rows:>4} cells={cells:>6}: \
{ms:>8.3} ms single-thread, {ns_per_cell:>7.1} ns/cell"
);
}
// All-267-bodies single-thread total, using the MEASURED per-cell rate
// from the Earth-class case above (representative — T-1178/T-1154 already
// established this per-cell rate is flat across canvas size) applied to
// the REAL total cell count across the population (4,825,615, from the
// sibling bench), not the average-cells-per-body figure multiplied out
// blindly.
let (_, earth_r_km) = cases[1];
let earth_cols = scale::regions_per_equator(earth_r_km);
let earth_rows = (earth_cols / 2).max(1);
let earth_cells = (earth_cols as u64) * (earth_rows as u64);
let mut earth_body_params = params.clone();
earth_body_params.body_radius_km = Some(earth_r_km);
let t0 = Instant::now();
for row in 0..earth_rows {
for col in 0..earth_cols {
let wx = col as f64 * region_m;
let wy = row as f64 * region_m;
let prof =
derive_orbital_at_metres(seed, "bench", &earth_body_params, &ta, wx, wy, &climate);
std::hint::black_box(prof.elev_q);
}
}
let earth_elapsed = t0.elapsed();
let earth_ns_per_cell = earth_elapsed.as_secs_f64() * 1e9 / earth_cells as f64;
let total_cells_all_267 = 4_825_615u64; // measured directly in bench_global_tier_bytes_real_population
let total_ms_all_267_singlethread = total_cells_all_267 as f64 * earth_ns_per_cell / 1e6;
println!(
"\n Reference per-cell rate used for population total (Earth-class case, MEASURED above): {earth_ns_per_cell:.1} ns/cell"
);
println!(
" Real per-body average (this file's population bench): {AVG_CELLS_PER_BODY} cells/body x {BODY_COUNT} bodies = {} total cells",
AVG_CELLS_PER_BODY * BODY_COUNT
);
println!(
" ALL 267 real bodies' rung-0 canvases, single-thread total (measured rate x real total cell count 4,825,615): {total_ms_all_267_singlethread:.1} ms = {:.3} s",
total_ms_all_267_singlethread / 1000.0
);
println!(
" Note: this is a ONE-TIME cost PER BODY (rung-0 solved once per body, held in the \
keep-always cache per Tier 1) — never a per-request or per-frame cost, and never all \
267 bodies solved in one synchronous batch in production (each body's rung-0 canvas \
is populated lazily on that body's first Atlas-open, same as the existing D-206 \
background-queue population path). The all-267-summed total above prices the \
worst-case ceiling (every body opened once, back to back, single-threaded); the \
REAL per-body cost that matters for a single Atlas-open is the individual-body rows \
above (~16-21 ms single-thread for one body's rung-0 canvas — trivially interactive, \
parallelizes further if ever needed the same way T-1177's per-body hydrology solves do)."
);
println!();
}