ggen_dod/
timing.rs

1//! Timing system: Enforces Chatman Constant (τ ≤ 8ms) guarantees
2//!
3//! All hot paths that declare τ constraints are verified to stay within bounds.
4//! Violations are fatal and prevent execution.
5
6use crate::error::DoDResult;
7use serde::{Deserialize, Serialize};
8// Removed unused imports: Duration, Instant
9
10/// Timing measurement for a kernel operation
11#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
12pub struct TimingMeasurement {
13    /// When measurement started
14    start_time: Option<std::time::SystemTime>,
15    /// When measurement ended
16    end_time: Option<std::time::SystemTime>,
17    /// Elapsed milliseconds
18    elapsed_ms: u64,
19}
20
21impl TimingMeasurement {
22    /// Create a new timing measurement (started now)
23    pub fn new() -> Self {
24        Self {
25            start_time: Some(std::time::SystemTime::now()),
26            end_time: None,
27            elapsed_ms: 0,
28        }
29    }
30
31    /// Mark measurement as finished with elapsed time
32    pub fn finished(mut self, elapsed_ms: u64) -> Self {
33        self.elapsed_ms = elapsed_ms;
34        self.end_time = Some(std::time::SystemTime::now());
35        self
36    }
37
38    /// Get elapsed time in milliseconds
39    pub fn elapsed_ms(&self) -> u64 {
40        self.elapsed_ms
41    }
42
43    /// Check if within timing constraint
44    pub fn within_constraint(&self, max_ms: u64) -> bool {
45        self.elapsed_ms <= max_ms
46    }
47}
48
49impl Default for TimingMeasurement {
50    fn default() -> Self {
51        Self::new()
52    }
53}
54
55/// A timing guarantee (τ ≤ X ms)
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
57pub struct TimingGuarantee {
58    /// Maximum time in milliseconds
59    max_ms: u64,
60    /// Whether this constraint is enforced strictly
61    strict: bool,
62}
63
64impl TimingGuarantee {
65    /// Create a new timing guarantee
66    pub fn new(max_ms: u64) -> Self {
67        Self {
68            max_ms,
69            strict: true,
70        }
71    }
72
73    /// Create a soft constraint (warning, not error)
74    pub fn soft(max_ms: u64) -> Self {
75        Self {
76            max_ms,
77            strict: false,
78        }
79    }
80
81    /// Get maximum time in milliseconds
82    pub fn max_ms(&self) -> u64 {
83        self.max_ms
84    }
85
86    /// Is this a strict constraint?
87    pub fn is_strict(&self) -> bool {
88        self.strict
89    }
90
91    /// Check if measurement violates this guarantee
92    pub fn check(&self, measurement: &TimingMeasurement) -> DoDResult<()> {
93        if measurement.elapsed_ms > self.max_ms {
94            if self.strict {
95                return Err(crate::error::DoDError::TimingViolation {
96                    expected: self.max_ms,
97                    actual: measurement.elapsed_ms,
98                });
99            }
100        }
101        Ok(())
102    }
103}
104
105/// The Chatman Constant: τ ≤ 8 milliseconds
106pub const CHATMAN_CONSTANT_MS: u64 = 8;
107
108/// Kernel timing constraint (strict)
109pub fn kernel_timing_constraint() -> TimingGuarantee {
110    TimingGuarantee::new(CHATMAN_CONSTANT_MS)
111}
112
113/// Decision closure check constraint (tighter)
114pub fn decision_closure_timing() -> TimingGuarantee {
115    TimingGuarantee::new(2)
116}
117
118/// Schema validation timing (moderate)
119pub fn schema_validation_timing() -> TimingGuarantee {
120    TimingGuarantee::soft(5)
121}
122
123/// Timing enforcer for execution
124#[derive(Clone)]
125pub struct TimingEnforcer {
126    /// Constraints being enforced
127    constraints: Vec<(String, TimingGuarantee)>,
128    /// Measurements collected
129    measurements: Vec<(String, TimingMeasurement)>,
130}
131
132impl TimingEnforcer {
133    /// Create a new timing enforcer
134    pub fn new() -> Self {
135        Self {
136            constraints: Vec::new(),
137            measurements: Vec::new(),
138        }
139    }
140
141    /// Register a timing constraint
142    pub fn with_constraint(mut self, name: impl Into<String>, constraint: TimingGuarantee) -> Self {
143        self.constraints.push((name.into(), constraint));
144        self
145    }
146
147    /// Register a measurement
148    pub fn record_measurement(
149        mut self, name: impl Into<String>, measurement: TimingMeasurement,
150    ) -> Self {
151        self.measurements.push((name.into(), measurement));
152        self
153    }
154
155    /// Check all measurements against constraints
156    pub fn verify(&self) -> DoDResult<()> {
157        for (_name, measurement) in &self.measurements {
158            for (_constraint_name, constraint) in &self.constraints {
159                constraint.check(measurement)?;
160            }
161        }
162        Ok(())
163    }
164
165    /// Get all measurements
166    pub fn measurements(&self) -> &[(String, TimingMeasurement)] {
167        &self.measurements
168    }
169
170    /// Compute statistics
171    pub fn stats(&self) -> TimingStats {
172        if self.measurements.is_empty() {
173            return TimingStats::default();
174        }
175
176        let times: Vec<u64> = self
177            .measurements
178            .iter()
179            .map(|(_, m)| m.elapsed_ms)
180            .collect();
181        let sum: u64 = times.iter().sum();
182        let count = times.len() as u64;
183        let mean = sum / count;
184
185        let mut sorted = times.clone();
186        sorted.sort_unstable();
187        let median = sorted[sorted.len() / 2];
188        let min = *sorted.first().unwrap_or(&0);
189        let max = *sorted.last().unwrap_or(&0);
190
191        // Calculate standard deviation
192        let variance: u64 = times
193            .iter()
194            .map(|t| {
195                let diff = if *t > mean { *t - mean } else { mean - *t };
196                diff * diff
197            })
198            .sum::<u64>()
199            / count;
200        let stddev = (variance as f64).sqrt() as u64;
201
202        TimingStats {
203            count: count as usize,
204            min,
205            max,
206            mean,
207            median,
208            stddev,
209            p99: sorted[(sorted.len() * 99) / 100],
210        }
211    }
212}
213
214impl Default for TimingEnforcer {
215    fn default() -> Self {
216        Self::new()
217    }
218}
219
220/// Timing statistics
221#[derive(Debug, Clone, Default, Serialize, Deserialize)]
222pub struct TimingStats {
223    /// Number of measurements
224    pub count: usize,
225    /// Minimum time in ms
226    pub min: u64,
227    /// Maximum time in ms
228    pub max: u64,
229    /// Mean time in ms
230    pub mean: u64,
231    /// Median time in ms
232    pub median: u64,
233    /// Standard deviation in ms
234    pub stddev: u64,
235    /// 99th percentile in ms
236    pub p99: u64,
237}
238
239impl TimingStats {
240    /// Is this within the Chatman Constant?
241    pub fn within_chatman_constant(&self) -> bool {
242        self.p99 <= CHATMAN_CONSTANT_MS
243    }
244
245    /// Confidence interval (95%)
246    pub fn confidence_interval_95(&self) -> (u64, u64) {
247        let margin = (1.96 * self.stddev as f64) as u64;
248        let lower = self.mean.saturating_sub(margin);
249        let upper = self.mean + margin;
250        (lower, upper)
251    }
252}
253
254#[cfg(test)]
255mod tests {
256    use super::*;
257
258    #[test]
259    fn test_timing_measurement() {
260        let measurement = TimingMeasurement::new().finished(5);
261        assert_eq!(measurement.elapsed_ms(), 5);
262    }
263
264    #[test]
265    fn test_timing_guarantee_check() -> DoDResult<()> {
266        let guarantee = TimingGuarantee::new(10);
267        let measurement = TimingMeasurement::new().finished(8);
268        guarantee.check(&measurement)?;
269        Ok(())
270    }
271
272    #[test]
273    fn test_timing_violation() {
274        let guarantee = TimingGuarantee::new(5);
275        let measurement = TimingMeasurement::new().finished(10);
276        assert!(guarantee.check(&measurement).is_err());
277    }
278
279    #[test]
280    fn test_chatman_constant() {
281        assert_eq!(CHATMAN_CONSTANT_MS, 8);
282    }
283
284    #[test]
285    fn test_timing_enforcer() -> DoDResult<()> {
286        let enforcer = TimingEnforcer::new()
287            .with_constraint("kernel", kernel_timing_constraint())
288            .record_measurement("test", TimingMeasurement::new().finished(5));
289
290        enforcer.verify()?;
291        Ok(())
292    }
293
294    #[test]
295    fn test_timing_stats() {
296        let enforcer = TimingEnforcer::new()
297            .record_measurement("m1", TimingMeasurement::new().finished(5))
298            .record_measurement("m2", TimingMeasurement::new().finished(10))
299            .record_measurement("m3", TimingMeasurement::new().finished(7));
300
301        let stats = enforcer.stats();
302        assert_eq!(stats.count, 3);
303        assert_eq!(stats.min, 5);
304        assert_eq!(stats.max, 10);
305    }
306}