Skip to content

Commit bcd619e

Browse files
committed
perf: Process.cpu_percent() no longer calls cpu_count()
1 parent 33acd63 commit bcd619e

2 files changed

Lines changed: 17 additions & 26 deletions

File tree

psutil/__init__.py

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,21 +1236,16 @@ def cpu_percent(self, interval: float | None = None) -> float:
12361236
if interval is not None and interval < 0:
12371237
msg = f"interval is not positive (got {interval!r})"
12381238
raise ValueError(msg)
1239-
num_cpus = cpu_count() or 1
1240-
1241-
def timer():
1242-
return _timer() * num_cpus
1243-
12441239
if blocking:
1245-
st1 = timer()
1240+
st1 = _timer()
12461241
pt1 = self._proc.cpu_times()
12471242
time.sleep(interval)
1248-
st2 = timer()
1243+
st2 = _timer()
12491244
pt2 = self._proc.cpu_times()
12501245
else:
12511246
st1 = self._last_sys_cpu_times
12521247
pt1 = self._last_proc_cpu_times
1253-
st2 = timer()
1248+
st2 = _timer()
12541249
pt2 = self._proc.cpu_times()
12551250
if st1 is None or pt1 is None:
12561251
self._last_sys_cpu_times = st2
@@ -1264,31 +1259,24 @@ def timer():
12641259
self._last_proc_cpu_times = pt2
12651260

12661261
try:
1267-
# This is the utilization split evenly between all CPUs.
1268-
# E.g. a busy loop process on a 2-CPU-cores system at this
1269-
# point is reported as 50% instead of 100%.
1270-
overall_cpus_percent = (delta_proc / delta_time) * 100
1271-
except ZeroDivisionError:
1272-
# interval was too low
1273-
return 0.0
1274-
else:
1275-
# Note 1:
1276-
# in order to emulate "top" we multiply the value for the num
1277-
# of CPU cores. This way the busy process will be reported as
1262+
# The value is deliberately not split evenly between logical
1263+
# CPUs, so that we emulate "top": a busy loop is reported as
12781264
# having 100% (or more) usage.
12791265
#
1280-
# Note 2:
1266+
# Note 1:
12811267
# taskmgr.exe on Windows differs in that it will show 50%
12821268
# instead.
12831269
#
1284-
# Note 3:
1270+
# Note 2:
12851271
# a percentage > 100 is legitimate as it can result from a
12861272
# process with multiple threads running on different CPU
12871273
# cores (top does the same), see:
12881274
# http://stackoverflow.com/questions/1032357
12891275
# https://github.com/giampaolo/psutil/issues/474
1290-
single_cpu_percent = overall_cpus_percent * num_cpus
1291-
return round(single_cpu_percent, 1)
1276+
return round((delta_proc / delta_time) * 100, 1)
1277+
except ZeroDivisionError:
1278+
# interval was too low
1279+
return 0.0
12921280

12931281
@_use_prefetch
12941282
@memoize_when_activated

tests/test_process.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,12 @@ def test_cpu_percent(self):
144144

145145
def test_cpu_percent_numcpus_none(self):
146146
# See: https://github.com/giampaolo/psutil/issues/1087
147-
with mock.patch('psutil.cpu_count', return_value=None) as m:
148-
psutil.Process().cpu_percent()
149-
assert m.called
147+
# cpu_percent() must not depend on cpu_count(), which is allowed
148+
# to return None.
149+
with mock.patch('psutil.cpu_count', return_value=None):
150+
p = psutil.Process()
151+
p.cpu_percent()
152+
assert isinstance(p.cpu_percent(), float)
150153

151154
def test_cpu_times(self):
152155
times = psutil.Process().cpu_times()

0 commit comments

Comments
 (0)