//! The frozen path of the whole process-counter chain — probe, status, cache, //! selection, metering — on any host. The counter is live on the Macs that run //! these tests, so `simulate_frozen_process_energy()` makes this process's //! counter hold at its first value before the meter's first use, as a frozen //! counter would. This file holds this one test so that it runs in a process //! of its own and the hook cannot reach any other test. //! //! A selection that ignored the counter's liveness — choosing it because it //! reads, not because it keeps advancing — fails here. use proof_cascade::meter::{ ioreport_status, measure_marginal, meter_source, process_energy_status, real_process_probe_runs, simulate_frozen_process_energy, CounterStatus, IoReportStatus, MeterSource, }; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Barrier}; /// How many times [`counted_work`] has run in this process. static WORK_CALLS: AtomicU64 = AtomicU64::new(0); fn counted_work() { WORK_CALLS.fetch_add(1, Ordering::SeqCst); std::hint::black_box((0..4000u64).fold(0u64, |a, b| a.wrapping_mul(31).wrapping_add(b))); } /// With the counter holding, the status is `Frozen` for every thread that /// asks, the counter is never selected and never meters, and its probe ran /// exactly once. Whatever IOReport does is IOReport's own: selected only when /// its CPU rail is live, and then its figure says so; otherwise there is no /// figure and the work never runs. #[test] fn a_frozen_process_counter_is_never_selected_and_never_meters() { assert_eq!(real_process_probe_runs(), 0, "the meter was used in this process before this test"); simulate_frozen_process_energy(); const THREADS: usize = 4; let gate = Arc::new(Barrier::new(THREADS)); let handles: Vec<_> = (0..THREADS) .map(|_| { let gate = gate.clone(); std::thread::spawn(move || { gate.wait(); let status = process_energy_status(); let source = meter_source(); (status, source) }) }) .collect(); let seen: Vec<_> = handles.into_iter().map(|h| h.join().expect("a thread panicked")).collect(); let runs = real_process_probe_runs(); let ioreport = ioreport_status(); let figure = measure_marginal(counted_work); let work = WORK_CALLS.load(Ordering::SeqCst); eprintln!( "process frozen: {THREADS} threads saw {seen:?}; probe runs {runs}; ioreport={ioreport:?}; figure={figure:?}; \ work calls {work}" ); let want_source = (ioreport == IoReportStatus::Live).then_some(MeterSource::IoReport); for (i, (status, source)) in seen.iter().enumerate() { if cfg!(target_os = "macos") { assert_eq!(*status, CounterStatus::Frozen, "thread {i}: a held counter was called {status:?}"); assert_eq!(*source, want_source, "thread {i}: a held process counter was selected, or IOReport mis-ranked"); } else { assert_eq!(*status, CounterStatus::Unavailable, "thread {i}: a process counter off macOS"); assert_ne!(*source, Some(MeterSource::ProcessEnergy)); } } assert_ne!(figure.map(|m| m.source), Some(MeterSource::ProcessEnergy), "a held process counter metered"); if cfg!(target_os = "macos") { assert_eq!(runs, 1, "the process-counter probe's runs in this process"); match want_source { Some(src) => assert_eq!(figure.map(|m| m.source), Some(src), "IOReport was live, yet: {figure:?}"), None => { assert_eq!(figure, None, "no live source, yet a figure"); assert_eq!(work, 0, "the work ran {work} times with no live source"); } } } else { assert_eq!(runs, 0, "a process-counter probe ran off macOS"); } }