Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CPU frequency support for FreeBSD #1369

Merged
merged 3 commits into from
Dec 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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