diff --git a/ROADMAP.md b/ROADMAP.md index e09746d..d4976f0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -32,6 +32,7 @@ luxpath's one-page summary. Details live in: | Date | Change | |---|---| +| 2026-10-25 | The performance budgets hold on CI: GitHub's Linux runners took 53 to 101 ms for M2's 100 ms case (55 ms on a developer's machine) and failed it at random, so under `CI` each budget is doubled; `cargo xtask ci` prints the timings even when they pass. | | 2026-10-25 | Findings per requirement: `luxpath check` lists every EN 1838:2024 requirement on every route, area and point with its clause (`luxpath_rules::en1838`), each "cannot verify" until its value is verified (gap 4); scenes gain the area kinds 2024 added (`toilets`, `swimming-pool`, `plant-room`, `local-area`). | | 2026-10-25 | EN 1838:2024 clause map: `docs/standards-parity.md` cites the 2024 clause of every requirement, from the table of contents in the free SIST preview (values stay unverified, gap 4), and lists what 2024 added: specific areas (5.4), safety signs (6), local area and standby lighting (7), the annexes. New parity entries `en1838.specific-areas`, `en1838.local-area`, `en1838.safety-signs`. | | 2026-10-22 | Public: the repository opened after a licence check; vulnerability reporting, topics, protected `main` with hosted CI on Linux, macOS and Windows (its first Windows run found a line-ending bug in a test, fixed). | diff --git a/crates/calc/tests/performance.rs b/crates/calc/tests/performance.rs index a79ad93..39264b1 100644 --- a/crates/calc/tests/performance.rs +++ b/crates/calc/tests/performance.rs @@ -1,6 +1,10 @@ //! M2's performance budget: 100 luminaires × 10,000 points in under 100 ms, with a realistic table //! (C every 5°, γ every 1°). Timing means something only in release builds, so this test is //! ignored by default and `cargo xtask ci` runs it with `--release -- --ignored`. +//! +//! The budgets are for a developer's machine (about 55 ms there). Shared CI machines vary from run to run, from as +//! fast to about twice as slow (53 to 101 ms on GitHub's Linux runners, which failed a fixed 100 ms at random), so +//! under CI each budget is doubled ([`CI_FACTOR`]): a real slowdown of twice or more still fails there. #![allow(clippy::unwrap_used)] @@ -31,6 +35,15 @@ fn scene() -> (Vec, Grid) { (luminaires, grid) } +/// How much slower than a developer's machine a shared CI machine may be. +const CI_FACTOR: u32 = 2; + +/// `ms` on a developer's machine; [`CI_FACTOR`] times that where the `CI` variable is set (GitHub Actions sets it). +fn budget(ms: u64) -> Duration { + let ci = std::env::var_os("CI").is_some_and(|v| !v.is_empty() && v != "false"); + Duration::from_millis(ms) * if ci { CI_FACTOR } else { 1 } +} + /// The best of five runs of `f`. fn best_of_five(f: impl Fn() -> Vec>) -> Duration { let mut best = Duration::MAX; @@ -49,7 +62,8 @@ fn a_hundred_luminaires_over_ten_thousand_points_within_budget() { let (luminaires, grid) = scene(); let best = best_of_five(|| illuminance(&luminaires, &grid)); eprintln!("100 luminaires × 10,000 points: {best:?} (best of 5)"); - assert!(best < Duration::from_millis(100), "{best:?} is over the 100 ms budget"); + let limit = budget(100); + assert!(best < limit, "{best:?} is over the {limit:?} budget"); } #[test] @@ -77,5 +91,6 @@ fn walls_stay_within_budget() { } let best = best_of_five(|| illuminance_with_walls(&luminaires, &walls, &grid)); eprintln!("100 luminaires × 10,000 points × {} walls: {best:?} (best of 5)", walls.len()); - assert!(best < Duration::from_millis(500), "{best:?} is over the 500 ms budget"); + let limit = budget(500); + assert!(best < limit, "{best:?} is over the {limit:?} budget"); } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 96b944c..4198adf 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -45,7 +45,8 @@ fn ci() -> Result<(), String> { cargo(&["clippy", "--workspace", "--all-targets", "--", "-D", "warnings"])?; cargo(&["test", "--workspace"])?; // M2's budget: timing is meaningful only in release. - cargo(&["test", "--release", "-p", "luxpath-calc", "--test", "performance", "--", "--ignored"])?; + // `--nocapture` prints the timings even when they pass, so a budget nearly reached shows in every log. + cargo(&["test", "--release", "-p", "luxpath-calc", "--test", "performance", "--", "--ignored", "--nocapture"])?; if wasm_target_installed() { let mut args = vec!["check", "--target", "wasm32-unknown-unknown"]; for krate in WASM_CRATES {