//! Rung-0.5 cost measurement on a real body (T-1213, carrying T-1212's question). //! //! D-258 ruled a STORED expanded layer; its 2026-08-06 amendment said to build //! the un-summarisation as a pure function first, measure that, and argue for //! storage only if the numbers force it. This is that measurement: the //! once-per-body solve every rung samples, and one served canvas per rung, on //! Ferrath at the descent ladder's own anchor and the ladder's own extent. //! //! Run: `cargo test --release --test rung_cost_bench -- --ignored --nocapture` //! (debug is several times slower and not worth recording). use std::time::Instant; use settled_reach_server::atlas::believability::cascade_snapshot_for_body; use settled_reach_server::atlas::district_profile::{derive_moisture_ceiling_q, ClimateConstants}; use settled_reach_server::atlas::layer1::run_layer1_with_moisture; use settled_reach_server::atlas::step_canvas::{build_step_canvas, StepCanvasRung}; use settled_reach_server::seed::SeedChain; const BODY: &str = "GJ820Bc"; /// The descent ladder's anchor (tests/visual.json, atlas_GJ820Bc_land_*). const ANCHOR: (i64, i64) = (29_422_008, -5_675_959); /// The ladder's held extent at 3440x1440 (2x2 display ratio). const EXTENT: (u32, u32) = (1290, 540); const RUNS: u32 = 5; #[test] #[ignore = "benchmark on a real body; run explicitly with --release"] fn rung_cost_on_a_real_body() { let Ok((snapshot, params)) = cascade_snapshot_for_body(42, BODY) else { eprintln!("skip: {BODY} not loadable"); return; }; let ceiling = derive_moisture_ceiling_q(¶ms); // The whole-body solve (drainage + settled hydrology) — what D-258 first // proposed moving onto a stored layer, and what already runs once per // body behind the server's TerrainAnalysisCache. let t = Instant::now(); let mut solved = None; for _ in 0..RUNS { solved = Some(run_layer1_with_moisture(&snapshot.heightmap, ceiling)); } let solve_ms = t.elapsed().as_secs_f64() * 1e3 / RUNS as f64; let (l1, ta) = solved.expect("ran"); eprintln!( "whole-body solve ({}x{} working grid): {solve_ms:.1} ms", ta.w, ta.h ); let climate = ClimateConstants::default(); let seed = SeedChain::for_body(42, BODY); for rung in [ StepCanvasRung::Global, StepCanvasRung::Region, StepCanvasRung::District, StepCanvasRung::Quarter, ] { let t = Instant::now(); let mut w = 0; let mut h = 0; for _ in 0..RUNS { let raw = build_step_canvas( seed, BODY, ¶ms, &ta, &l1.river_network, &[], rung, ANCHOR, EXTENT, &climate, 0, ); w = raw.width; h = raw.height; } let ms = t.elapsed().as_secs_f64() * 1e3 / RUNS as f64; assert!(w > 0 && h > 0, "{rung:?} built an empty canvas"); // Wall time: build_step_canvas derives rows in parallel (rayon), so // this is the latency a request sees on this machine, not CPU cost. eprintln!( "{rung:?}: {w}x{h} canvas in {ms:.1} ms wall ({:.2} us/cell)", ms * 1e3 / (w as f64 * h as f64), ); } }