summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2016-12-02 02:46:35 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2016-12-02 02:46:35 +0100
commit8d83d5f3669e00af4f50a4434fd0d3e26d0c96a4 (patch)
tree34c49e9b6e7966ad94a220b579fb988be1744d10
parent6967c8d6cf8072a2bcd911e47ebbfa37d606394e (diff)
downloadpsutil-8d83d5f3669e00af4f50a4434fd0d3e26d0c96a4.tar.gz
#941: implement cpu_freq() for Linux
-rw-r--r--psutil/__init__.py13
-rw-r--r--psutil/_common.py2
-rw-r--r--psutil/_pslinux.py35
-rwxr-xr-xpsutil/tests/test_system.py10
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"]