Skip to main content

scx_pandemonium/cli/
probe.rs

1use std::sync::atomic::{AtomicBool, Ordering};
2
3static RUNNING: AtomicBool = AtomicBool::new(true);
4
5// PRE-ALLOCATED SAMPLE BUFFER -- NO I/O DURING MEASUREMENT
6const MAX_SAMPLES: usize = 16384;
7
8/// Interactive wakeup probe.
9/// When PANDEMONIUM is running, BPF records latencies to ring buffer.
10/// For EEVDF baseline, we measure in userspace.
11/// Either way: ZERO I/O during measurement, bulk output at end.
12pub fn run_probe(death_pipe_fd: Option<i32>) {
13    ctrlc::set_handler(move || {
14        RUNNING.store(false, Ordering::Relaxed);
15    })
16    .ok();
17
18    if let Some(fd) = death_pipe_fd {
19        super::death_pipe::spawn_death_watcher(fd, &RUNNING);
20    }
21
22    let mut samples: Vec<i64> = Vec::with_capacity(MAX_SAMPLES);
23
24    let target_ns: i64 = 10_000_000; // 10MS SLEEP TARGET
25    let req = libc::timespec {
26        tv_sec: 0,
27        tv_nsec: target_ns,
28    };
29
30    // HOT LOOP: MEASURE + BUFFER. ZERO I/O.
31    while RUNNING.load(Ordering::Relaxed) && samples.len() < MAX_SAMPLES {
32        let mut t0 = libc::timespec {
33            tv_sec: 0,
34            tv_nsec: 0,
35        };
36        let mut t1 = libc::timespec {
37            tv_sec: 0,
38            tv_nsec: 0,
39        };
40        unsafe {
41            libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut t0);
42            libc::nanosleep(&req, std::ptr::null_mut());
43            libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut t1);
44        }
45        let elapsed_ns = (t1.tv_sec - t0.tv_sec) * 1_000_000_000 + (t1.tv_nsec - t0.tv_nsec);
46        let overshoot_us = (elapsed_ns - target_ns).max(0) / 1000;
47        samples.push(overshoot_us);
48    }
49
50    // BULK OUTPUT AT END -- USE write() DIRECTLY TO MINIMIZE OVERHEAD
51    use std::io::Write;
52    let stdout = std::io::stdout();
53    let mut handle = stdout.lock();
54    for s in &samples {
55        let _ = writeln!(handle, "{}", s);
56    }
57}