jcp-energy: the RAPL probe tests advance their fake zones on the probe's own tick #272

Merged
dcharlot merged 1 commit from fix/rapl-probe-test-starvation into main 2026-10-16 04:39:57 -04:00

View file

@ -7368,39 +7368,53 @@ mod tests {
}
}
/// RAPL's probe — its opener on `tree`, its sampler, the CPU-burning tick,
/// the real clock, one budget — with `advance` run after each tick: the
/// fake hardware's rise for that interval. These tests once advanced the
/// zones from another thread on a 2 ms timer instead, which a loaded CI
/// host starved while the tick burned CPU: intervals went flat, and two
/// live packages read Frozen. On the probe's own thread the rise lands in
/// every interval, so the verdict is the rule's, not the scheduler's.
fn rapl_status_ticking(tree: &FakePowercap, mut advance: impl FnMut()) -> CounterStatus {
crate::liveness::status_of(
crate::liveness::probe(
|| Rapl::open_in(&tree.root),
Rapl::liveness_sample,
|| {
crate::liveness::burn_tick();
advance();
},
std::time::Instant::now,
crate::liveness::BUDGET,
)
.as_ref(),
)
}
/// The real RAPL probe — the real reader on files, the CPU-burning tick,
/// the real clock, one budget — on fake powercap trees. A tree whose
/// counters hold is Frozen; one whose two packages another thread
/// advances every 2 ms is Live; one where that thread advances package 0
/// alone, package 1 holding, is Frozen; no tree, or a tree whose
/// `energy_uj` is not a number, is Unavailable, as RAPL was declined
/// before.
/// counters hold is Frozen; one whose two packages advance 4 mJ every tick
/// is Live; one where package 0 advances alone, package 1 holding, is
/// Frozen; no tree, or a tree whose `energy_uj` is not a number, is
/// Unavailable, as RAPL was declined before.
#[test]
fn the_rapl_probe_on_fake_powercap_trees() {
/// The real probe on `tree` while another thread advances the
/// packages in `advancing` by 4 mJ every 2 ms.
/// The probe on `tree`, the packages in `advancing` rising by 4 mJ at
/// every tick ([`rapl_status_ticking`]).
fn probe_while_advancing(tree: &FakePowercap, advancing: &[usize]) -> CounterStatus {
let stop = std::sync::atomic::AtomicBool::new(false);
std::thread::scope(|s| {
s.spawn(|| {
let mut uj: u64 = 1_000;
while !stop.load(std::sync::atomic::Ordering::SeqCst) {
uj += 4_000;
for &k in advancing {
tree.write(k, &uj.to_string());
}
std::thread::sleep(Duration::from_millis(2));
}
});
let started = std::time::Instant::now();
let status = rapl_status_on(|| Rapl::open_in(&tree.root));
eprintln!(
"rapl probe: a fake tree with packages {advancing:?} advancing every 2 ms -> {status:?} in {:?}",
started.elapsed()
);
stop.store(true, std::sync::atomic::Ordering::SeqCst);
status
})
let mut uj: u64 = 1_000;
let started = std::time::Instant::now();
let status = rapl_status_ticking(tree, || {
uj += 4_000;
for &k in advancing {
tree.write(k, &uj.to_string());
}
});
eprintln!(
"rapl probe: a fake tree with packages {advancing:?} advancing every tick -> {status:?} in {:?}",
started.elapsed()
);
status
}
#[cfg(target_os = "macos")]
let _hw = ioreport_hw_lock();
@ -8734,7 +8748,8 @@ mod tests {
/// alone, although every other zone rose too; a package wrapping at its own
/// range is corrected at that range. And the real probe is Live while the
/// two packages advance with `psys` and `dram` holding, Frozen while
/// `psys`, `dram` and one package advance with the other package holding.
/// `psys`, `dram` and one package advance with the other package holding
/// (each advancing at every tick of the probe, [`rapl_status_ticking`]).
#[test]
fn rapl_sums_and_probes_the_package_zones_only() {
#[cfg(target_os = "macos")]
@ -8778,26 +8793,18 @@ mod tests {
assert_eq!((e.provenance, e.measured_uj), (Provenance::HwShunt, Some(12_487)), "{e:?}");
drop(meter);
/// The real probe on `tree` while another thread advances the zones
/// in `advancing` by 4 mJ every 2 ms.
/// The probe on `tree`, the zones in `advancing` rising by 4 mJ at
/// every tick ([`rapl_status_ticking`]).
fn probe_advancing(tree: &FakePowercap, advancing: &[&str]) -> CounterStatus {
let stop = std::sync::atomic::AtomicBool::new(false);
std::thread::scope(|s| {
s.spawn(|| {
let mut uj: u64 = 100_000;
while !stop.load(std::sync::atomic::Ordering::SeqCst) {
uj += 4_000;
for dir in advancing {
tree.write_zone(dir, &uj.to_string());
}
std::thread::sleep(Duration::from_millis(2));
}
});
let status = rapl_status_on(|| Rapl::open_in(&tree.root));
eprintln!("rapl probe: zones {advancing:?} advancing, the rest holding -> {status:?}");
stop.store(true, std::sync::atomic::Ordering::SeqCst);
status
})
let mut uj: u64 = 100_000;
let status = rapl_status_ticking(tree, || {
uj += 4_000;
for dir in advancing {
tree.write_zone(dir, &uj.to_string());
}
});
eprintln!("rapl probe: zones {advancing:?} advancing, the rest holding -> {status:?}");
status
}
let tree = two_sockets_with_psys_and_dram();
assert_eq!(