HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Calculate CPU% by process from /proc/stat and /proc/<pid>/stat

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
processpidprocstatcalculateandcpufrom

Problem

We don't have the possibility to install modules like psutil on some boxes, thus I decided to write a simple script to calculate the CPU percentage by the given PID.

It uses /proc/stat to get CPU times and /proc//stat to get the process CPU usage.

I added top output here, just to compare results and to be sure it's (about) correct. But - I don't like to use external utilities in Python scripts, thus top will be removed.

  • OS: CentOS 6.5



  • Python: 2.6.6



Next - it calculates % of CPU, taken by this process:

```
#!/usr/bin/env python

import sys
import os
import time
import subprocess

if len(sys.argv) == 2:
pid = sys.argv[1]
else:
print('No PID specified. Usage: %s ' % os.path.basename(__file__))
sys.exit(1)

def proct(pid):
try:
with open(os.path.join('/proc/', pid, 'stat'), 'r') as pidfile:
proctimes = pidfile.readline()
# get utime from /proc//stat, 14 item
utime = proctimes.split(' ')[13]
# get stime from proc//stat, 15 item
stime = proctimes.split(' ')[14]
# count total process used time
proctotal = int(utime) + int(stime)
return(float(proctotal))
except IOError as e:
print('ERROR: %s' % e)
sys.exit(2)

def cput():
try:
with open('/proc/stat', 'r') as procfile:
cputimes = procfile.readline()
cputotal = 0
# count from /proc/stat: user, nice, system, idle, iowait, irc, softirq, steal, guest
for i in cputimes.split(' ')[2:]:
i = int(i)
cputotal = (cputotal + i)
return(float(cputotal))
except IOError as e:
print('ERROR: %s' % e)
sys.exit(3)

# assign start values before loop them
proctotal = proct(pid)
cputotal = cput()

try:
while True:

# for test, to compare results
proc = subprocess.Popen("top -p %s -b -n 1 | grep -w mysql | awk '{print $9}'" % pid, shell=True, stdout=

Solution

You have code outside of functions or an if __name__ == "__main__" guard (which isn't ideal in itself), both above and below the various function definitions, which makes the code relatively difficult to follow. I would structure the script as follows:

import os
import subprocess
import sys
import time

def proct(pid):
    ...

def cput():
    ...

def main(pid):
    ...

def parse_args():
    ...
    return pid

if __name__ == "__main__":
    main(parse_args())


Now if you want to import this functionality elsewhere, it's easy. Also, note that I have made the imports alphabetical, per the style guide.

I would factor out any temporary variables, e.g.

proctotal = int(utime) + int(stime)
return(float(proctotal))


can be written:

return float(int(utime) + int(stime))


Try not to do the same thing twice, e.g.

proctimes = pidfile.readline()
utime = proctimes.split(' ')[13]
stime = proctimes.split(' ')[14]


could be rewritten

proctimes = pidfile.readline().split(' ')
utime = proctime[13] # you could also call int here
stime = proctime[14]


which only calls str.split once.

Consider adding docstrings to your functions, rather than the inline comments (some of which are redundant - utime = proctimes.split(' ')[13] does not need the explanation # get utime from /proc//stat, 14 item, which just adds an extra line to read). Better function names would also help with clarity - e.g. cpu_total rather than cput.

The main part of cput:

cputimes = procfile.readline()
cputotal = 0
for i in cputimes.split(' ')[2:]:
    i = int(i)
    cputotal = (cputotal + i)
return(float(cputotal))


can be rewritten in a functional style:

return sum(map(float, procfile.readline().split(' ')[2:]))


or using a generator expression:

return sum(float(s) for s in procfile.readline().split(' ')[2:])

Code Snippets

import os
import subprocess
import sys
import time

def proct(pid):
    ...

def cput():
    ...

def main(pid):
    ...

def parse_args():
    ...
    return pid

if __name__ == "__main__":
    main(parse_args())
proctotal = int(utime) + int(stime)
return(float(proctotal))
return float(int(utime) + int(stime))
proctimes = pidfile.readline()
utime = proctimes.split(' ')[13]
stime = proctimes.split(' ')[14]
proctimes = pidfile.readline().split(' ')
utime = proctime[13] # you could also call int here
stime = proctime[14]

Context

StackExchange Code Review Q#67904, answer score: 8

Revisions (0)

No revisions yet.