Skip to content

Commit

Permalink
Fix #1055, fix #1085, fix #1087.
Browse files Browse the repository at this point in the history
- no longer cache cpu_count() return value in Process.cpu_percent()
- in Process.cpu_percent(), guard against cpu_count() returning None and
  assume 1 instead
- add test cases
  • Loading branch information
giampaolo committed May 19, 2017
1 parent e20b347 commit e5a0811
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 7 deletions.
4 changes: 3 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
- 1047_: [Windows] Process username(): memory leak in case exception is thrown.
- 1048_: [Windows] users()'s host field report an invalid IP address.
- 1050_: [Windows] Process.memory_maps memory() leaks memory.
- 1055_: cpu_count() is no longer cached.
- 1055_: cpu_count() is no longer cached; this is useful on systems such as
Linux where CPUs can be disabled at runtime. This also reflects on
Process.cpu_percent() which no longer uses the cache.
- 1058_: fixed Python warnings.
- 1062_: disk_io_counters() and net_io_counters() raise TypeError if no disks
or NICs are installed on the system.
Expand Down
7 changes: 1 addition & 6 deletions psutil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@
POWER_TIME_UNLIMITED = _common.POWER_TIME_UNLIMITED
POWER_TIME_UNKNOWN = _common.POWER_TIME_UNKNOWN
_TOTAL_PHYMEM = None
_NUM_CPUS = None
_timer = getattr(time, 'monotonic', time.time)


Expand Down Expand Up @@ -1043,9 +1042,7 @@ def cpu_percent(self, interval=None):
blocking = interval is not None and interval > 0.0
if interval is not None and interval < 0:
raise ValueError("interval is not positive (got %r)" % interval)
# TODO: rarely cpu_count() may return None, meaning this will
# break. It's probably wise to fall back to 1.
num_cpus = _NUM_CPUS or cpu_count()
num_cpus = cpu_count() or 1

def timer():
return _timer() * num_cpus
Expand Down Expand Up @@ -1645,10 +1642,8 @@ def cpu_count(logical=True):
>>> psutil.cpu_count.cache_clear()
"""
global _NUM_CPUS
if logical:
ret = _psplatform.cpu_count_logical()
_NUM_CPUS = ret
else:
ret = _psplatform.cpu_count_physical()
return ret if ret >= 1 else None
Expand Down
6 changes: 6 additions & 0 deletions psutil/tests/test_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ def test_cpu_percent(self):
with self.assertRaises(ValueError):
p.cpu_percent(interval=-1)

def test_cpu_percent_numcpus_none(self):
# See: https://github.com/giampaolo/psutil/issues/1087
with mock.patch('psutil.cpu_count', return_value=None) as m:
psutil.Process().cpu_percent()
assert m.called

def test_cpu_times(self):
times = psutil.Process().cpu_times()
assert (times.user > 0.0) or (times.system > 0.0), times
Expand Down
12 changes: 12 additions & 0 deletions psutil/tests/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,18 @@ def test_cpu_count(self):
self.assertGreaterEqual(physical, 1)
self.assertGreaterEqual(logical, physical)

def test_cpu_count_none(self):
# https://github.com/giampaolo/psutil/issues/1085
for val in (-1, 0, None):
with mock.patch('psutil._psplatform.cpu_count_logical',
return_value=val) as m:
self.assertIsNone(psutil.cpu_count())
assert m.called
with mock.patch('psutil._psplatform.cpu_count_physical',
return_value=val) as m:
self.assertIsNone(psutil.cpu_count(logical=False))
assert m.called

def test_cpu_times(self):
# Check type, value >= 0, str().
total = 0
Expand Down

0 comments on commit e5a0811

Please sign in to comment.