Octavian has asked for the wisdom of the Perl Monks concerning the following question:
I have been given a task to write a script that sounds simple, but is beyond the scope of my perl knowledge and so I come to you seeking help.
What is required is I need to write a script that runs every half hour and checks all the processes that are running on our UNIX server (HPUX 11.00 to be exact). If it finds a process that is utilizing more than 75% of a cpu, it should "mark" that process. The next time it runs, if that process is still using more than 75%, it sends an email to our group letting us know that there is a process hog so that we may take action on it.
Now, everything in the script I can do, with the exception of figuring out which processes are taking up more than 75% of the cpu. I could sloppily make a call to top and have it dump its output to a file and get it that way, but I know there has to be a way for perl to get that information without having to resort to using something like top.
I also need to note, that we are using perl version 5.6.1 and that going to cpan for additional modules that is not in the standard build is out of the question, we have a standard build on all of our systems and even upgrading to 5.6.1 was a large undertaking due to the fact that all the powers that be around here have to give their blessing.
That being said, does anyone know of a way to quickly grab the cpu utilization percentage of a process using perl?
Re: Using Perl to find Process Hogs
by VSarkiss (Monsignor) on Apr 17, 2003 at 18:49 UTC
|
Boy, this sounds like a shop I used to work at. Do I know you from somewhere? ;-)
As I recall, HP-UX doesn't have anything like a /proc file system, so you're limited to tools like ps. What I did (and you're right, it's very sloppy) was to write a script that read the output from ps, saved the TIME column against each PID in a hash, slept, then did it again, and compared the time for each matching PID. If it was greater than a threshold, it printed a message (in your case, you would send an email).
I'm reconstructing this from memory, so you'll have to make this work for real, but the code basically looks like this:
my (%current, %previous);
while (1)
{
open PS, "ps -ef |" or die "Can't run ps: $!\n";
while (<PS>)
{
# you need to do this with the correct column
# widths; something like split won't work,
# and a regex would be way too complicated.
my ($pid, $time) = unpack '...';
$current{$pid} = $time;
if (exists $previous($pid})
{
# difference sub is an exercise for the reader....
if (difference($current{$pid}, $previous{$pid}
>= $threshold)
{
warn "$pid is a piggy\n";
}
}
}
close PS;
%previous = %current;
sleep 3600;
}
Sorry I couldn't be more specific. HTH anyway. | [reply] [d/l] [select] |
•Re: Using Perl to find Process Hogs
by merlyn (Sage) on Apr 17, 2003 at 20:18 UTC
|
| [reply] |
Re: Using Perl to find Process Hogs
by dmitri (Priest) on Apr 17, 2003 at 18:38 UTC
|
I've had to do something similar before, and I believe the output of this command should help you:
ps -eo pcpu,pid | sed '1d; s/^ *//; s/ */ /g;' | sort -nr
Update:
One assumption here is that process IDs don't get wrapped around in half an hour, but what are the chances of that?
Another update:
Thinking about it some more, since only one process can consume 75% of CPU at one time, you can append this piece to the pipeline above:
| head -1
| [reply] |
|
What operating system does this work on? -eo, or at least o is not a valid option with ps on our HPUX 11 machine... I actually did explore with ps a bit, and ps -fl or even -ef does give CPU as one of the columns, but the number it gives doesnt make sense to me...our top proccess is taking up about 11% right now, but that number shows 112...so that confused me more than helped, so I gave up on ps ;)
and to answer your update, yes, more than one proc can have 75% of a CPU, my test box has 2 CPU's, but this will eventually go on machines with 6 ;)
| [reply] |
|
The TIME CPU column is the total CPU time accumulated by the process. You have to be careful what you mean by "75% of the CPU", because you need to quantify that by saying "over how long of a period". I'm assuming you're going to use some number of seconds or minutes. Thus you would calculate the CPU usage for that period by subtracting the total times for any process that's still running between the two times that you looked, then get the percentage by dividing over the time period you're using.
Notice this implies your CPU hogs are also long-running. In other words, a CPU-intensive process that goes away in a less than a minute may not register, though your users may still complain about a momentary lack of response.
Yes, this isn't precise, but it's good enough for government work. ;-)
Update
Mislabelled the column name.
| [reply] |
|
According to 'man ps', -o, and many othe useful options, only work on XPG4 (X/Open Portability Guide v4) compatible boxes...
--perlplexer
| [reply] |
|
| [reply] |
Re: Using Perl to find Process Hogs
by Limbic~Region (Chancellor) on Apr 17, 2003 at 20:46 UTC
|
Octavian,
I am not sure of another HPUX utility that calculates the
CPU utilization percentage on the fly like top does. Since
you are being tasked to do this, I am betting this is the
value they want you to use.
#!/usr/bin/perl -w
use strict;
unlink "/tmp/prochogs.$$" if (-e "/tmp/prochogs.$$");
system ("top -u -h -d1 -s1 -f /tmp/prochogs.$$");
open (TOP,"/tmp/prochogs.$$") or die "Unable to open top file - $!";
my %Proc;
my $FoundList;
while (<TOP>) {
if (/^CPU/) {
$FoundList = 1;
next;
}
next unless ($FoundList);
my @Values = split;
$Proc{$Values[2]} = \@Values;
}
foreach(keys %Proc) {
print "$_ : $Proc{$_}->[11]\n";
}
So why write the output to a file and read it back in instead
of creating a pipe? Well, when run interactively, top on HPUX
formats the output with a bunch of ANSI escape sequences that
is a pain to parse.
This should give you what you want and is easy to modify. You
want to make sure your temporary file makes sense on your system.
Cheers - L~R | [reply] [d/l] |
Re: Using Perl to find Process Hogs
by toma (Vicar) on Apr 18, 2003 at 04:43 UTC
|
| [reply] |
|
#!/usr/bin/perl -w
use strict;
use Proc::ProcessTable;
my $t = new Proc::ProcessTable;
foreach my $proc ( @{$t->table} ){
print $proc->pid , " : " , $proc->pctcpu , "\n";
}
Cheers - L~R | [reply] [d/l] |
|
Yeah, I have seen ProcessTable talked about before, but its not found in our build of perl, so I assumed it was an extra module downloadable from CPAN...that is why I made mention that I couldnt use any extra stuff like that, only the built in stuff in the standard build of perl...
I would like to thank you though for your assistance, I am not sure how TOP calculates that %CPU stat, but that is the one that needs to be searched on. I was hoping for a special magic perl function that I didnt know about, but when trying out your snippet using top, it works pretty quick (alot faster than my attempt at using top) so it looks like that is the way to go for me.
Again, thank you for your wisdom!
| [reply] |
|
|