facett-map3d-flight/benches/heavy_daycycle.rs
//! **HEAVY day-cycle benchmark** — the time-of-day sun/sky driver evaluated at full
//! rate over a dense hour + season sweep (the Bencher LAW: bench the PARTS, then the
//! rollup). Each `sun_sky` call reuses the landed `Atmosphere` transmittance LUT, so
//! this measures the per-frame cost of animating the whole sky.
//!
//! Steps benched, each with an evaluations/sec throughput:
//! - `solar_angles` — the astronomy (declination + hour angle → elevation/azimuth)
//! - `sun_dir` — angles → unit surface→sun direction
//! - `sun_sky_clear` — the FULL SunSky (sun colour/intensity + atmosphere sky tint)
//! - `sun_sky_overcast` — the same with the overcast weather blend on top
//!
//! Sweep size is `MAP3D_FLIGHT_DAYCYCLE_N` (default 100000 queries). Run:
//! CARGO_TARGET_DIR=/mnt/work4t/cargo-target/facett-map3d-flight \
//! cargo bench -p facett-map3d-flight --bench heavy_daycycle
use std::hint::black_box;
use criterion::{Criterion, Throughput, criterion_group, criterion_main};
use facett_map3d_flight::daycycle::{DayCycle, Weather, solar_angles, sun_dir};
use facett_map3d_flight::Atmosphere;
fn sweep_n() -> usize {
std::env::var("MAP3D_FLIGHT_DAYCYCLE_N").ok().and_then(|v| v.parse().ok()).unwrap_or(100_000)
}
/// A deterministic `(latitude, day_of_year, hour)` query cloud over the year + globe.
fn queries(n: usize) -> Vec<(f32, u32, f32)> {
(0..n)
.map(|i| {
let f = i as f32 / n as f32;
let lat = -60.0 + 120.0 * ((i * 2654435761usize) % 1000) as f32 / 1000.0;
let doy = ((i * 40503) % 365) as u32;
let hour = 24.0 * f;
(lat, doy, hour)
})
.collect()
}
fn bench_daycycle(c: &mut Criterion) {
let n = sweep_n();
let q = queries(n);
let atmos = Atmosphere::earth();
{
let mut g = c.benchmark_group("solar_angles");
g.throughput(Throughput::Elements(n as u64));
g.bench_function("astronomy", |b| {
b.iter(|| {
let mut acc = 0.0f32;
for &(lat, doy, hour) in black_box(&q) {
acc += solar_angles(lat, doy, hour).elevation_rad;
}
black_box(acc)
});
});
g.finish();
}
{
let mut g = c.benchmark_group("sun_dir");
g.throughput(Throughput::Elements(n as u64));
g.bench_function("dir", |b| {
b.iter(|| {
let mut acc = 0.0f32;
for &(lat, doy, hour) in black_box(&q) {
acc += sun_dir(solar_angles(lat, doy, hour))[1];
}
black_box(acc)
});
});
g.finish();
}
for (label, weather) in [("sun_sky_clear", Weather::clear()), ("sun_sky_overcast", Weather::overcast())] {
let mut g = c.benchmark_group(label);
g.throughput(Throughput::Elements(n as u64));
g.bench_function("full", |b| {
b.iter(|| {
let mut acc = 0.0f32;
for &(lat, doy, hour) in black_box(&q) {
let dc = DayCycle { latitude_deg: lat, day_of_year: doy, weather, exposure: 12.0 };
let (s, _) = dc.sun_sky(hour, black_box(&atmos), 1500.0);
acc += s.sun_intensity + s.sky_color[2];
}
black_box(acc)
});
});
g.finish();
}
eprintln!("[heavy_daycycle] {n} time-of-day queries per iteration (lat × season × hour sweep)");
}
criterion_group!(benches, bench_daycycle);
criterion_main!(benches);