Files
settled-reach/server/examples/bench_layer1.rs
T
jpmschweitzerandClaude Opus 4.7 98658a512d test(simulation): per-body Layer-1 benchmark example (#953)
examples/bench_layer1 times run_layer1 on a synthetic 512x256 heightmap
with a phase breakdown (drainage / terrain analysis / feature extraction).
Post-optimization: ~106ms/body total (drainage ~45ms). Documents the
synthetic-terrain caveat (real heightmaps via #963).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:35:47 +02:00

103 lines
3.9 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.
//! Benchmark: per-body Layer-1 topography generation (#953).
//!
//! Times `run_layer1` (D8 drainage → terrain analysis → 7 feature tags →
//! sub-biome classification) on a synthetic canonical 512×256 heightmap — the
//! cost of "populating the top-level map for a body." Run with:
//!
//! cargo run --release --example bench_layer1
//!
//! The committed systems.db carries no heightmaps yet (the importer isn't in
//! regen-db), so this uses a multi-octave synthetic heightmap representative of
//! a continental body. Heightmap *content* affects timing (river/attractor
//! counts), so treat this as an order-of-magnitude figure against the D-208
//! ~50ms target, not a per-body guarantee.
use std::time::Instant;
use settled_reach_server::atlas::heightmap::{BodyHeightmap, GRID_H, GRID_W};
use settled_reach_server::atlas::layer1::run_layer1;
/// Deterministic multi-octave sine "noise" → continents, coasts, drainage.
fn synth_heightmap(w: u32, h: u32) -> Vec<f32> {
use std::f32::consts::{PI, TAU};
let mut data = vec![0f32; (w * h) as usize];
for r in 0..h {
for c in 0..w {
let x = c as f32 / w as f32 * TAU;
let y = r as f32 / h as f32 * PI;
let e = 0.5
+ 0.25 * (x * 3.0).sin() * (y * 2.0).sin()
+ 0.15 * (x * 7.0).cos() * (y * 5.0).sin()
+ 0.08 * (x * 13.0).sin() * (y * 11.0).cos()
+ 0.05 * (x * 23.0).cos() * (y * 19.0).sin();
data[(r * w + c) as usize] = e.clamp(0.0, 1.0);
}
}
data
}
fn main() {
let (w, h) = (GRID_W, GRID_H);
let hm = BodyHeightmap {
body_id: "Bench".into(),
width: w,
height: h,
data: synth_heightmap(w, h),
sea_level: 0.40,
};
// Warm-up + output characterization.
let o = run_layer1(&hm);
let mut by_type: std::collections::BTreeMap<String, usize> = std::collections::BTreeMap::new();
for a in &o.attractors {
*by_type.entry(format!("{:?}", a.attractor_type)).or_default() += 1;
}
println!("=== Layer-1 output for one 512×256 body ===");
println!(
" river cells: {} mouths: {} confluences: {} basins: {}",
o.river_network.river_cells.len(),
o.river_network.mouths.len(),
o.river_network.confluences.len(),
o.drainage_basins.len(),
);
println!(" attractors: {} {:?}", o.attractors.len(), by_type);
// Phase breakdown (median of N) to locate the cost.
use settled_reach_server::atlas::drainage;
use settled_reach_server::atlas::features::{extract_attractors, TerrainAnalysis};
let n = 30;
let med = |mut v: Vec<f64>| {
v.sort_by(|a, b| a.partial_cmp(b).unwrap());
v[v.len() / 2]
};
let mut t_drain = vec![];
let mut t_terr = vec![];
let mut t_feat = vec![];
let mut t_total = vec![];
for _ in 0..n {
let t = Instant::now();
let dr = drainage::analyze(&hm.data, hm.width, hm.height, hm.sea_level);
t_drain.push(t.elapsed().as_secs_f64() * 1000.0);
let t = Instant::now();
let ta = TerrainAnalysis::analyze(&hm, &dr);
t_terr.push(t.elapsed().as_secs_f64() * 1000.0);
let t = Instant::now();
let raw = extract_attractors(&hm, &dr, &ta);
t_feat.push(t.elapsed().as_secs_f64() * 1000.0);
std::hint::black_box(&raw);
let t = Instant::now();
let out = run_layer1(&hm);
std::hint::black_box(&out);
t_total.push(t.elapsed().as_secs_f64() * 1000.0);
}
println!("\n=== phase breakdown (median of {n}, 512×256, release) ===");
println!(" D8 drainage (D-208): {:.2}ms", med(t_drain));
println!(" terrain analysis: {:.2}ms", med(t_terr));
println!(" feature extraction: {:.2}ms", med(t_feat));
println!(" run_layer1 (total): {:.2}ms", med(t_total));
println!(" D-208 target: ~50ms/body");
}