views:

36

answers:

2

I made the following script which searches for certain processes, displays uses pflags for each one, and stops when it finds one with the word "pause":

!cat find_pause
#!/usr/bin/perl -W

use warnings;
use strict;

if (open(WCF,
         "ps -ef | grep '/transfile' | cut -c10-15 | xargs -n1 pflags 2>&1 |"
   )) {
    while (<WCF>) {
       next if ($_ =~ /cannot/);
       print $_;
       last if ($_ =~ /pause/);
    }
    close(WCF);
}

It works, but I wonder if there is a better way to do this.

Update

pause is a low-level system call. Like read, nanosleep, waitid, etc.

With this script I want to find processes that are stuck in the pause call. We are trying to find a bug in our system, and we think it might be related to this.

+1  A: 

There are two possible improvements to this, depending on:

  1. Do you actually require to print exact output of pflags command or some info from it (e.g. list of PIDs and flags?)

  2. What does "pause" in pflags output mean? It's nowhere in "proc" or "pflags" man-pages and all the actual flags are upper case. Depending on its meaning, it might be found in native Perl implementation of "/proc" - Proc::processTable::Process.

    For example, that Process object contains all the flags (in a bit vector) and process status (my suspicion is that "pause" might be a process status).


If the answers to those questions are "Proc::processTable::Process contains enough info for my needs", then a better solution is to use that:

#!/usr/bin/perl -W
use warnings;
use strict;

use Proc::ProcessTable;

my $t = new Proc::ProcessTable;
foreach $p ( @{$t->table} ) {
   my $flags = $p->pid; # This is an integer containing bit vector.
   # Somehow process $flags or $p->status to find "if the process is paused"
   print "$flags\n";
   last if paused($p); # No clue how to do that without more info from you
   # May be : last if $p->status =~ /paused/;
}

However, if the native Perl process does not have enough info for you (unlikely but possible), OR if you acually desire to print exact pflags output as-is for some reason, the best optimization is to construct a list of PIDs for pflags natively - not as big of a win but you still lose a bunch of extra forked off processes. Something like this:

#!/usr/bin/perl -W
use warnings;
use strict;

use Proc::ProcessTable;

my $t = new Proc::ProcessTable;
my $pids = join " ", map { $_->pid } @{$t->table};
if (open(WCF, "pflags 2>&1 $pids|")) {
    while (<WCF>) {
       next if ($_ =~ /cannot/);
       print $_;
       last if ($_ =~ /pause/);
    }
    close(WCF);
}

DVK
+1  A: 

I don't know what you'd consider a "better way" in this case, but I can offer some technique guidance for the approach you already have:

  • grep '/[t]ransfile'

    A grep against ps output often runs the risk of matching the grep process itself, which is almost never desired. An easy protection against this is simply to introduce a character class of one member in the grep pattern argument.

  • awk '/\/[t]ransfile/{ print $2 }'

    grep + cut, that is, field extraction following a pattern match, is an easy task for a single awk command.

  • Don't refer to $_

    Tighter, more idiomatic perl would omit explicit use of $_. Try next if /cannot/ and the like.

  • open(my $wcf, ...)

    Please use lexical filehandles, otherwise you'll be chided by those old enough to remember when we couldn't use them. :)

pilcrow