diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2016-12-02 02:46:35 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2016-12-02 02:46:35 +0100 |
commit | 8d83d5f3669e00af4f50a4434fd0d3e26d0c96a4 (patch) | |
tree | 34c49e9b6e7966ad94a220b579fb988be1744d10 | |
parent | 6967c8d6cf8072a2bcd911e47ebbfa37d606394e (diff) | |
download | psutil-8d83d5f3669e00af4f50a4434fd0d3e26d0c96a4.tar.gz |
#941: implement cpu_freq() for Linux
-rw-r--r-- | psutil/__init__.py | 13 | ||||
-rw-r--r-- | psutil/_common.py | 2 | ||||
-rw-r--r-- | psutil/_pslinux.py | 35 | ||||
-rwxr-xr-x | psutil/tests/test_system.py | 10 |
4 files changed, 60 insertions, 0 deletions
diff --git a/psutil/__init__.py b/psutil/__init__.py index 3269c857..d3d7bda2 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -1846,6 +1846,19 @@ def cpu_stats(): return _psplatform.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. + """ + return _psplatform.cpu_freq() + + # ===================================================================== # --- system memory related functions # ===================================================================== diff --git a/psutil/_common.py b/psutil/_common.py index 3879a1d7..a8ae27ac 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -156,6 +156,8 @@ snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu']) # psutil.cpu_stats() scpustats = namedtuple( 'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls']) +# psutil.cpu_freq() +scpufreq = namedtuple('scpufreq', ['curr', 'min', 'max']) # --- for Process methods diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index 91fdae4f..c2247ae0 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -9,6 +9,7 @@ from __future__ import division import base64 import errno import functools +import glob import os import re import socket @@ -133,6 +134,8 @@ TCP_STATUSES = { "0B": _common.CONN_CLOSING } +_DEFAULT = object() + # ===================================================================== # -- exceptions @@ -276,6 +279,18 @@ def set_scputimes_ntuple(procfs_path): return scputimes +def cat(fname, fallback=_DEFAULT, binary=True): + """Return file content.""" + try: + with open_binary(fname) if binary else open_text(fname) as f: + return f.read() + except IOError: + if fallback != _DEFAULT: + return fallback + else: + raise + + try: scputimes = set_scputimes_ntuple("/proc") except Exception: @@ -607,6 +622,26 @@ def cpu_stats(): ctx_switches, interrupts, soft_interrupts, syscalls) +if os.path.exists("/sys/devices/system/cpu/cpufreq"): + + def cpu_freq(): + # scaling_* files seem preferable to cpuinfo_*, see: + # http://unix.stackexchange.com/a/87537/168884 + ret = [] + ls = glob.glob("/sys/devices/system/cpu/cpufreq/policy[0-9]*") + # Sort the list so that '10' comes after '2'. This should + # ensure the CPU order is consistent with other CPU functions + # having a 'percpu' argument and returning results for multiple + # CPUs (cpu_times(), cpu_percent(), cpu_times_percent()). + ls.sort(key=lambda x: int(os.path.basename(x)[6:])) + for path in ls: + curr = int(cat(os.path.join(path, "scaling_cur_freq"))) / 1000 + max_ = int(cat(os.path.join(path, "scaling_max_freq"))) / 1000 + min_ = int(cat(os.path.join(path, "scaling_min_freq"))) / 1000 + ret.append(_common.scpufreq(curr, min_, max_)) + return ret + + # ===================================================================== # --- network # ===================================================================== diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index e2220be4..ac63dc7c 100755 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -697,6 +697,16 @@ class TestSystemAPIs(unittest.TestCase): if name in ('ctx_switches', 'interrupts'): self.assertGreater(value, 0) + @unittest.skipUnless(hasattr(psutil, "cpu_freq"), + "platform not suported") + def test_cpu_freq(self): + ls = psutil.cpu_freq() + assert ls, ls + for nt in ls: + for name in nt._fields: + value = getattr(nt, name) + self.assertGreaterEqual(value, 0) + def test_os_constants(self): names = ["POSIX", "WINDOWS", "LINUX", "OSX", "FREEBSD", "OPENBSD", "NETBSD", "BSD", "SUNOS"] |