Skip to content

Commit

Permalink
Add CPU frequency support for FreeBSD (#1369)
Browse files Browse the repository at this point in the history
Add CPU frequency support for FreeBSD (patch by @amanusk)
  • Loading branch information
amanusk authored and giampaolo committed Dec 1, 2018
1 parent a3d6a28 commit 459556d
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 1 deletion.
26 changes: 26 additions & 0 deletions psutil/_psbsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,32 @@ def sensors_temperatures():

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
Expand Down
2 changes: 2 additions & 0 deletions psutil/_psutil_bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 33 additions & 0 deletions psutil/arch/freebsd/specific.c
Original file line number Diff line number Diff line change
Expand Up @@ -1046,3 +1046,36 @@ psutil_sensors_cpu_temperature(PyObject *self, PyObject *args) {
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;
}
1 change: 1 addition & 0 deletions psutil/arch/freebsd/specific.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
18 changes: 18 additions & 0 deletions psutil/tests/test_bsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,24 @@ def test_proc_cpu_times(self):
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()
Expand Down
2 changes: 1 addition & 1 deletion psutil/tests/test_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def test_cpu_freq(self):
(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(
Expand Down

0 comments on commit 459556d

Please sign in to comment.