diff --git a/CREDITS b/CREDITS index 1ade9d3ef..59715ac76 100644 --- a/CREDITS +++ b/CREDITS @@ -813,3 +813,7 @@ I: 2156, 2345 N: Lawrence D'Anna W: https://github.com/smoofra I: 2010 + +N: Oliver Tomé +W: https://github.com/snom3ad +I: 2222 diff --git a/HISTORY.rst b/HISTORY.rst index 8467b90e5..e0316f66c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -20,6 +20,8 @@ - 2340_, [NetBSD]: if process is terminated, `Process.cwd()`_ will return an empty string instead of raising `NoSuchProcess`_. - 2345_, [Linux]: fix compilation on older compiler missing DUPLEX_UNKNOWN +- 2222_, [macOS]: `cpu_freq()` now returns fixed values for `min` and `max` + frequencies in all Apple Silicon chips. 5.9.7 ===== diff --git a/psutil/arch/osx/cpu.c b/psutil/arch/osx/cpu.c index a1ba11429..4196083ec 100644 --- a/psutil/arch/osx/cpu.c +++ b/psutil/arch/osx/cpu.c @@ -26,6 +26,10 @@ For reference, here's the git history with original implementations: #include #include #include +#if defined(__arm64__) || defined(__aarch64__) +#include +#include +#endif #include "../../_psutil_common.h" #include "../../_psutil_posix.h" @@ -109,7 +113,122 @@ psutil_cpu_stats(PyObject *self, PyObject *args) { ); } +#if defined(__arm64__) || defined(__aarch64__) +PyObject * +psutil_cpu_freq(PyObject *self, PyObject *args) { + uint32_t min; + uint32_t curr; + uint32_t pMin; + uint32_t eMin; + uint32_t max; + kern_return_t status; + CFDictionaryRef matching = NULL; + CFTypeRef pCoreRef = NULL; + CFTypeRef eCoreRef = NULL; + io_iterator_t iter = 0; + io_registry_entry_t entry = 0; + io_name_t name; + + matching = IOServiceMatching("AppleARMIODevice"); + if (matching == 0) { + return PyErr_Format( + PyExc_RuntimeError, + "IOServiceMatching call failed, 'AppleARMIODevice' not found" + ); + } + + status = IOServiceGetMatchingServices(kIOMainPortDefault, matching, &iter); + if (status != KERN_SUCCESS) { + PyErr_Format( + PyExc_RuntimeError, "IOServiceGetMatchingServices call failed" + ); + goto error; + } + + while ((entry = IOIteratorNext(iter)) != 0) { + status = IORegistryEntryGetName(entry, name); + if (status != KERN_SUCCESS) { + IOObjectRelease(entry); + continue; + } + if (strcmp(name, "pmgr") == 0) { + break; + } + IOObjectRelease(entry); + } + if (entry == 0) { + PyErr_Format( + PyExc_RuntimeError, + "'pmgr' entry was not found in AppleARMIODevice service" + ); + goto error; + } + + pCoreRef = IORegistryEntryCreateCFProperty( + entry, CFSTR("voltage-states5-sram"), kCFAllocatorDefault, 0); + if (pCoreRef == NULL) { + PyErr_Format( + PyExc_RuntimeError, "'voltage-states5-sram' property not found"); + goto error; + } + + eCoreRef = IORegistryEntryCreateCFProperty( + entry, CFSTR("voltage-states1-sram"), kCFAllocatorDefault, 0); + if (eCoreRef == NULL) { + PyErr_Format( + PyExc_RuntimeError, "'voltage-states1-sram' property not found"); + goto error; + } + + size_t pCoreLength = CFDataGetLength(pCoreRef); + size_t eCoreLength = CFDataGetLength(eCoreRef); + if (pCoreLength < 8) { + PyErr_Format( + PyExc_RuntimeError, + "expected 'voltage-states5-sram' buffer to have at least size 8" + ); + goto error; + } + if (eCoreLength < 4) { + PyErr_Format( + PyExc_RuntimeError, + "expected 'voltage-states1-sram' buffer to have at least size 4" + ); + goto error; + } + + CFDataGetBytes(pCoreRef, CFRangeMake(0, 4), (UInt8 *) &pMin); + CFDataGetBytes(eCoreRef, CFRangeMake(0, 4), (UInt8 *) &eMin); + CFDataGetBytes(pCoreRef, CFRangeMake(pCoreLength - 8, 4), (UInt8 *) &max); + + min = pMin < eMin ? pMin : eMin; + curr = max; + + CFRelease(pCoreRef); + CFRelease(eCoreRef); + IOObjectRelease(iter); + IOObjectRelease(entry); + + return Py_BuildValue( + "IKK", + curr / 1000 / 1000, + min / 1000 / 1000, + max / 1000 / 1000 + ); + +error: + if (pCoreRef != NULL) + CFRelease(pCoreRef); + if (eCoreRef != NULL) + CFRelease(eCoreRef); + if (iter != 0) + IOObjectRelease(iter); + if (entry != 0) + IOObjectRelease(entry); + return NULL; +} +#else PyObject * psutil_cpu_freq(PyObject *self, PyObject *args) { unsigned int curr; @@ -138,7 +257,7 @@ psutil_cpu_freq(PyObject *self, PyObject *args) { min / 1000 / 1000, max / 1000 / 1000); } - +#endif PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) {