Power & Storage only had macOS's thermal state (a level, no degrees) and the battery temperature. The CPU die sensors are now read through IOHIDEventSystemClient (no root or entitlement needed outside the sandbox): "PMU tdie*" from M2 on, "pACC/eACC MTR Temp Sensor*" on M1. System Status shows the hottest one, with the average and sensor count in the tooltip, coloured from 80/90/100 °C. Intel Macs have no such sensors and the row stays hidden. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 sor
2.9 KiB
Swift
72 sor
2.9 KiB
Swift
import XCTest
|
|
@testable import TopManager
|
|
|
|
final class ThermalMathTests: XCTestCase {
|
|
|
|
// Names as an M3 reports them (PMU / PMU2 dies, package, calibration, NAND, battery).
|
|
private let m3: [TemperatureReading] = [
|
|
.init(name: "PMU tdie1", celsius: 48.8),
|
|
.init(name: "PMU tdie2", celsius: 46.4),
|
|
.init(name: "PMU2 tdie1", celsius: 43.4),
|
|
.init(name: "PMU tdev2", celsius: 36.2),
|
|
.init(name: "PMU tdev1", celsius: -1.5),
|
|
.init(name: "PMU tcal", celsius: 51.9),
|
|
.init(name: "NAND CH0 temp", celsius: 34.0),
|
|
.init(name: "gas gauge battery", celsius: 31.3),
|
|
]
|
|
|
|
func testOnlyDieSensorsCount() {
|
|
let info = ThermalMath.summarize(m3)
|
|
XCTAssertEqual(info?.cpuSensorCount, 3)
|
|
// tcal (51.9) is hotter than every die but is a calibration value, not the CPU.
|
|
XCTAssertEqual(info?.cpuMax ?? 0, 48.8, accuracy: 0.001)
|
|
XCTAssertEqual(info?.cpuAverage ?? 0, (48.8 + 46.4 + 43.4) / 3, accuracy: 0.001)
|
|
}
|
|
|
|
func testM1ClusterSensorsCount() {
|
|
let m1: [TemperatureReading] = [
|
|
.init(name: "pACC MTR Temp Sensor0", celsius: 55),
|
|
.init(name: "eACC MTR Temp Sensor1", celsius: 41),
|
|
.init(name: "GPU MTR Temp Sensor1", celsius: 60),
|
|
.init(name: "SOC MTR Temp Sensor0", celsius: 50),
|
|
]
|
|
let info = ThermalMath.summarize(m1)
|
|
XCTAssertEqual(info?.cpuSensorCount, 2)
|
|
XCTAssertEqual(info?.cpuMax ?? 0, 55, accuracy: 0.001)
|
|
}
|
|
|
|
func testImplausibleDieReadingsAreDropped() {
|
|
let readings: [TemperatureReading] = [
|
|
.init(name: "PMU tdie1", celsius: 0),
|
|
.init(name: "PMU tdie2", celsius: -2),
|
|
.init(name: "PMU tdie3", celsius: 170),
|
|
.init(name: "PMU tdie4", celsius: 44),
|
|
]
|
|
XCTAssertEqual(ThermalMath.summarize(readings)?.cpuSensorCount, 1)
|
|
}
|
|
|
|
func testNoCPUSensorsMeansNil() {
|
|
// An Intel Mac: no IOHID die sensors at all, or only non-CPU ones.
|
|
XCTAssertNil(ThermalMath.summarize([]))
|
|
XCTAssertNil(ThermalMath.summarize([.init(name: "gas gauge battery", celsius: 30)]))
|
|
}
|
|
|
|
func testReadsRealSensorsOnAppleSilicon() throws {
|
|
#if !arch(arm64)
|
|
throw XCTSkip("Apple Silicon only: Intel Macs expose these sensors through the SMC")
|
|
#else
|
|
let info = try XCTUnwrap(TemperatureMonitor().fetchThermalInfo())
|
|
XCTAssertGreaterThan(info.cpuSensorCount, 0)
|
|
XCTAssertTrue((15...110).contains(info.cpuMax), "implausible CPU temperature \(info.cpuMax)")
|
|
XCTAssertLessThanOrEqual(info.cpuAverage, info.cpuMax)
|
|
#endif
|
|
}
|
|
|
|
func testLevels() {
|
|
XCTAssertEqual(ThermalMath.level(cpuCelsius: 48), .nominal)
|
|
XCTAssertEqual(ThermalMath.level(cpuCelsius: 85), .fair)
|
|
XCTAssertEqual(ThermalMath.level(cpuCelsius: 95), .serious)
|
|
XCTAssertEqual(ThermalMath.level(cpuCelsius: 104), .critical)
|
|
}
|
|
}
|