diff --git a/README.rst b/README.rst index d413f1e8b..67e5bc923 100644 --- a/README.rst +++ b/README.rst @@ -122,6 +122,9 @@ CPU >>> >>> psutil.cpu_stats() scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0) + >>> + >>> psutil.cpu_freq() + scpufreq(current=931.42925, min=800.0, max=3500.0) Memory ====== diff --git a/docs/index.rst b/docs/index.rst index 270124b77..71c0b9c48 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -191,6 +191,32 @@ CPU .. versionadded:: 4.1.0 +.. function:: cpu_freq(percpu=False) + + Return CPU frequency as a nameduple including *current*, *min* and *max* + frequencies expressed in Mhz. + If *percpu* is ``True`` and the system supports per-cpu frequency + retrieval (Linux only) a list of frequencies is returned for each CPU, + if not, a list with a single element is returned. + + Example (Linux): + + .. code-block:: python + + >>> import psutil + >>> psutil.cpu_freq() + scpufreq(current=931.42925, min=800.0, max=3500.0) + >>> psutil.cpu_freq(percpu=True) + [scpufreq(current=2394.945, min=800.0, max=3500.0), + scpufreq(current=2236.812, min=800.0, max=3500.0), + scpufreq(current=1703.609, min=800.0, max=3500.0), + scpufreq(current=1754.289, min=800.0, max=3500.0)] + + Availability: Linux, OSX, Windows + + .. versionadded:: 5.1.0 + + Memory ------ diff --git a/psutil/__init__.py b/psutil/__init__.py index a8aa84e20..77830230c 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -1854,20 +1854,30 @@ def cpu_stats(): if hasattr(_psplatform, "cpu_freq"): - def cpu_freq(): - """Return CPU frequencies as a list of nameduples including - current, min and max CPU frequency. - The CPUs order is supposed to be consistent with other CPU - functions having a 'percpu' argument and returning results for - multiple CPUs (cpu_times(), cpu_percent(), cpu_times_percent()). - Values are expressed in Mhz. - - Notes about OSX: - - it is not possible to get per-cpu freq - - reported freq never changes: - https://arstechnica.com/civis/viewtopic.php?f=19&t=465002 + def cpu_freq(percpu=False): + """Return CPU frequency as a nameduple including current, + min and max frequency expressed in Mhz. + + If percpu is True and the system supports per-cpu frequency + retrieval (Linux only) a list of frequencies is returned for + each CPU. If not a list with one element is returned. """ - return _psplatform.cpu_freq() + ret = _psplatform.cpu_freq() + if percpu: + return ret + else: + num_cpus = len(ret) + if num_cpus == 1: + return ret[0] + currs, mins, maxs = [], [], [] + for cpu in ret: + currs.append(cpu.current) + mins.append(cpu.min) + maxs.append(cpu.max) + return _common.scpufreq( + sum(currs) / num_cpus, + sum(mins) / num_cpus, + sum(maxs) / num_cpus) __all__.append("cpu_freq") diff --git a/psutil/_common.py b/psutil/_common.py index a8ae27ac1..68134820f 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -157,7 +157,7 @@ class NicDuplex(enum.IntEnum): scpustats = namedtuple( 'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls']) # psutil.cpu_freq() -scpufreq = namedtuple('scpufreq', ['curr', 'min', 'max']) +scpufreq = namedtuple('scpufreq', ['current', 'min', 'max']) # --- for Process methods diff --git a/psutil/_psosx.py b/psutil/_psosx.py index 0778b5fb7..f7adb43ac 100644 --- a/psutil/_psosx.py +++ b/psutil/_psosx.py @@ -166,6 +166,11 @@ def cpu_stats(): def cpu_freq(): + """Return CPU frequency. + On OSX per-cpu frequency is not supported. + Also, the returned frequency never changes, see: + https://arstechnica.com/civis/viewtopic.php?f=19&t=465002 + """ curr, min_, max_ = cext.cpu_freq() return [_common.scpufreq(curr, min_, max_)] diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 8c9625352..da8552e13 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -300,9 +300,12 @@ def cpu_stats(): def cpu_freq(): + """Return CPU frequency. + On Windows per-cpu frequency is not supported. + """ curr, max_ = cext.cpu_freq() - min_ = 0 - return [_common.scpufreq(curr, min_, max_)] + min_ = 0.0 + return [_common.scpufreq(float(curr), min_, float(max_))] # ===================================================================== diff --git a/psutil/tests/test_osx.py b/psutil/tests/test_osx.py index 02fa430b7..6e7a58917 100755 --- a/psutil/tests/test_osx.py +++ b/psutil/tests/test_osx.py @@ -153,7 +153,7 @@ def test_cpu_count_physical(self): def test_cpu_freq(self): freq = psutil.cpu_freq()[0] self.assertEqual( - freq.curr * 1000 * 1000, sysctl("sysctl hw.cpufrequency")) + freq.current * 1000 * 1000, sysctl("sysctl hw.cpufrequency")) self.assertEqual( freq.min * 1000 * 1000, sysctl("sysctl hw.cpufrequency_min")) self.assertEqual( diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index d1b81838b..4cbdb056e 100755 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -700,13 +700,21 @@ def test_cpu_stats(self): @unittest.skipUnless(hasattr(psutil, "cpu_freq"), "platform not suported") def test_cpu_freq(self): - ls = psutil.cpu_freq() + def check_ls(ls): + for nt in ls: + self.assertLessEqual(nt.current, nt.max) + for name in nt._fields: + value = getattr(nt, name) + self.assertGreaterEqual(value, 0) + + ls = psutil.cpu_freq(percpu=True) if not TRAVIS: assert ls, ls - for nt in ls: - for name in nt._fields: - value = getattr(nt, name) - self.assertGreaterEqual(value, 0) + + check_ls([psutil.cpu_freq(percpu=False)]) + + if LINUX: + self.assertEqual(len(ls), psutil.cpu_count()) def test_os_constants(self): names = ["POSIX", "WINDOWS", "LINUX", "OSX", "FREEBSD", "OPENBSD",