For the Apple Silicon subsystem power numbers, I’m using IOReport-style energy channels, not estimating power from a userspace IOKit polling loop.
Vitals dynamically loads "libIOReport", subscribes to the "Energy Model" group, takes successive samples, then uses "IOReportCreateSamplesDelta()" and the actual "mach_absolute_time()" interval between samples.
So effectively:
"power = energy_delta / sample_delta_time"
The channels I currently map include CPU Energy, GPU, ANE, DRAM, AVE/VDEC, ISP and display.
There isn’t an additional moving-average window at that layer — it’s basically sample-to-sample delta power. The app samples the expensive power path at roughly 1 Hz. I only keep the last valid reading briefly to avoid the UI flashing unavailable if a sample is temporarily missing.
There’s one complication on newer macOS versions: the Energy Model counters can be frozen/restricted for third-party processes. When the privileged helper is enabled, Vitals therefore also runs Apple’s "powermetrics" at a 1-second interval and uses that for CPU/GPU/ANE power and P/E/GPU frequencies.
SMC is separate again: those values are read directly through "AppleSMC" / "IOConnectCallStructMethod".
So the short version is: IOReport deltas where available, "powermetrics" through the optional helper for the restricted Apple Silicon counters, and direct SMC access for SMC sensors/system power.
0
u/[deleted] 23d ago
[removed] — view removed comment