On Thu, Feb 03, 2011 at 01:09:04PM +0100, Michael Schwartzkopff wrote:
> On Thursday 03 February 2011 12:35:34 Ulrich Windl wrote:
> > Hi!
> >
> > I'm starting to explore Linux-HA. Examining one of the monitors, I think
> > things could be made much more efficient. For example: To get the percent
> > of idle CPU the monitor uses 4 processes: top -b -n2 | grep Cpu | tail -1
> > | awk -F",|\.[0-9]%id" '{ print $4 }'
> >
> > However awk can do the effect of grep and tail as well. My first attempt is
> > this: top -b -n2 | awk -F",|\.[0-9]%id" '/^Cpu/{ print $4; exit }'
> >
> > My second attempt uses /proc/stat instead, avoiding the slow top process:
> > awk '$1 == "cpu" { print $7; exit }' /proc/stat
> >
> > time (top -b -n2 | grep Cpu | tail -1 | awk -F",|\.[0-9]%id" '{ print $4
> > }') awk: warning: escape sequence `\.' treated as plain `.'
> > 99
> >
> > real 0m3.533s
> > user 0m0.008s
> > sys 0m0.008s
> >
> > time (top -b -n2| awk -F",|\.[0-9]%id" '/^Cpu/{ print $4; exit }')
> > awk: warning: escape sequence `\.' treated as plain `.'
> > 99
Outch. Big FAIL here already ;-)
> >
> > real 0m0.518s
> > user 0m0.000s
> > sys 0m0.008s
> >
> > time awk '$1 == "cpu" { print $7; exit }' /proc/stat
> > 98
And you actually believe that this was the equivalent of the above
top | etc pipe ?
See below.
> > real 0m0.004s
> > user 0m0.000s
> > sys 0m0.000s
> >
> > Regards,
> > Ulrich
>
> Hi,
>
> good idea. The only problem it that the information in /proc/stats is in
> ticks
> and does not give you an absolute value. So you would have to calculate the
> difference yourself, which makes the task much more difficult.
1) /proc/stat is linux specific.
2) /proc/stat is what top samles on linux ;-)
3) it is in "USER_HZ", so it's in centi secs,
which makes it easy enough to calculate a meaningfull difference.
besides, as long as it is _any_ consistent unit,
the unit does not matter, as it is in both nominator and denominator
;-)
4) time top -b -n2 | pipe
vs. time cat /proc/stats
...
You do realize that to get any meaningfull measure about "current"
cpu usage, while the only measure readily available is "cpu usage
since system boot", you need to watch it for a while?
$ strace -tt -T -e read,select top -b -n2 2>&1 1>/dev/null |
grep -Ee ' read[(][0-9]*, "cpu | select[(]'
12:27:55.985830 read(3, "cpu 2146371 14 1345585 66007476"..., 8192) = 1586
<0.000395>
12:27:56.065141 select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
<0.500579>
12:27:56.644309 read(5, "cpu 2146377 14 1345595 66007497"..., 1024) = 1024
<0.000164>
12:27:56.645109 select(0, NULL, NULL, NULL, {3, 0}) = 0 (Timeout) <3.002688>
12:27:59.730617 read(5, "cpu 2146379 14 1345604 66007624"..., 1024) = 1024
<0.000164>
[lars@soda:~/DRBD/drbd-8.3]$ strace -tt -T -e read,select top -b -n2 -d 0.1
2>&1 1>/dev/null |
grep -Ee ' read[(][0-9]*, "cpu | select[(]'
12:28:14.834497 read(3, "cpu 2146386 14 1345657 66008224"..., 8192) = 1586
<0.000395>
12:28:14.919021 select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
<0.500582>
12:28:15.501349 read(5, "cpu 2146391 14 1345669 66008247"..., 1024) = 1024
<0.000165>
12:28:15.502149 select(0, NULL, NULL, NULL, {0, 100000}) = 0 (Timeout)
<0.100165>
12:28:15.681910 read(5, "cpu 2146394 14 1345674 66008252"..., 1024) = 1024
<0.000162>
Notice something? (mind the timestamp, and the -d option...)
Default delay of top on my setup seems to be 3 seconds. If you want the same
"accuracy", then any replacement would need to sleep the same three seconds
between two samplings of /proc/stat.
So what you "measure" with your first variant (the print $4; exit)
is the first "estimate" of top, after sampling /proc/stat twice with
a hardcoded delay of 0.5 seconds, not waiting for the better, 3 seconds
sampling period. While this may be "good enough", it is certainly not
equivalent.
You could drop the exit from awk, and do top -b -n1 to achieve the same.
And exactly what do you think you measure with
awk '$1 == "cpu" { print $7; exit }' /proc/stat ?
column 7 is cumulative centiseconds spent in (hard)irq since system boot.
What would the HealthCPU agent do with that?
What you would need to do is sample /proc/stat twice, with a delay of,
say, 1 to 3 seconds, calculate the relative cpu time spent in idle,
and get that calculation right.
That certainly can be done in bash, even from bash,
though to grab the "^cpu " line from stat I'll use grep anyways,
that's faster than trying a "while read a b c ... case a in "cpu "*) ..."
at least in my experience.
#!/bin/bash
percent_cpu_spent_doing_stuff()
{
local delay=${1:-2}
set -- $(grep '^cpu ' < /proc/stat );
shift;
local u=${1:-0} n=${2:-0} s=${3:-0} i=${4:-0} io=${5:-0} irq=${6:-0}
softirq=${7:-0} steal=${8:-0} guest=${9:-0} guest_nice=${10:-0};
sleep $delay;
set -- $(grep '^cpu ' < /proc/stat );
shift;
local sum0=$[u+n+s+i+io+irq+softirq+steal+guest+guest_nice];
local sum1=$[${1:-0} + ${2:-0} + ${3:-0} + ${4:-0} + ${5:-0} + ${6:-0} +
${7:-0} + ${8:-0} + ${9:-0} + ${10:-0}];
local d=$[sum1-sum0];
echo "$sum1 - $sum0 = $d";
u=$[${1:-0} - u] n=$[${2:-0} - n] s=$[${3:-0} - s] i=$[${4:-0} - i];
io=$[${5:-0} - io] irq=$[${6:-0} - irq] softirq=$[${7:-0} - softirq];
steal=$[${8:-0} - steal] guest=$[${9:-0} - guest] guest_nice=$[${10:-0} -
guest_nice];
local x;
for x in u n s i io irq softirq steal guest guest_nice;
do
printf "%12s = %3d%%\n" $x $[${!x}*100/d];
done
}
percent_cpu_spent_doing_stuff
But why would we want to do that?
Would it be sufficient to add a "delay" parameter to the HealthCPU agent,
and pass it to "top -b -n2 -d $delay"? So anyone who wants a completely
useless erratically fluctuating cpu usage measure can use delay=0.1,
and others can pass in delay=10 ?
--
: Lars Ellenberg
: LINBIT | Your Way to High Availability
: DRBD/HA support and consulting http://www.linbit.com
DRBD® and LINBIT® are registered trademarks of LINBIT, Austria.
_______________________________________________
Linux-HA mailing list
[email protected]
http://lists.linux-ha.org/mailman/listinfo/linux-ha
See also: http://linux-ha.org/ReportingProblems