1use serde::{Deserialize, Serialize};
7use silicera::hardware::HardwareInfo;
8use silicera::measure::{MeasurementConfig, MeasurementEngine, Stability};
9use silicera::Result;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct CalmCheckReport {
14 pub host_brand: String,
16 pub fingerprint: Option<String>,
18 pub pass_a: String,
20 pub pass_b: String,
22 pub median_a_ns: f64,
24 pub median_b_ns: f64,
26 pub relative_drift: f64,
28 pub calm: bool,
30 pub recommendation: String,
32}
33
34pub fn run_calm_check(info: &HardwareInfo, iterations: usize) -> Result<CalmCheckReport> {
36 let eng = MeasurementEngine::new(MeasurementConfig {
37 warmup: 5,
38 iterations: iterations.max(20),
39 ..Default::default()
40 });
41 let a = eng.measure(|| {
42 let mut x = 1u64;
43 for i in 0..50_000u64 {
44 x = x.wrapping_mul(1664525).wrapping_add(1013904223).wrapping_add(i);
45 }
46 std::hint::black_box(x);
47 })?;
48 std::thread::sleep(std::time::Duration::from_millis(50));
50 let b = eng.measure(|| {
51 let mut x = 1u64;
52 for i in 0..50_000u64 {
53 x = x.wrapping_mul(1664525).wrapping_add(1013904223).wrapping_add(i);
54 }
55 std::hint::black_box(x);
56 })?;
57 let denom = a.median_ns.max(b.median_ns).max(1.0);
58 let relative_drift = (a.median_ns - b.median_ns).abs() / denom;
59 let calm = a.stability != Stability::Unstable
60 && b.stability != Stability::Unstable
61 && relative_drift < 0.15;
62 let recommendation = if calm {
63 "Host looks calm enough for specialization under this soft probe.".into()
64 } else {
65 "MEASUREMENT ENVIRONMENT MAY BE NOISY — close background load, re-run calm-check, \
66 then retrain. Do not trust razor-thin specialization margins."
67 .into()
68 };
69 Ok(CalmCheckReport {
70 host_brand: info.brand.clone(),
71 fingerprint: info.fingerprint.as_ref().map(|f| f.value.clone()),
72 pass_a: a.stability.label().into(),
73 pass_b: b.stability.label().into(),
74 median_a_ns: a.median_ns,
75 median_b_ns: b.median_ns,
76 relative_drift,
77 calm,
78 recommendation,
79 })
80}