diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2020-12-21 14:27:22 -0800 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2020-12-21 14:27:22 -0800 |
commit | 7e7449d51b3a388bdd3a078ca279ecbb3ab53bb0 (patch) | |
tree | 52a636fe552f34f13f5cb6602f9b08ec68b19b64 | |
parent | fe6e09fc158dfc947a6a2de0e45681e5b7ca25a9 (diff) | |
parent | 9906ffa432116cba3ebacc4010c1bde15ea1bcc2 (diff) | |
download | psutil-7e7449d51b3a388bdd3a078ca279ecbb3ab53bb0.tar.gz |
merge from master
-rw-r--r-- | psutil/__init__.py | 2 | ||||
-rw-r--r-- | psutil/_psosx.py | 5 | ||||
-rw-r--r-- | psutil/_psutil_osx.c | 151 | ||||
-rw-r--r-- | psutil/arch/osx/cpu.c | 151 | ||||
-rw-r--r-- | psutil/arch/osx/cpu.h | 14 | ||||
-rwxr-xr-x | psutil/tests/test_system.py | 30 | ||||
-rwxr-xr-x | setup.py | 1 |
7 files changed, 194 insertions, 160 deletions
diff --git a/psutil/__init__.py b/psutil/__init__.py index f8c0ba98..63f77e63 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -1598,7 +1598,7 @@ def cpu_count(kind="logical", **_kwargs): return None n = _psplatform.cpu_count_cores() elif kind == "sockets": - # Availability: Linux, TODO + # Availability: Linux, Windows, macOS if not hasattr(_psplatform, "cpu_count_sockets"): return None n = _psplatform.cpu_count_sockets() diff --git a/psutil/_psosx.py b/psutil/_psosx.py index d948cc15..9cfb2d15 100644 --- a/psutil/_psosx.py +++ b/psutil/_psosx.py @@ -164,6 +164,11 @@ def cpu_count_cores(): return cext.cpu_count_cores() +def cpu_count_sockets(): + """Return the number of physical sockets on the motherboard.""" + return cext.cpu_count_sockets() + + def cpu_stats(): ctx_switches, interrupts, soft_interrupts, syscalls, traps = \ cext.cpu_stats() diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c index b5aa7653..47b5393f 100644 --- a/psutil/_psutil_osx.c +++ b/psutil/_psutil_osx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * @@ -14,7 +14,6 @@ #include <stdio.h> #include <utmpx.h> #include <sys/sysctl.h> -#include <sys/vmmeter.h> #include <libproc.h> #include <sys/proc_info.h> #include <netinet/tcp_fsm.h> @@ -22,13 +21,7 @@ #include <net/if_dl.h> #include <pwd.h> #include <unistd.h> - #include <mach/mach.h> -#include <mach/task.h> -#include <mach/mach_init.h> -#include <mach/host_info.h> -#include <mach/mach_host.h> -#include <mach/mach_traps.h> #include <mach/mach_vm.h> #include <mach/shared_region.h> @@ -45,6 +38,7 @@ #include "_psutil_common.h" #include "_psutil_posix.h" #include "arch/osx/process_info.h" +#include "arch/osx/cpu.h" #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) @@ -354,50 +348,6 @@ psutil_proc_environ(PyObject *self, PyObject *args) { /* - * Return the number of logical CPUs in the system. - * XXX this could be shared with BSD. - */ -static PyObject * -psutil_cpu_count_logical(PyObject *self, PyObject *args) { - /* - int mib[2]; - int ncpu; - size_t len; - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - len = sizeof(ncpu); - - if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) - Py_RETURN_NONE; // mimic os.cpu_count() - else - return Py_BuildValue("i", ncpu); - */ - int num; - size_t size = sizeof(int); - - if (sysctlbyname("hw.logicalcpu", &num, &size, NULL, 2)) - Py_RETURN_NONE; // mimic os.cpu_count() - else - return Py_BuildValue("i", num); -} - - -/* - * Return the number of CPU cores in the system. - */ -static PyObject * -psutil_cpu_count_cores(PyObject *self, PyObject *args) { - int num; - size_t size = sizeof(int); - - if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0)) - Py_RETURN_NONE; // mimic os.cpu_count() - else - return Py_BuildValue("i", num); -} - - -/* * Indicates if the given virtual address on the given architecture is in the * shared VM region. */ @@ -588,36 +538,6 @@ psutil_swap_mem(PyObject *self, PyObject *args) { /* - * Return a Python tuple representing user, kernel and idle CPU times - */ -static PyObject * -psutil_cpu_times(PyObject *self, PyObject *args) { - mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; - kern_return_t error; - host_cpu_load_info_data_t r_load; - - mach_port_t host_port = mach_host_self(); - error = host_statistics(host_port, HOST_CPU_LOAD_INFO, - (host_info_t)&r_load, &count); - if (error != KERN_SUCCESS) { - return PyErr_Format( - PyExc_RuntimeError, - "host_statistics(HOST_CPU_LOAD_INFO) syscall failed: %s", - mach_error_string(error)); - } - mach_port_deallocate(mach_task_self(), host_port); - - return Py_BuildValue( - "(dddd)", - (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK, - (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK, - (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, - (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK - ); -} - - -/* * Return a Python list of tuple representing per-cpu times */ static PyObject * @@ -684,40 +604,6 @@ error: /* - * Retrieve CPU frequency. Note: all of these are static vendor values - * that never change. - */ -static PyObject * -psutil_cpu_freq(PyObject *self, PyObject *args) { - unsigned int curr; - int64_t min = 0; - int64_t max = 0; - int mib[2]; - size_t len = sizeof(curr); - size_t size = sizeof(min); - - // also availble as "hw.cpufrequency" but it's deprecated - mib[0] = CTL_HW; - mib[1] = HW_CPU_FREQ; - - if (sysctl(mib, 2, &curr, &len, NULL, 0) < 0) - return PyErr_SetFromOSErrnoWithSyscall("sysctl(HW_CPU_FREQ)"); - - if (sysctlbyname("hw.cpufrequency_min", &min, &size, NULL, 0)) - psutil_debug("sysct('hw.cpufrequency_min') failed (set to 0)"); - - if (sysctlbyname("hw.cpufrequency_max", &max, &size, NULL, 0)) - psutil_debug("sysctl('hw.cpufrequency_min') failed (set to 0)"); - - return Py_BuildValue( - "IKK", - curr / 1000 / 1000, - min / 1000 / 1000, - max / 1000 / 1000); -} - - -/* * Return a Python float indicating the system boot time expressed in * seconds since the epoch. */ @@ -1635,37 +1521,6 @@ error: /* - * Return CPU statistics. - */ -static PyObject * -psutil_cpu_stats(PyObject *self, PyObject *args) { - struct vmmeter vmstat; - kern_return_t ret; - mach_msg_type_number_t count = sizeof(vmstat) / sizeof(integer_t); - mach_port_t mport = mach_host_self(); - - ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)&vmstat, &count); - if (ret != KERN_SUCCESS) { - PyErr_Format( - PyExc_RuntimeError, - "host_statistics(HOST_VM_INFO) failed: %s", - mach_error_string(ret)); - return NULL; - } - mach_port_deallocate(mach_task_self(), mport); - - return Py_BuildValue( - "IIIII", - vmstat.v_swtch, // ctx switches - vmstat.v_intr, // interrupts - vmstat.v_soft, // software interrupts - vmstat.v_syscall, // syscalls - vmstat.v_trap // traps - ); -} - - -/* * Return battery information. */ static PyObject * @@ -1791,6 +1646,8 @@ static PyMethodDef mod_methods[] = { "Return number of logical CPUs on the system"}, {"cpu_count_cores", psutil_cpu_count_cores, METH_VARARGS, "Return number of CPU cores on the system"}, + {"cpu_count_sockets", psutil_cpu_count_sockets, METH_VARARGS, + "Return number of CPU sockets on the motherboard"}, {"virtual_mem", psutil_virtual_mem, METH_VARARGS, "Return system virtual memory stats"}, {"swap_mem", psutil_swap_mem, METH_VARARGS, diff --git a/psutil/arch/osx/cpu.c b/psutil/arch/osx/cpu.c new file mode 100644 index 00000000..e6f72a8a --- /dev/null +++ b/psutil/arch/osx/cpu.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* +System-wide CPU related functions. + +Original code was refactored and moved from psutil/_psutil_osx.c in 2020 +right before a4c0a0eb0d2a872ab7a45e47fcf37ef1fde5b012. +For reference, here's the git history with original implementations: + +- CPU count logical: 3d291d425b856077e65163e43244050fb188def1 +- CPU count physical: 4263e354bb4984334bc44adf5dd2f32013d69fba +- CPU times: 32488bdf54aed0f8cef90d639c1667ffaa3c31c7 +- CPU stat: fa00dfb961ef63426c7818899340866ced8d2418 +- CPU frequency: 6ba1ac4ebfcd8c95fca324b15606ab0ec1412d39 +*/ + +#include <Python.h> +#include <sys/sysctl.h> +#include <sys/vmmeter.h> + +#include <mach/mach_error.h> +#include <mach/mach_host.h> +#include <mach/mach_port.h> + +#include "../../_psutil_common.h" +#include "../../_psutil_posix.h" + + +PyObject * +psutil_cpu_count_logical(PyObject *self, PyObject *args) { + int num; + size_t size = sizeof(int); + + if (sysctlbyname("hw.logicalcpu", &num, &size, NULL, 2)) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("i", num); +} + + +PyObject * +psutil_cpu_count_cores(PyObject *self, PyObject *args) { + int num; + size_t size = sizeof(int); + + if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0)) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("i", num); +} + + +PyObject * +psutil_cpu_count_sockets(PyObject *self, PyObject *args) { + int value; + size_t size = sizeof(value); + + if (sysctlbyname("hw.packages", &value, &size, NULL, 2)) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("i", value); +} + + +PyObject * +psutil_cpu_times(PyObject *self, PyObject *args) { + mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; + kern_return_t error; + host_cpu_load_info_data_t r_load; + + mach_port_t host_port = mach_host_self(); + error = host_statistics(host_port, HOST_CPU_LOAD_INFO, + (host_info_t)&r_load, &count); + if (error != KERN_SUCCESS) { + return PyErr_Format( + PyExc_RuntimeError, + "host_statistics(HOST_CPU_LOAD_INFO) syscall failed: %s", + mach_error_string(error)); + } + mach_port_deallocate(mach_task_self(), host_port); + + return Py_BuildValue( + "(dddd)", + (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK, + (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK, + (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, + (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK + ); +} + + +PyObject * +psutil_cpu_stats(PyObject *self, PyObject *args) { + struct vmmeter vmstat; + kern_return_t ret; + mach_msg_type_number_t count = sizeof(vmstat) / sizeof(integer_t); + mach_port_t mport = mach_host_self(); + + ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)&vmstat, &count); + if (ret != KERN_SUCCESS) { + PyErr_Format( + PyExc_RuntimeError, + "host_statistics(HOST_VM_INFO) failed: %s", + mach_error_string(ret)); + return NULL; + } + mach_port_deallocate(mach_task_self(), mport); + + return Py_BuildValue( + "IIIII", + vmstat.v_swtch, // ctx switches + vmstat.v_intr, // interrupts + vmstat.v_soft, // software interrupts + vmstat.v_syscall, // syscalls + vmstat.v_trap // traps + ); +} + + +PyObject * +psutil_cpu_freq(PyObject *self, PyObject *args) { + unsigned int curr; + int64_t min = 0; + int64_t max = 0; + int mib[2]; + size_t len = sizeof(curr); + size_t size = sizeof(min); + + // also availble as "hw.cpufrequency" but it's deprecated + mib[0] = CTL_HW; + mib[1] = HW_CPU_FREQ; + + if (sysctl(mib, 2, &curr, &len, NULL, 0) < 0) + return PyErr_SetFromOSErrnoWithSyscall("sysctl(HW_CPU_FREQ)"); + + if (sysctlbyname("hw.cpufrequency_min", &min, &size, NULL, 0)) + psutil_debug("sysct('hw.cpufrequency_min') failed (set to 0)"); + + if (sysctlbyname("hw.cpufrequency_max", &max, &size, NULL, 0)) + psutil_debug("sysctl('hw.cpufrequency_min') failed (set to 0)"); + + return Py_BuildValue( + "IKK", + curr / 1000 / 1000, + min / 1000 / 1000, + max / 1000 / 1000); +} diff --git a/psutil/arch/osx/cpu.h b/psutil/arch/osx/cpu.h new file mode 100644 index 00000000..40be1117 --- /dev/null +++ b/psutil/arch/osx/cpu.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <Python.h> + +PyObject *psutil_cpu_count_logical(PyObject *self, PyObject *args); +PyObject *psutil_cpu_count_cores(PyObject *self, PyObject *args); +PyObject *psutil_cpu_count_sockets(PyObject *self, PyObject *args); +PyObject *psutil_cpu_times(PyObject *self, PyObject *args); +PyObject *psutil_cpu_freq(PyObject *self, PyObject *args); +PyObject *psutil_cpu_stats(PyObject *self, PyObject *args); diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index 4044e468..317a0ea8 100755 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -303,13 +303,14 @@ class TestMemoryAPIs(PsutilTestCase): assert mem.sout >= 0, mem -class TestCpuAPIs(PsutilTestCase): +class TestCpuCount(PsutilTestCase): - def test_cpu_count(self): + def test_base(self): kinds = ("logical", "cores", "sockets", "numa", "usable") for kind in kinds: n = psutil.cpu_count(kind=kind) if n is not None: + self.assertIsInstance(n, int) with self.subTest(kind): self.assertGreaterEqual(n, 1) @@ -321,7 +322,7 @@ class TestCpuAPIs(PsutilTestCase): psutil.cpu_count(kind='xxx') self.assertIn(str(kinds), str(cm.exception)) - def test_cpu_count_consistency(self): + def test_consistency(self): logical = psutil.cpu_count("logical") cores = psutil.cpu_count("cores") sockets = psutil.cpu_count("sockets") @@ -341,7 +342,7 @@ class TestCpuAPIs(PsutilTestCase): if sockets is not None: self.assertGreaterEqual(cores, sockets) - def test_cpu_count_deprecation(self): + def test_deprecation(self): with warnings.catch_warnings(): warnings.simplefilter("ignore") self.assertEqual(psutil.cpu_count(logical=True), @@ -363,7 +364,7 @@ class TestCpuAPIs(PsutilTestCase): psutil.cpu_count(True) assert ws - def test_cpu_count_cores(self): + def test_cores(self): logical = psutil.cpu_count() cores = psutil.cpu_count(logical=False) if cores is None: @@ -374,19 +375,18 @@ class TestCpuAPIs(PsutilTestCase): self.assertGreaterEqual(cores, 1) self.assertGreaterEqual(logical, cores) - def test_cpu_count_none(self): + def test_return_none(self): # https://github.com/giampaolo/psutil/issues/1085 for val in (-1, 0, None): with mock.patch('psutil._psplatform.cpu_count_logical', return_value=val) as m: self.assertIsNone(psutil.cpu_count()) assert m.called - with mock.patch('psutil._psplatform.cpu_count_cores', - return_value=val) as m: - self.assertIsNone(psutil.cpu_count(logical=False)) - assert m.called - def test_cpu_times(self): + +class TestCpuTimes(PsutilTestCase): + + def test_base(self): # Check type, value >= 0, str(). total = 0 times = psutil.cpu_times() @@ -415,7 +415,7 @@ class TestCpuAPIs(PsutilTestCase): # msg="%s %s" % (new_t, last_t)) # last = new - def test_cpu_times_time_increases(self): + def test_time_increases(self): # Make sure time increases between calls. t1 = sum(psutil.cpu_times()) stop_at = time.time() + GLOBAL_TIMEOUT @@ -483,6 +483,9 @@ class TestCpuAPIs(PsutilTestCase): self.assertAlmostEqual( getattr(base, field), getattr(summed_values, field), delta=1) + +class TestCpuPercent(PsutilTestCase): + def _test_cpu_percent(self, percent, last_ret, new_ret): try: self.assertIsInstance(percent, float) @@ -545,6 +548,9 @@ class TestCpuAPIs(PsutilTestCase): for percent in cpu: self._test_cpu_percent(percent, None, None) + +class TestOtherCPUFunctions(PsutilTestCase): + def test_cpu_stats(self): # Tested more extensively in per-platform test modules. infos = psutil.cpu_stats() @@ -189,6 +189,7 @@ elif MACOS: sources=sources + [ 'psutil/_psutil_osx.c', 'psutil/arch/osx/process_info.c', + 'psutil/arch/osx/cpu.c', ], define_macros=macros, extra_link_args=[ |