proof-cascade: the raw-reader pin counts the subscriptions it hands the reader (a laptop registers IOReport channels as it runs) #543

Merged
dcharlot merged 1 commit from proof/ioreport-same-subscription into main 2026-10-29 21:09:22 -04:00

View file

@ -3800,47 +3800,59 @@ mod macos_ioreport {
/// cumulative values of the CPU and GPU energy channels, in channel
/// order.
fn read(&self) -> Option<OracleRead> {
unsafe {
let smp = IOReportCreateSamples(self.sub, self.ch, std::ptr::null());
if smp.is_null() {
return None;
}
let key = CFStringCreateWithCString(
std::ptr::null_mut(),
c"IOReportChannels".as_ptr() as *const _,
K_CFSTRING_ENCODING_UTF8,
);
let mut read = OracleRead { group: Group { energy_model: 0, all: 0 }, cpu: Vec::new(), gpu: Vec::new() };
if !key.is_null() {
let arr = CFDictionaryGetValue(smp, key as *const _) as CFArrayRef;
CFRelease(key as CFTypeRef);
if !arr.is_null() {
for i in 0..CFArrayGetCount(arr) {
let it = CFArrayGetValueAtIndex(arr, i);
if it.is_null() {
continue;
}
read.group.all += 1;
let group = cfstring_to_string(IOReportChannelGetGroup(it)).unwrap_or_default();
let name = cfstring_to_string(IOReportChannelGetChannelName(it)).unwrap_or_default();
let em = group.eq_ignore_ascii_case("Energy Model");
read.group.energy_model += usize::from(em);
let rail = |group: String, name: String| OracleRail {
group,
name,
value: IOReportSimpleGetIntegerValue(it, 0) as i64,
};
if name.ends_with("CPU Energy") {
read.cpu.push(rail(group, name));
} else if em && name == "GPU Energy" {
read.gpu.push(rail(group, name));
}
// SAFETY: the subscription is live until drop.
unsafe { oracle_read(self.sub, self.ch) }
}
}
/// The oracle's read of any live subscription, with its own sampling
/// and parsing (not `energy_model_channels`): what `OracleSub::read`
/// reads of its own, and what the raw-reader pin counts of the
/// subscriptions it hands the reader.
///
/// # Safety
/// `sub` and `ch` must be a live subscription and its channels.
unsafe fn oracle_read(sub: IOReportSubscriptionRef, ch: CFMutableDictionaryRef) -> Option<OracleRead> {
unsafe {
let smp = IOReportCreateSamples(sub, ch, std::ptr::null());
if smp.is_null() {
return None;
}
let key = CFStringCreateWithCString(
std::ptr::null_mut(),
c"IOReportChannels".as_ptr() as *const _,
K_CFSTRING_ENCODING_UTF8,
);
let mut read = OracleRead { group: Group { energy_model: 0, all: 0 }, cpu: Vec::new(), gpu: Vec::new() };
if !key.is_null() {
let arr = CFDictionaryGetValue(smp, key as *const _) as CFArrayRef;
CFRelease(key as CFTypeRef);
if !arr.is_null() {
for i in 0..CFArrayGetCount(arr) {
let it = CFArrayGetValueAtIndex(arr, i);
if it.is_null() {
continue;
}
read.group.all += 1;
let group = cfstring_to_string(IOReportChannelGetGroup(it)).unwrap_or_default();
let name = cfstring_to_string(IOReportChannelGetChannelName(it)).unwrap_or_default();
let em = group.eq_ignore_ascii_case("Energy Model");
read.group.energy_model += usize::from(em);
let rail = |group: String, name: String| OracleRail {
group,
name,
value: IOReportSimpleGetIntegerValue(it, 0) as i64,
};
if name.ends_with("CPU Energy") {
read.cpu.push(rail(group, name));
} else if em && name == "GPU Energy" {
read.gpu.push(rail(group, name));
}
}
}
CFRelease(smp);
Some(read)
}
CFRelease(smp);
Some(read)
}
}
@ -4445,10 +4457,17 @@ mod macos_ioreport {
/// The raw reader reads the subscription it is handed, every time.
/// Handed the probe's own Energy Model subscription and an all-channel
/// one (`open()`) in turn, it lists the group's channels, then every
/// channel, then the group's again — as many as the oracle counts in
/// each. A reader that hands back an earlier read (stale for the
/// process) fails here whether or not any channel moves, which the GPU
/// freshness pin cannot promise on a host whose GPU is idle.
/// channel, then the group's again — as many as the oracle's own reader
/// counts in each. A reader that hands back an earlier read (stale for
/// the process) fails here whether or not any channel moves, which the
/// GPU freshness pin cannot promise on a host whose GPU is idle.
///
/// The oracle counts the two subscriptions the reader is handed, not
/// one of its own: an all-channel subscription holds the channels
/// registered when it opened, and a laptop registers more as it runs
/// (12,862 when the oracle's opened, 13,014 a moment later for
/// `open()`'s, on an M5 Max), so a third subscription is no measure of
/// these two.
#[test]
fn the_raw_reader_reads_the_subscription_it_is_given_every_time() {
let Some(oracle) = OracleSub::open() else {
@ -4456,10 +4475,17 @@ mod macos_ioreport {
assert_ne!(ioreport_status(), IoReportStatus::Live, "Live with no IOReport");
return;
};
let group = oracle.read().expect("the oracle's subscription yields a sample").group;
let own = oracle.read().expect("the oracle's subscription yields a sample").group;
let probe = EnergyModelSub::open().expect("the oracle reads IOReport; the probe's group subscription does not open");
// SAFETY: open returns owned, non-null refs, released below.
let (sub, ch) = unsafe { open() }.expect("the probe's group opens, a subscription to every channel does not");
// SAFETY: both subscriptions are live until released below.
let (want_g, want_a) = unsafe {
(
oracle_read(probe.sub, probe.ch).expect("the oracle reads the group subscription").group,
oracle_read(sub, ch).expect("the oracle reads the all-channel subscription").group,
)
};
let mut listed = Vec::new();
for _ in 0..3 {
// SAFETY: both subscriptions are live until released below.
@ -4473,17 +4499,34 @@ mod macos_ioreport {
CFRelease(ch as CFTypeRef);
}
eprintln!(
"ioreport raw reader: (group, every channel) listed {listed:?}; the oracle counts ({}, {})",
group.energy_model, group.all
"ioreport raw reader: (group, every channel) listed {listed:?}; the oracle counts ({}, {}) in the \
subscriptions handed over, ({}, {}) in its own",
want_g.all, want_a.all, own.energy_model, own.all
);
assert_eq!(
want_g.energy_model, want_g.all,
"the probe's subscription holds {} channels, {} of them the Energy Model group's",
want_g.all, want_g.energy_model
);
assert_eq!(
want_a.energy_model, want_g.all,
"the all-channel subscription holds {} Energy Model channels, the probe's {}",
want_a.energy_model, want_g.all
);
assert!(
want_g.all < want_a.all,
"the group's {} channels are not fewer than every channel's {}",
want_g.all,
want_a.all
);
for (i, (g, a)) in listed.iter().enumerate() {
assert_eq!(
(*g, *a),
(group.energy_model, group.all),
(want_g.all, want_a.all),
"read {i}: the raw reader listed {g} channels for the group and {a} for every channel; the oracle \
counts {} and {}: it did not read the subscription it was handed",
group.energy_model,
group.all
counts {} and {} in those subscriptions: it did not read the subscription it was handed",
want_g.all,
want_a.all
);
}
}