Skip to content

Commit

Permalink
Fix cpu_freq for Apple silicon
Browse files Browse the repository at this point in the history
Apple SoC returns empty string after querying the cpu frequency using
sysctl, this information however, can still be extracted from the IOKit
registry. This PR adds a new method that is specific to Apple ARM
architecture.

Fixes #1892
  • Loading branch information
snOm3ad committed Apr 8, 2023
1 parent 55b7ca0 commit d13cb18
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 1 deletion.
6 changes: 5 additions & 1 deletion psutil/_psosx.py
Expand Up @@ -176,7 +176,11 @@ def cpu_freq():
Also, the returned frequency never changes, see:
https://arstechnica.com/civis/viewtopic.php?f=19&t=465002
"""
curr, min_, max_ = cext.cpu_freq()
try:
curr, min_, max_ = cext.cpu_freq()
except FileNotFoundError:
# apple silicon requires specialized call.
curr, min_, max_ = cext.arm_cpu_freq()
return [_common.scpufreq(curr, min_, max_)]


Expand Down
1 change: 1 addition & 0 deletions psutil/_psutil_osx.c
Expand Up @@ -1723,6 +1723,7 @@ static PyMethodDef mod_methods[] = {
{"cpu_count_cores", psutil_cpu_count_cores, METH_VARARGS},
{"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS},
{"cpu_freq", psutil_cpu_freq, METH_VARARGS},
{"arm_cpu_freq", psutil_arm_cpu_freq, METH_VARARGS},
{"cpu_stats", psutil_cpu_stats, METH_VARARGS},
{"cpu_times", psutil_cpu_times, METH_VARARGS},
{"disk_io_counters", psutil_disk_io_counters, METH_VARARGS},
Expand Down
45 changes: 45 additions & 0 deletions psutil/arch/osx/cpu.c
Expand Up @@ -29,6 +29,9 @@ For reference, here's the git history with original implementations:
#include "../../_psutil_common.h"
#include "../../_psutil_posix.h"

#include <COreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>



PyObject *
Expand Down Expand Up @@ -109,6 +112,48 @@ psutil_cpu_stats(PyObject *self, PyObject *args) {
);
}

PyObject *
psutil_arm_cpu_freq(PyObject *self, PyObject *args) {
unsigned int curr;
uint32_t min = UINT32_MAX;
uint32_t max = 0;

CFDictionaryRef matching = IOServiceMatching("AppleARMIODevice");
io_iterator_t iter;

IOServiceGetMatchingServices(kIOMainPortDefault, matching, &iter);
io_registry_entry_t entry;
while ((entry = IOIteratorNext(iter))) {
io_name_t name;
IORegistryEntryGetName(entry, name);

if (strncmp(name, "pmgr", 4) == 0) {
break;
}
}
IOObjectRelease(iter);
CFRelease(matching);
CFTypeRef pCoreRef = IORegistryEntryCreateCFProperty(entry, CFSTR("voltage-states5-sram"), kCFAllocatorDefault, 0);

size_t length = CFDataGetLength(pCoreRef);
for (size_t i = 0; i < length - 3; i += 4) {
uint32_t curr_freq = 0;
CFDataGetBytes(pCoreRef, CFRangeMake(i, sizeof(uint32_t)), (UInt8 *) &curr_freq);
if (curr_freq > 1e6 && curr_freq < min) {
min = curr_freq;
}
if (curr_freq > max) {
max = curr_freq;
}
}
curr = max;

return Py_BuildValue(
"IKK",
curr / 1000 / 1000,
min / 1000 / 1000,
max / 1000 / 1000);
}

PyObject *
psutil_cpu_freq(PyObject *self, PyObject *args) {
Expand Down
1 change: 1 addition & 0 deletions psutil/arch/osx/cpu.h
Expand Up @@ -10,4 +10,5 @@ PyObject *psutil_cpu_count_logical(PyObject *self, PyObject *args);
PyObject *psutil_cpu_count_cores(PyObject *self, PyObject *args);
PyObject *psutil_cpu_times(PyObject *self, PyObject *args);
PyObject *psutil_cpu_freq(PyObject *self, PyObject *args);
PyObject *psutil_arm_cpu_freq(PyObject *self, PyObject *args);
PyObject *psutil_cpu_stats(PyObject *self, PyObject *args);

0 comments on commit d13cb18

Please sign in to comment.