Finding the right CPU stats

In the sysmon I tried

(echo $'MEM\tCMD\tCPU'
ps -Ao rss,comm,pcpu | sort -rn | head -n 10 | sed 's/\([a-z]\) \([a-z]\)/\1_\2/g' ) | awk '{printf "%-9.9s%-15.15s%6.6s\n",$1,$2,$3}'

beyond head it’s just for formatting. (and I get processes with spaces in the filename)

However, as man ps says pcpu is just process’ running time / time it spent in CPU.

Run a process at 0% for 1 hour => 0%
Peak it for 5 minutes and it will go to 1% or something. And not 100% what you really want.

Side tracking a bit… On the forums a while ago there was a post that described how to get total CPU with /proc/stat. I converted it to bash, try it out:

previdle=0
prevtotal=0
while sleep 1; do
eval $(awk '/^cpu /{print "idle=" $5 "; total=" $2+$3+$4+$5 }' /proc/stat)
echo -en '\r'$((100* ( ($total-$prevtotal) - ($idle-$previdle) ) / ($total - $prevtotal) ))
previdle=$idle
prevtotal=$total
done

It will print the current percentage in the same spot.

For a per process usage there is /proc/[0-9]*/stat. It is in the same unit as the above. That means you can take the usage of the interval from above, the previous usage of the process, and use it to get a percentage of that process since the last interval. Kind of like htop.


#! /bin/bash
IFS="
"
previdle=0
prevtotal=0
while true; do
memused=$(free -m | sed -n '3s/^[^0-9]*\([0-9]*\).*/\1/p')

eval $(awk '/^cpu /{print "idle=" $5 "; total=" $2+$3+$4+$5 }' /proc/stat)
intervaltotal=$((total-prevtotal))
echo -e "$memused\tTOTAL\t$((100*( (intervaltotal) - ($idle-$previdle) ) / (intervaltotal) ))" > /tmp/recentcpu.new
previdle=$idle
prevtotal=$total

for line in $(sed 's/ /_/2;s/)_/ /g;s/[()]//g' /proc/[0-9]*/stat 2>/dev/null | awk '{CONVFMT="%d"; print "process=" $2, ";pid=" $1 , ";proctime=" $14+$15+$16+$17, ";rss=" $24*4/1024}'); do
eval $line
prevproc=${array[$pid]:-0}
echo -e "$rss\t$process\t$(( ( 100*($proctime-$prevproc) / intervaltotal ) ))" >> /tmp/recentcpu.new
array[$pid]=$proctime
done
mv /tmp/recentcpu.new /tmp/recentcpu
sleep 5
done

notes: The sed line for the /proc/*/stat allows for 0 or 1 spaces in the process name. The process time is four values, I don’t know if they are the right ones to use, especially the last two. Look at man 5 ps for a definition. The rss value is in pages, for me a page turned out to be 4 bytes, I don’t know if this is standard it’s the first time I heard of it.

It outputs MB memory used (non-cached RSS mem, the good stuff) / process name / cpu% used.

It outputs to a file, so you can run it in the background and get the values from a script. For quick checking you can use:
while true; do clear; sort -rn -k 3,3 /tmp/recentcpu | head -n 10;sleep 5; done

Or with some nice formatting in your own script
(echo 'MEM CMD CPU'; sort -rn -k 3,3 /tmp/recentcpu | head -n 10) | awk '{printf "%-6.6s%-15.15s%4.4s\n",$1,$2,$3}'

I am comparing the results with htop / top / and conky. It is a bit hard to see, but it looks like htop and top are *2, and conky and the above script seem similar. May be a dual core issue? I may look at conky source to see how they get the values.

This entry was posted in Programming. Bookmark the permalink.

One Response to Finding the right CPU stats

  1. procyon says:

    And if the output is a bit confusing with TOTAL appearing like an entry, you put it above the MEM CMD CPU line, add some lines too, and it will look much clearer
    sort -rn -k 3,3 /tmp/recentcpu | head -n 10 | sed '1a MEM--- CMD------------ -CPU
    ' | awk '{printf "%-6.6s%-15.15s%4.4s\n",$1,$2,$3}'

    Or even, head is redundant, just quit sed early, and secondary sorting is also possible, so you see the highest memory user with 0% CPU:

    sort -rn -k 3,3 -k 1,1 /tmp/recentcpu | sed '1a MEM--- CMD------------ -CPU
    9q' | awk '{printf "%-6.6s%-15.15s%4.4s\n",$1,$2,$3}'

Comments are closed.