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

Cpu freq fix #1481

Merged
merged 3 commits into from Apr 5, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -11,6 +11,7 @@ syntax: glob
*.rej
*.so
*.swp
.failed-tests.txt
.cache/
.idea/
.tox/
Expand Down
26 changes: 11 additions & 15 deletions psutil/_pslinux.py
Expand Up @@ -688,23 +688,19 @@ def cpu_freq():
Contrarily to other OSes, Linux updates these values in
real-time.
"""
# scaling_* files seem preferable to cpuinfo_*, see:
# http://unix.stackexchange.com/a/87537/168884
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

ret = []
ls = glob.glob("/sys/devices/system/cpu/cpufreq/policy*")
if ls:
# 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:]))
else:
# https://github.com/giampaolo/psutil/issues/981
ls = glob.glob("/sys/devices/system/cpu/cpu[0-9]*/cpufreq")
ls.sort(key=lambda x: int(re.search('[0-9]+', x).group(0)))
for n in range(cpu_count_logical()):
path = get_path(n)
if not path:
continue

pjoin = os.path.join
for path in ls:
pjoin = os.path.join
curr = cat(pjoin(path, "scaling_cur_freq"), fallback=None)
if curr is None:
# Likely an old RedHat, see:
Expand Down
81 changes: 47 additions & 34 deletions psutil/tests/test_linux.py
Expand Up @@ -10,7 +10,6 @@
import collections
import contextlib
import errno
import glob
import io
import os
import re
Expand Down Expand Up @@ -698,27 +697,26 @@ class TestSystemCPUFrequency(unittest.TestCase):

@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
def test_emulate_no_files(self):
with mock.patch("psutil._pslinux.glob.glob", return_value=[]):
with mock.patch("os.path.exists", return_value=False):
self.assertIsNone(psutil.cpu_freq())

@unittest.skipIf(TRAVIS, "fails on Travis")
@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
def test_emulate_use_second_file(self):
# https://github.com/giampaolo/psutil/issues/981
def glob_mock(pattern):
if pattern.startswith("/sys/devices/system/cpu/cpufreq/policy"):
flags.append(None)
return []
def path_exists_mock(path):
if path.startswith("/sys/devices/system/cpu/cpufreq/policy"):
return False
else:
flags.append(None)
return orig_glob(pattern)
return orig_exists(path)

flags = []
orig_glob = glob.glob
with mock.patch("psutil._pslinux.glob.glob", side_effect=glob_mock,
orig_exists = os.path.exists
with mock.patch("os.path.exists", side_effect=path_exists_mock,
create=True):
assert psutil.cpu_freq()
self.assertEqual(len(flags), 2)
self.assertEqual(len(flags), psutil.cpu_count(logical=True))

@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
def test_emulate_use_cpuinfo(self):
Expand Down Expand Up @@ -752,11 +750,14 @@ def path_exists_mock(path):
@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
def test_emulate_data(self):
def open_mock(name, *args, **kwargs):
if name.endswith('/scaling_cur_freq'):
if (name.endswith('/scaling_cur_freq') and
name.startswith("/sys/devices/system/cpu/cpufreq/policy")):
return io.BytesIO(b"500000")
elif name.endswith('/scaling_min_freq'):
elif (name.endswith('/scaling_min_freq') and
name.startswith("/sys/devices/system/cpu/cpufreq/policy")):
return io.BytesIO(b"600000")
elif name.endswith('/scaling_max_freq'):
elif (name.endswith('/scaling_max_freq') and
name.startswith("/sys/devices/system/cpu/cpufreq/policy")):
return io.BytesIO(b"700000")
else:
return orig_open(name, *args, **kwargs)
Expand All @@ -765,8 +766,7 @@ def open_mock(name, *args, **kwargs):
patch_point = 'builtins.open' if PY3 else '__builtin__.open'
with mock.patch(patch_point, side_effect=open_mock):
with mock.patch(
'glob.glob',
return_value=['/sys/devices/system/cpu/cpufreq/policy0']):
'os.path.exists', return_value=True):
freq = psutil.cpu_freq()
self.assertEqual(freq.current, 500.0)
self.assertEqual(freq.min, 600.0)
Expand All @@ -775,26 +775,41 @@ def open_mock(name, *args, **kwargs):
@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
def test_emulate_multi_cpu(self):
def open_mock(name, *args, **kwargs):
if name.endswith('/scaling_cur_freq'):
n = name
if (n.endswith('/scaling_cur_freq') and
n.startswith("/sys/devices/system/cpu/cpufreq/policy0")):
return io.BytesIO(b"100000")
elif name.endswith('/scaling_min_freq'):
elif (n.endswith('/scaling_min_freq') and
n.startswith("/sys/devices/system/cpu/cpufreq/policy0")):
return io.BytesIO(b"200000")
elif name.endswith('/scaling_max_freq'):
elif (n.endswith('/scaling_max_freq') and
n.startswith("/sys/devices/system/cpu/cpufreq/policy0")):
return io.BytesIO(b"300000")
elif (n.endswith('/scaling_cur_freq') and
n.startswith("/sys/devices/system/cpu/cpufreq/policy1")):
return io.BytesIO(b"400000")
elif (n.endswith('/scaling_min_freq') and
n.startswith("/sys/devices/system/cpu/cpufreq/policy1")):
return io.BytesIO(b"500000")
elif (n.endswith('/scaling_max_freq') and
n.startswith("/sys/devices/system/cpu/cpufreq/policy1")):
return io.BytesIO(b"600000")
else:
return orig_open(name, *args, **kwargs)

orig_open = open
patch_point = 'builtins.open' if PY3 else '__builtin__.open'
policies = ['/sys/devices/system/cpu/cpufreq/policy0',
'/sys/devices/system/cpu/cpufreq/policy1',
'/sys/devices/system/cpu/cpufreq/policy2']
with mock.patch(patch_point, side_effect=open_mock):
with mock.patch('glob.glob', return_value=policies):
freq = psutil.cpu_freq()
self.assertEqual(freq.current, 100.0)
self.assertEqual(freq.min, 200.0)
self.assertEqual(freq.max, 300.0)
with mock.patch('os.path.exists', return_value=True):
with mock.patch('psutil._pslinux.cpu_count_logical',
return_value=2):
freq = psutil.cpu_freq(percpu=True)
self.assertEqual(freq[0].current, 100.0)
self.assertEqual(freq[0].min, 200.0)
self.assertEqual(freq[0].max, 300.0)
self.assertEqual(freq[1].current, 400.0)
self.assertEqual(freq[1].min, 500.0)
self.assertEqual(freq[1].max, 600.0)

@unittest.skipIf(TRAVIS, "fails on Travis")
@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
Expand All @@ -810,14 +825,12 @@ def open_mock(name, *args, **kwargs):

orig_open = open
patch_point = 'builtins.open' if PY3 else '__builtin__.open'
policies = ['/sys/devices/system/cpu/cpufreq/policy0',
'/sys/devices/system/cpu/cpufreq/policy1',
'/sys/devices/system/cpu/cpufreq/policy2']

with mock.patch(patch_point, side_effect=open_mock):
with mock.patch('glob.glob', return_value=policies):
freq = psutil.cpu_freq()
self.assertEqual(freq.current, 200)
with mock.patch('os.path.exists', return_value=True):
with mock.patch('psutil._pslinux.cpu_count_logical',
return_value=1):
freq = psutil.cpu_freq()
self.assertEqual(freq.current, 200)

# Also test that NotImplementedError is raised in case no
# current freq file is present.
Expand All @@ -833,7 +846,7 @@ def open_mock(name, *args, **kwargs):
orig_open = open
patch_point = 'builtins.open' if PY3 else '__builtin__.open'
with mock.patch(patch_point, side_effect=open_mock):
with mock.patch('glob.glob', return_value=policies):
with mock.patch('os.path.exists', return_value=True):
self.assertRaises(NotImplementedError, psutil.cpu_freq)


Expand Down