Skip to content

Commit

Permalink
Speed up cpu_frequncy() on Linux systems (giampaolo#1851).
Browse files Browse the repository at this point in the history
The change is about using /proc/cpuinfo when available. It provides
cached values for frequencies and one can fill up minimum and maximum
frequency from /sys/devices/system/cpu/cpufreq/policy/* sub-system
(which is fast).

Fixes giampaolo#1851.
  • Loading branch information
marxin committed Oct 15, 2020
1 parent d08f44b commit 5e7d22f
Showing 1 changed file with 48 additions and 33 deletions.
81 changes: 48 additions & 33 deletions psutil/_pslinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,41 +672,43 @@ def cpu_stats():
ctx_switches, interrupts, soft_interrupts, syscalls)


if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or \
os.path.exists("/sys/devices/system/cpu/cpu0/cpufreq"):
def cpu_freq():
"""Return frequency metrics for all CPUs.
Contrarily to other OSes, Linux updates these values in
real-time.
"""
def get_path(num):
for p in ("/sys/devices/system/cpu/cpufreq/policy%s" % num,
"/sys/devices/system/cpu/cpu%s/cpufreq" % num):
if os.path.exists(p):
return p
HAS_CPUFREQ = (os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or
os.path.exists("/sys/devices/system/cpu/cpu0/cpufreq"))

ret = []
for n in range(cpu_count_logical()):
path = get_path(n)
if not path:
continue

pjoin = os.path.join
curr = cat(pjoin(path, "scaling_cur_freq"), fallback=None)
if curr is None:
# Likely an old RedHat, see:
# https://github.com/giampaolo/psutil/issues/1071
curr = cat(pjoin(path, "cpuinfo_cur_freq"), fallback=None)
if curr is None:
raise NotImplementedError(
"can't find current frequency file")
curr = int(curr) / 1000
max_ = int(cat(pjoin(path, "scaling_max_freq"))) / 1000
min_ = int(cat(pjoin(path, "scaling_min_freq"))) / 1000
ret.append(_common.scpufreq(curr, min_, max_))
return ret
def _get_path(num):
"""Return frequency metrics for all CPUs.
Contrarily to other OSes, Linux updates these values in
real-time.
"""
for p in ("/sys/devices/system/cpu/cpufreq/policy%s" % num,
"/sys/devices/system/cpu/cpu%s/cpufreq" % num):
if os.path.exists(p):
return p


def _get_cpu_scaling_value(num, key):
"""Return frequncy value based on key for a NUMth CPU. """
if not HAS_CPUFREQ:
return 0.

path = _get_path(num)
if not path:
return 0.

pjoin = os.path.join
value = cat(pjoin(path, key), fallback=None)
if value is None and key == "scaling_cur_freq":
# Likely an old RedHat, see:
# https://github.com/giampaolo/psutil/issues/1071
value = cat(pjoin(path, key), fallback=None)
if value is None:
raise NotImplementedError(
"can't find current frequency file")
return int(value) / 1000


elif os.path.exists("/proc/cpuinfo"):
if os.path.exists("/proc/cpuinfo"):
def cpu_freq():
"""Alternate implementation using /proc/cpuinfo.
min and max frequencies are not available and are set to None.
Expand All @@ -716,7 +718,20 @@ def cpu_freq():
for line in f:
if line.lower().startswith(b'cpu mhz'):
key, value = line.split(b':', 1)
ret.append(_common.scpufreq(float(value), 0., 0.))
n = len(ret)
max_ = _get_cpu_scaling_value(n, "scaling_max_freq")
min_ = _get_cpu_scaling_value(n, "scaling_min_freq")
ret.append(_common.scpufreq(float(value), min_, max_))
return ret

elif HAS_CPUFREQ:
def cpu_freq():
ret = []
for n in range(cpu_count_logical()):
curr = _get_cpu_scaling_value(n, "scaling_cur_freq")
max_ = _get_cpu_scaling_value(n, "scaling_max_freq")
min_ = _get_cpu_scaling_value(n, "scaling_min_freq")
ret.append(_common.scpufreq(curr, min_, max_))
return ret

else:
Expand Down

0 comments on commit 5e7d22f

Please sign in to comment.