btop/src/osx/sensors.cpp
2021-11-13 23:15:53 +01:00

93 lines
3.6 KiB
C++

#include "sensors.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hidsystem/IOHIDEventSystemClient.h>
#include <string>
#include <numeric>
#include <vector>
extern "C" {
typedef struct __IOHIDEvent *IOHIDEventRef;
typedef struct __IOHIDServiceClient *IOHIDServiceClientRef;
#ifdef __LP64__
typedef double IOHIDFloat;
#else
typedef float IOHIDFloat;
#endif
#define IOHIDEventFieldBase(type) (type << 16)
#define kIOHIDEventTypeTemperature 15
IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef allocator);
int IOHIDEventSystemClientSetMatching(IOHIDEventSystemClientRef client, CFDictionaryRef match);
int IOHIDEventSystemClientSetMatchingMultiple(IOHIDEventSystemClientRef client, CFArrayRef match);
IOHIDEventRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef, int64_t, int32_t, int64_t);
CFStringRef IOHIDServiceClientCopyProperty(IOHIDServiceClientRef service, CFStringRef property);
IOHIDFloat IOHIDEventGetFloatValue(IOHIDEventRef event, int32_t field);
// create a dict ref, like for temperature sensor {"PrimaryUsagePage":0xff00, "PrimaryUsage":0x5}
CFDictionaryRef matching(int page, int usage) {
CFNumberRef nums[2];
CFStringRef keys[2];
keys[0] = CFStringCreateWithCString(0, "PrimaryUsagePage", 0);
keys[1] = CFStringCreateWithCString(0, "PrimaryUsage", 0);
nums[0] = CFNumberCreate(0, kCFNumberSInt32Type, &page);
nums[1] = CFNumberCreate(0, kCFNumberSInt32Type, &usage);
CFDictionaryRef dict = CFDictionaryCreate(0, (const void **)keys, (const void **)nums, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFRelease(keys);
return dict;
}
double getValue(IOHIDServiceClientRef sc) {
IOHIDEventRef event = IOHIDServiceClientCopyEvent(sc, kIOHIDEventTypeTemperature, 0, 0); // here we use ...CopyEvent
IOHIDFloat temp = 0.0;
if (event != 0) {
temp = IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(kIOHIDEventTypeTemperature));
CFRelease(event);
}
return temp;
}
} // extern C
long long Cpu::ThermalSensors::getSensors() {
CFDictionaryRef thermalSensors = matching(0xff00, 5); // 65280_10 = FF00_16
// thermalSensors's PrimaryUsagePage should be 0xff00 for M1 chip, instead of 0xff05
// can be checked by ioreg -lfx
IOHIDEventSystemClientRef system = IOHIDEventSystemClientCreate(kCFAllocatorDefault);
IOHIDEventSystemClientSetMatching(system, thermalSensors);
CFArrayRef matchingsrvs = IOHIDEventSystemClientCopyServices(system);
std::vector<double> temps;
if (matchingsrvs) {
long count = CFArrayGetCount(matchingsrvs);
for (int i = 0; i < count; i++) {
IOHIDServiceClientRef sc = (IOHIDServiceClientRef)CFArrayGetValueAtIndex(matchingsrvs, i);
if (sc) {
CFStringRef name = IOHIDServiceClientCopyProperty(sc, CFSTR("Product")); // here we use ...CopyProperty
if (name) {
char buf[200];
CFStringGetCString(name, buf, 200, kCFStringEncodingASCII);
std::string n(buf);
// this is just a guess, nobody knows which sensors mean what
// on my system PMU tdie 3 and 9 are missing...
// there is also PMU tdev1-8 but it has negative values??
// there is also eACC for efficiency package but it only has 2 entries
// and pACC for performance but it has 7 entries (2 - 9) WTF
if (n.starts_with("eACC") or n.starts_with("pACC")) {
temps.push_back(getValue(sc));
}
CFRelease(name);
}
}
}
CFRelease(matchingsrvs);
}
CFRelease(system);
CFRelease(thermalSensors);
if (temps.empty()) return 0ll;
return round(std::accumulate(temps.begin(), temps.end(), 0ll) / temps.size());
}