1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
#include "cpu.h"
#include "common/sysctl.h"
#include "common/apple/smc_temps.h"
#include "common/strutil.h"
static double detectCpuTemp(const FFCPUOptions* options, const FFstrbuf* cpuName) {
double result = 0;
const char* error = NULL;
if (options->tempSensor.length) {
error = ffDetectSmcSpecificTemp(options->tempSensor.chars, &result);
} else {
if (ffStrbufStartsWithS(cpuName, "Apple M")) {
switch (strtol(cpuName->chars + strlen("Apple M"), NULL, 10)) {
case 1:
error = ffDetectSmcTemps(FF_TEMP_CPU_M1X, &result);
break;
case 2:
error = ffDetectSmcTemps(FF_TEMP_CPU_M2X, &result);
break;
case 3:
error = ffDetectSmcTemps(FF_TEMP_CPU_M3X, &result);
break;
case 4:
error = ffDetectSmcTemps(FF_TEMP_CPU_M4X, &result);
break;
default:
error = "Unsupported Apple Silicon CPU";
}
} else { // PPC?
error = ffDetectSmcTemps(FF_TEMP_CPU_X64, &result);
}
}
if (error) {
return FF_CPU_TEMP_UNSET;
}
return result;
}
#ifdef __aarch64__
#include "common/apple/cf_helpers.h"
#include <IOKit/IOKitLib.h>
static const char* detectFrequency(FFCPUResult* cpu) {
// https://github.com/giampaolo/psutil/pull/2222/files
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("pmgr"));
if (!entryDevice) {
return "IOServiceGetMatchingService() failed";
}
if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice")) {
return "\"pmgr\" should conform to \"AppleARMIODevice\"";
}
FF_CFTYPE_AUTO_RELEASE CFDataRef freqProperty = (CFDataRef) IORegistryEntryCreateCFProperty(entryDevice, CFSTR("voltage-states5-sram"), kCFAllocatorDefault, kNilOptions);
if (!freqProperty || CFGetTypeID(freqProperty) != CFDataGetTypeID()) {
return "\"voltage-states5-sram\" in \"pmgr\" is not found";
}
// voltage-states5-sram stores supported <frequency / voltage> pairs of pcores from the lowest to the highest
// voltage-states1-sram stores ecores'
CFIndex propLength = CFDataGetLength(freqProperty);
if (propLength == 0 || propLength % (CFIndex) sizeof(uint32_t) * 2 != 0) {
return "Invalid \"voltage-states5-sram\" length";
}
uint32_t* pStart = (uint32_t*) CFDataGetBytePtr(freqProperty);
uint32_t pMax = *pStart;
for (CFIndex i = 2; i < propLength / (CFIndex) sizeof(uint32_t) && pStart[i] > 0; i += 2 /* skip voltage */) {
pMax = pMax > pStart[i] ? pMax : pStart[i];
}
if (pMax > 0) {
if (pMax > 100000000) { // Assume that pMax is in Hz, M1~M3
cpu->frequencyMax = pMax / 1000 / 1000;
} else { // Assume that pMax is in kHz, M4 and later (#1394)
cpu->frequencyMax = pMax / 1000;
}
}
return NULL;
}
#else
static const char* detectFrequency(FFCPUResult* cpu) {
cpu->frequencyBase = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency", 0) / 1000 / 1000);
cpu->frequencyMax = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency_max", 0) / 1000 / 1000);
if (cpu->frequencyBase == 0) {
unsigned current = 0;
size_t size = sizeof(current);
if (sysctl((int[]) { CTL_HW, HW_CPU_FREQ }, 2, ¤t, &size, NULL, 0) == 0) {
cpu->frequencyBase = (uint32_t) (current / 1000 / 1000);
}
}
return NULL;
}
#endif
static const char* detectCoreCount(FFCPUResult* cpu) {
uint32_t nPerfLevels = (uint32_t) ffSysctlGetInt("hw.nperflevels", 0);
if (nPerfLevels <= 0) {
return "sysctl(hw.nperflevels) failed";
}
char sysctlKey[] = "hw.perflevelN.logicalcpu";
if (nPerfLevels > ARRAY_SIZE(cpu->coreTypes)) {
nPerfLevels = ARRAY_SIZE(cpu->coreTypes);
}
for (uint32_t i = 0; i < nPerfLevels; ++i) {
sysctlKey[strlen("hw.perflevel")] = (char) ('0' + i);
cpu->coreTypes[i] = (FFCPUCore) {
.freq = nPerfLevels - i,
.count = (uint32_t) ffSysctlGetInt(sysctlKey, 0),
};
}
return NULL;
}
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
if (ffSysctlGetString("machdep.cpu.brand_string", &cpu->name) != NULL) {
return "sysctlbyname(machdep.cpu.brand_string) failed";
}
ffSysctlGetString("machdep.cpu.vendor", &cpu->vendor);
cpu->packages = (uint16_t) ffSysctlGetInt("hw.packages", 1);
if (cpu->vendor.length == 0 && ffStrbufStartsWithS(&cpu->name, "Apple ")) {
ffStrbufAppendS(&cpu->vendor, "Apple");
}
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu_max", 1);
if (cpu->coresPhysical == 1) {
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu", 1);
}
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.logicalcpu_max", 1);
if (cpu->coresLogical == 1) {
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
}
cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.logicalcpu", 1);
if (cpu->coresOnline == 1) {
cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.activecpu", 1);
}
ffCPUDetectByCpuid(cpu);
detectFrequency(cpu);
if (options->showPeCoreCount) {
detectCoreCount(cpu);
}
cpu->temperature = options->temp ? detectCpuTemp(options, &cpu->name) : FF_CPU_TEMP_UNSET;
return NULL;
}
|