Skip to main content

rac_engine/
timing.rs

1//! Opt-in, stderr-only phase timing for performance diagnosis.
2//!
3//! `DECIDED_TIMING` is deliberately outside every output/parity contract. When it
4//! is unset these helpers do not read clocks and emit nothing. Timing lines do
5//! not contain paths, queries, identifiers, or document content.
6
7use std::time::{Duration, Instant};
8
9pub const ENV: &str = "DECIDED_TIMING";
10
11pub fn enabled() -> bool {
12    std::env::var_os(ENV).is_some()
13}
14
15/// Start an operation without touching the monotonic clock when timing is off.
16pub fn start() -> Option<Instant> {
17    enabled().then(Instant::now)
18}
19
20/// Emit one stable operation record. Counter names and order are caller-owned
21/// constants; values are numeric so no corpus or query material can leak.
22pub fn emit(operation: &'static str, duration: Duration, counters: &[(&'static str, u64)]) {
23    if !enabled() {
24        return;
25    }
26    eprint!(
27        "decided-timing: op={operation} duration_ms={:.3}",
28        duration.as_secs_f64() * 1000.0
29    );
30    for (name, value) in counters {
31        eprint!(" {name}={value}");
32    }
33    eprintln!();
34}
35
36pub fn emit_since(
37    operation: &'static str,
38    started: Option<Instant>,
39    counters: &[(&'static str, u64)],
40) {
41    if let Some(started) = started {
42        emit(operation, started.elapsed(), counters);
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn duration_conversion_is_fractional_milliseconds() {
52        let duration = Duration::from_micros(1_234);
53        assert_eq!(duration.as_secs_f64() * 1000.0, 1.234);
54    }
55}