Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Better way to search in the process table?

by karlgoethebier (Abbot)
on Mar 02, 2014 at 19:24 UTC ( [id://1076730]=perlquestion: print w/replies, xml ) Need Help??

karlgoethebier has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, i need to search for some long running processes and their parents...

603 ? Ss 0:01 /usr/sbin/cron 18421 ? S 0:00 \_ /usr/sbin/cron 18423 ? Ss 0:00 | \_ /bin/sh /opt/pdi-jobs/4.3.0/CST/CE_Upload/CE_U +pload_MON.sh 18425 ? S 0:00 | \_ /bin/sh ./kitchen.sh -file=/opt/pdi-jobs/4 +.3.0/... 18444 ? Sl 1:47 | \_ java -Xmx512m -cp .:./lib/kettle-core. +jar...

...in this example the pids 18444, 18425, 18423 and 18421.

I thought to do it like this (scratch):

use Proc::ProcessTable; my $processes = new Proc::ProcessTable; my @java_processes = grep { $_->cmndline =~ /^\/System/ } @{ $processes->table }; # fake +pattern, got no java at home ;-) foreach my $java_process (@java_processes) { my $pid = $java_process->pid; # more stuff with this pid my $ppid = $java_process->ppid; my @parent = grep { $_->pid == $ppid } @{ $processes->table }; # more stuff with the parent my $gppid = $parent[0]->ppid; my @gparent = grep { $_->pid == $gppid } @{ $processes->table }; # more stuff with the grandparent my $ggppid = $gparent[0]->ppid; my @ggparent = grep { $_->pid == $ggppid } @{ $processes->table }; # more stuff with the great-grandparent }

Update: fixed typo: $ggppid.

I couldn't figure out something better yet.

Thank you very much for any hint and best regards, Karl

«The Crux of the Biscuit is the Apostrophe»

Replies are listed 'Best First'.
Re: Better way to search in the process table?
by kcott (Archbishop) on Mar 02, 2014 at 22:29 UTC

    G'day Karl,

    My main issues with the way you're currently doing this is that you're reading the entire process table for every ancestry level you want and, for each of those levels, you're repeating almost identical code.

    Here's a technique that only reads the process table once and allows access to the process data in a variety of ways (I've shown a few examples). I've used your data (and some extra for testing) in a dummy AoH reference ($table) rather than attempting to recreate a Proc::ProcessTable object: you'll need to make changes (e.g. '$_->{pid}' to '$_->pid') for a real solution. Also note that by changing the value of $ancestry, you can get whatever number of ancestry levels you want; although, you may want to rethink my constant names if you start using 'GREATGREAT...GREATGRANDPARENT'. :-)

    #!/usr/bin/env perl use strict; use warnings; use constant { CHILD => 0, PARENT => 1, GRANDPARENT => 2, GREATGRANDPARENT => 3, }; my $table = [ { pid => 0, ppid => 0, cmd => 'root' }, { pid => 603, ppid => 0, cmd => 'cron_parent' }, { pid => 18421, ppid => 603, cmd => 'cron_child' }, { pid => 18423, ppid => 18421, cmd => 'sh_mon' }, { pid => 18425, ppid => 18423, cmd => 'sh_kit' }, { pid => 18444, ppid => 18425, cmd => 'java' }, { pid => 28421, ppid => 603, cmd => 'cron_child' }, { pid => 28423, ppid => 18421, cmd => 'sh_mon' }, { pid => 28425, ppid => 18423, cmd => 'sh_kit' }, { pid => 28444, ppid => 18425, cmd => 'java' }, { pid => 28445, ppid => 18425, cmd => 'java' }, { pid => 99999, ppid => 18421, cmd => 'java' }, { pid => 2, ppid => 1, cmd => 'unwanted' }, ]; my $ancestry = 3; my %tree; { my %all; for (@$table) { $all{$_->{pid}} = $_; $tree{$_->{pid}} = [ $_ ] if $_->{cmd} =~ /java/; } for my $child (keys %tree) { my $ppid = $all{$child}{ppid}; for (1 .. $ancestry) { push @{$tree{$child}}, {%{$all{$ppid}}}; $ppid = $all{$ppid}{ppid}; } } } use Data::Dump; print "*** All parents ***\n"; dd [ map { $tree{$_}[PARENT] } sort keys %tree ]; print "*** 18444 grandparent ***\n"; dd $tree{18444}[GRANDPARENT]; print "*** 18444 greatgrandparent ***\n"; dd $tree{18444}[GREATGRANDPARENT]; print "*** All ancestries ***\n"; dd \%tree;

    Output:

    *** All parents *** [ { cmd => "sh_kit", pid => 18425, ppid => 18423 }, { cmd => "sh_kit", pid => 18425, ppid => 18423 }, { cmd => "sh_kit", pid => 18425, ppid => 18423 }, { cmd => "cron_child", pid => 18421, ppid => 603 }, ] *** 18444 grandparent *** { cmd => "sh_mon", pid => 18423, ppid => 18421 } *** 18444 greatgrandparent *** { cmd => "cron_child", pid => 18421, ppid => 603 } *** All ancestries *** { 18444 => [ { cmd => "java", pid => 18444, ppid => 18425 }, { cmd => "sh_kit", pid => 18425, ppid => 18423 }, { cmd => "sh_mon", pid => 18423, ppid => 18421 }, { cmd => "cron_child", pid => 18421, ppid => 603 }, ], 28444 => [ { cmd => "java", pid => 28444, ppid => 18425 }, { cmd => "sh_kit", pid => 18425, ppid => 18423 }, { cmd => "sh_mon", pid => 18423, ppid => 18421 }, { cmd => "cron_child", pid => 18421, ppid => 603 }, ], 28445 => [ { cmd => "java", pid => 28445, ppid => 18425 }, { cmd => "sh_kit", pid => 18425, ppid => 18423 }, { cmd => "sh_mon", pid => 18423, ppid => 18421 }, { cmd => "cron_child", pid => 18421, ppid => 603 }, ], 99999 => [ { cmd => "java", pid => 99999, ppid => 18421 }, { cmd => "cron_child", pid => 18421, ppid => 603 }, { cmd => "cron_parent", pid => 603, ppid => 0 }, { cmd => "root", pid => 0, ppid => 0 }, ], }

    [While I can see the Proc::ProcessTable documentation uses indirect object notation, please be aware this syntax is strongly discouraged (explained in perlobj: Invoking Class Methods).]

    -- Ken

      Hello kcott and thank you very much for your elegant solution!

      Here is what i worked out:

      #!/usr/bin/perl use strict; use warnings; use Proc::ProcessTable; use Data::Dump; my $processes = new Proc::ProcessTable; my $ancestry = 3; my %tree; my %all; for ( @{ $processes->table } ) { $all{ $_->pid } = $_; $tree{ $_->pid } = [$_] if $_->cmndline =~ /^\/usr\/sbin\/mysqld/; } # dd \%all; exit; # dd \%tree; exit; for my $child (keys %tree) { print qq(child:\t$child\n); my $ppid = $all{$child}->ppid; print qq(ppid:\t$ppid\n); for (1 .. $ancestry) { push @{$tree{$child}}, $all{$ppid}; $ppid = $all{$ppid}{ppid}; last unless $ppid; print qq(ppid:\t$ppid\n); } } dd \%tree; __END__

      This seems to work.

      If $ancestry == 3 and i don't say last unless $ppid, it goes back until PID 0 and sets one key in %tree to undef. I hope i didn't miss something.

      Thanks again for sharing your knowledge and best regards,

      Karl

      «The Crux of the Biscuit is the Apostrophe»

        "If $ancestry == 3 and i don't say last unless $ppid, it goes back until PID 0 and sets one key in %tree to undef. I hope i didn't miss something."

        The keys in %tree are unaffected by that statement: they're already set and you're looping through them (i.e. for my $child (keys %tree) {...}). You'll need to clarify this. You're probably referring to one of these: the value of the key (normally an arrayref); an element in that arrayref (normally a hashref); a key/value in one of those hashrefs.

        I'd normally expect the parent of PID 0 to be PID 0 also. That's true for my OS but perhaps it's not the case on your OS. It's possible that Proc::ProcessTable does not return information for PID 0: I claim no particular experise with this module, you'll need to research this yourself. It could also be a security feature: maybe only UID 0 (root) can query PID 0.

        If the code you currently have does what you want, perhaps just keep to the old adage: "If it ain't broke, don't fix it." :-)

        -- Ken

Re: Better way to search in the process table?
by hdb (Monsignor) on Mar 02, 2014 at 22:17 UTC

    I would build a tree of parent ids:

    use strict; use warnings; use Proc::ProcessTable; my $p = new Proc::ProcessTable; my $t = $p->table; my %tree; $tree{$_->pid} = $_->ppid for @$t; for my $process ( @$t ) { print $process->cmndline; my $pid = $process->pid; while( $pid > 1 ) { print "->$pid"; $pid = $tree{$pid} } print "->$pid\n"; }
Re: Better way to search in the process table?
by shmem (Chancellor) on Mar 02, 2014 at 22:04 UTC
    Well, this...
    # more stuff with this pid # more stuff with the parent # more stuff with the grandparent # more stuff with the great-grandparent
    ...looks like a something recursive... like... nature...

    Seriously, without knowing the purpose of all this, it is difficult to tell the meaning of life.
    Maybe "more stuff" is an anonymous sub which does pamper/feed/play with/kill or such? and is passed as an argument into the sub which deals with a process?
    Is all that just for fun? Do we want to build a tree?

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      Hello shmem and thank you very much for answering.

      I'm sorry if my question was too imprecise. This issue has a serious background and is not just for fun. On a Pentaho server some java processes run forever, consume all memory, bring load average up to 500 and then kill the machine.

      This These processes are triggered by cron which triggers a shell script that triggers another shell script that triggers the java process.

      No one had any idea yet why the processes run amok.

      My task is: The processes have to be monitored. At least pids, time and cmndline have to be written to a logfile. A mail has to be send to the admin of the machine. If the cputime exeeds some value, the processes have to be killed. (N.B.: Nagios is not an option).

      "Do we want to build a tree?"

      Yes, we really should do that ;-)

      I think, the solution provided below by kcott at Re: Better way to search in the process table? does what i need and is much better than my example.

      Update: I tried to fix my Denglisch ;-)

      Best regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (5)
As of 2024-03-28 18:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found