Python: Find Your System's Biggest CPU Hogs
My machine has recently developed an overheating problem. I haven't found a solution for that yet -- you'd think Linux would have a way to automatically kill or suspend processes based on CPU temperature, but apparently not -- but my investigations led me down one interesting road: how to write a Python script that finds CPU hogs.
The psutil module can get a list
of processes with psutil.process_iter()
, which returns
Process
objects that have a cpu_percent()
call.
Great! Except it always returns 0.0, even for known hogs like Firefox,
or if you start up a VLC and make it play video scaled to the monitor size.
That's because cpu_percent()
needs to run twice,
with an interval in between:
it records the elapsed run time and sees how much it changes.
You can pass an interval to cpu_percent()
(the units aren't documented, but apparently they're seconds).
But if you're calling it on more than one process -- as you usually
will be -- it's better not to wait for each process.
You have to wait at least a quarter of a second to get useful
numbers, and longer is better. If you do that for every process on the
system, you'll be waiting a long time.
Instead, use cpu_percent()
in non-blocking mode.
Pass None as the interval (or leave it blank since None is
the default), then loop over the process list and call
proc.cpu_percent(None)
on each process, throwing away the
results the first time.
Then sleep for a while and repeat the loop: the second time,
cpu_percent()
will give you useful numbers.
def hoglist(delay=5): '''Return a list of processes using a nonzero CPU percentage during the interval specified by delay (seconds), sorted so the biggest hog is first. ''' proccesses = list(psutil.process_iter()) for proc in proccesses: proc.cpu_percent(None) # non-blocking; throw away first bogus value print("Sleeping ...") sys.stdout.flush() time.sleep(delay) print() procs = [] for proc in proccesses: percent = proc.cpu_percent(None) if percent: procs.append((proc.name(), percent)) print(procs) procs.sort(key=lambda x: x[1], reverse=True) return procs if __name__ == '__main__': prohogscs = hoglist() for p in hogs: print("%20s: %5.2f" % p)
It's a useful trick. Though actually applying this to a daemon that responds to temperature, to solve my overheating problem, is more complicated. For one thing, you need rules about special processes. If your Firefox goes wonky and starts making your X server take lots of CPU time, you want to suspend Firefox, not the X server.
[ 15:54 Jan 18, 2019 More programming | permalink to this entry | ]