metrale_bench/gate/
record_env.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-26: What a gate record discloses about the environment its server
4//! ran under: the performance controls with their defaults filled in
5//! (`perf_env`) and the `METRALE_*` levers the gate applied (`serve_env`).
6//!
7//! Owner: bench gate (records).
8//! Invariants:
9//! - [`resolve_perf_env`] returns every `PERF_CONTROLS` key.
10
11use std::collections::BTreeMap;
12
13use super::record::GateRecord;
14
15/// 2026-09-26: The performance controls a gate record discloses, each with
16/// the value recorded when it is unset.
17///
18/// - The two co-dispatch timing controls carry the defaults the scheduler
19///   passes to `num` in `SchedLevers::from_env`. They are copied because
20///   `metrale-bench` does not depend on `metrale-server`;
21///   `perf_env_defaults_match_the_scheduler` reads the scheduler's source.
22/// - `METRALE_NO_W4A16_TC`, `METRALE_NO_MTP_TC` and
23///   `METRALE_NO_BORROW_STREAK_LIMIT` are presence kill switches: any
24///   non-empty value, `0` included, turns the path off, so the default is the
25///   literal `unset`, under which the path ran.
26/// - `METRALE_W4A16_TC_WIDE` is a presence opt-in that raises
27///   `narrow_gemv_max_rows` to `WIDE_MAX_ROWS`, so `unset` means it did not
28///   run.
29///
30/// `record_env_tests` pins each switch rule against its lever's source. The
31/// `--prefill-codispatch` and `--w4a4-downcast` flags are disclosed in
32/// `serve_resolved` instead.
33const PERF_CONTROLS: [(&str, &str); 6] = [
34    ("METRALE_PREFILL_CODISPATCH_WINDOW_MS", "100"),
35    ("METRALE_PREFILL_CODISPATCH_SETTLE_MS", "10"),
36    ("METRALE_NO_W4A16_TC", "unset"),
37    ("METRALE_W4A16_TC_WIDE", "unset"),
38    ("METRALE_NO_MTP_TC", "unset"),
39    ("METRALE_NO_BORROW_STREAK_LIMIT", "unset"),
40];
41
42/// 2026-09-26: Resolve `PERF_CONTROLS` through `lookup`, substituting each
43/// default for an unset, empty or whitespace-only value. Takes `lookup` so
44/// tests need not set process environment variables.
45pub fn resolve_perf_env(lookup: impl Fn(&str) -> Option<String>) -> BTreeMap<String, String> {
46    PERF_CONTROLS
47        .iter()
48        .map(|(key, default)| {
49            let value = lookup(key).filter(|v| !v.trim().is_empty());
50            (
51                (*key).to_string(),
52                value.unwrap_or_else(|| (*default).to_string()),
53            )
54        })
55        .collect()
56}
57
58impl GateRecord {
59    /// 2026-09-26: Attach the `METRALE_*` levers the gate applied to its
60    /// server (`serve_env::Reconciled::env`) and re-resolve `perf_env` with
61    /// the applied set first and this process's environment second. A leased
62    /// server is a child given the declared levers this process lacks, so
63    /// this process's environment alone can miss a value the server had.
64    #[must_use]
65    pub fn with_serve_env(mut self, env: BTreeMap<String, String>) -> Self {
66        self.perf_env = resolve_perf_env(|k| env.get(k).cloned().or_else(|| std::env::var(k).ok()));
67        self.serve_env = env;
68        self
69    }
70}
71
72#[cfg(test)]
73#[path = "record_env_tests.rs"]
74mod tests;