summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Manuskin <amanusk@protonmail.com>2018-12-01 20:14:53 +0200
committerGiampaolo Rodola <g.rodola@gmail.com>2018-12-01 19:14:53 +0100
commit459556dd1e2979cdee22177339ced0761caf4c83 (patch)
tree50fc0c6ef3dd355d78220f8c620271ca81a8c03c
parenta3d6a28be2631cae7f78287b0742bba36338a745 (diff)
downloadpsutil-459556dd1e2979cdee22177339ced0761caf4c83.tar.gz
Add CPU frequency support for FreeBSD (#1369)
Add CPU frequency support for FreeBSD (patch by @amanusk)
-rw-r--r--psutil/_psbsd.py26
-rw-r--r--psutil/_psutil_bsd.c2
-rw-r--r--psutil/arch/freebsd/specific.c33
-rw-r--r--psutil/arch/freebsd/specific.h1
-rwxr-xr-xpsutil/tests/test_bsd.py18
-rwxr-xr-xpsutil/tests/test_contracts.py2
6 files changed, 81 insertions, 1 deletions
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index 0727dd2e..d3ce7b5c 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -455,6 +455,32 @@ if FREEBSD:
return ret
+ def cpu_freq():
+ """
+ Return frequency metrics for CPUs. Currently, only CPU 0 is supported
+ by FreeBSD, all other cores match the frequency of CPU 0.
+ """
+ ret = []
+ num_cpus = cpu_count_logical()
+ for cpu in range(num_cpus):
+ try:
+ current, available_freq = cext.cpu_frequency(cpu)
+ except NotImplementedError:
+ continue
+ min_freq = None
+ max_freq = None
+ if available_freq:
+ try:
+ min_freq = int(available_freq.split(" ")[-1].split("/")[0])
+ except(IndexError, ValueError):
+ pass
+ try:
+ max_freq = int(available_freq.split(" ")[0].split("/")[0])
+ except(IndexError, ValueError):
+ pass
+ ret.append(_common.scpufreq(current, min_freq, max_freq))
+ return ret
+
# =====================================================================
# --- other system functions
diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c
index 6b366f13..dce157f5 100644
--- a/psutil/_psutil_bsd.c
+++ b/psutil/_psutil_bsd.c
@@ -983,6 +983,8 @@ PsutilMethods[] = {
"Return battery information."},
{"sensors_cpu_temperature", psutil_sensors_cpu_temperature, METH_VARARGS,
"Return temperature information for a given CPU core number."},
+ {"cpu_frequency", psutil_cpu_freq, METH_VARARGS,
+ "Return frequency of a given CPU"},
#endif
// --- others
diff --git a/psutil/arch/freebsd/specific.c b/psutil/arch/freebsd/specific.c
index 14be26b3..70dc7f2c 100644
--- a/psutil/arch/freebsd/specific.c
+++ b/psutil/arch/freebsd/specific.c
@@ -1046,3 +1046,36 @@ error:
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
+
+
+/*
+ * Return frequency information of a given CPU
+ */
+PyObject *
+psutil_cpu_freq(PyObject *self, PyObject *args) {
+ int current;
+ int core;
+ char sensor[26];
+ char available_freq_levels[1000];
+ size_t size = sizeof(current);
+
+ if (! PyArg_ParseTuple(args, "i", &core))
+ return NULL;
+ sprintf(sensor, "dev.cpu.%d.freq", core);
+ if (sysctlbyname(sensor, &current, &size, NULL, 0))
+ goto error;
+
+ size = sizeof(available_freq_levels);
+ // In case of failure, an empty string is returned
+ sprintf(sensor, "dev.cpu.%d.freq_levels", core);
+ sysctlbyname(sensor, &available_freq_levels, &size, NULL, 0);
+
+ return Py_BuildValue("is", current, available_freq_levels);
+
+error:
+ if (errno == ENOENT)
+ PyErr_SetString(PyExc_NotImplementedError, "Unable to read frequency");
+ else
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+}
diff --git a/psutil/arch/freebsd/specific.h b/psutil/arch/freebsd/specific.h
index cb71ff61..875c8166 100644
--- a/psutil/arch/freebsd/specific.h
+++ b/psutil/arch/freebsd/specific.h
@@ -30,4 +30,5 @@ PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
#if defined(PSUTIL_FREEBSD)
PyObject* psutil_sensors_battery(PyObject* self, PyObject* args);
PyObject* psutil_sensors_cpu_temperature(PyObject* self, PyObject* args);
+PyObject* psutil_cpu_freq(PyObject* self, PyObject* args);
#endif
diff --git a/psutil/tests/test_bsd.py b/psutil/tests/test_bsd.py
index df43a023..87feb147 100755
--- a/psutil/tests/test_bsd.py
+++ b/psutil/tests/test_bsd.py
@@ -250,6 +250,24 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
if len(tested) != 2:
raise RuntimeError("couldn't find lines match in procstat out")
+ # --- cpu_freq(); tests against sysctl
+ def test_cpu_frequency_against_sysctl(self):
+ # Currently only cpu 0 is frequency is supported in FreeBSD
+ # All other cores use the same frequency
+ sensor = "dev.cpu.0.freq"
+ sysctl_result = int(sysctl(sensor))
+ self.assertEqual(psutil.cpu_freq().current, sysctl_result)
+
+ sensor = "dev.cpu.0.freq_levels"
+ sysctl_result = sysctl(sensor)
+ # sysctl returns a string of the format:
+ # <freq_level_1>/<voltage_level_1> <freq_level_2>/<voltage_level_2>...
+ # Ordered highest available to lowest available
+ max_freq = int(sysctl_result.split()[0].split("/")[0])
+ min_freq = int(sysctl_result.split()[-1].split("/")[0])
+ self.assertEqual(psutil.cpu_freq().max, max_freq)
+ self.assertEqual(psutil.cpu_freq().min, min_freq)
+
# --- virtual_memory(); tests against sysctl
@retry_before_failing()
diff --git a/psutil/tests/test_contracts.py b/psutil/tests/test_contracts.py
index 8ff41e5b..78e6ba22 100755
--- a/psutil/tests/test_contracts.py
+++ b/psutil/tests/test_contracts.py
@@ -115,7 +115,7 @@ class TestAvailability(unittest.TestCase):
(os.path.exists("/sys/devices/system/cpu/cpufreq") or
os.path.exists("/sys/devices/system/cpu/cpu0/cpufreq")))
self.assertEqual(hasattr(psutil, "cpu_freq"),
- linux or MACOS or WINDOWS)
+ linux or MACOS or WINDOWS or FREEBSD)
def test_sensors_temperatures(self):
self.assertEqual(