Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Using Perl to find Process Hogs

by Octavian (Monk)
on Apr 17, 2003 at 18:23 UTC ( [id://251281]=perlquestion: print w/replies, xml ) Need Help??

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?

Replies are listed 'Best First'.
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.

•Re: Using Perl to find Process Hogs
by merlyn (Sage) on Apr 17, 2003 at 20:18 UTC
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
    
      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 ;)

        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.

        According to 'man ps', -o, and many othe useful options, only work on XPG4 (X/Open Portability Guide v4) compatible boxes...

        --perlplexer
        Six processors... sweet!

        The ps command I'm talking about works on Linux. Of course, Linux's ps supports both BSD and SVR4-type options. On my box, -o lets user specify the columns of output.

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

Re: Using Perl to find Process Hogs
by toma (Vicar) on Apr 18, 2003 at 04:43 UTC
    Proc::ProcessTable works fine on HP-UX. It does exactly what you need. There is no need to use ps.

    It should work perfectly the first time! - toma

      toma,
      You are correct, Proc::ProcessTable does provide a pctcpu option. There are a couple of reasons I suggested parsing top instead of Proc::ProcessTable. The first is because there is no way (that I know of) to change the sampling window as there is with top. The second reason is HPUX does not ship with an ANSI compliant C compiler. This isn't a big obstacle to overcome, but for the sake of portability, I have no issues parsing the output of a built-in command especially one developed by the vendor.

      With that said, here is some sample code on how it could be used:
      (Much cleaner than my parsing of top)

      #!/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

        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!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://251281]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (8)
As of 2024-04-19 09:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found