I originally wrote this to tell me how much memory a certain Apache instance was using. I made it slightly more general purpose. You pass it a regular expression that matches the processes which you want to see the total memory usage of. You can use a debug option to get more verbose output.
I'm aware that the binary itself is not counted multiple times when totaling memory consumption, but in Apache this always comes to less than 10% of the total, so I don't even bother anymore.
Updated version after taking John's excellent suggestions below.
use strict; use warnings; use Getopt::Long; my $debug; GetOptions('debug|verbose|d|v' => \$debug); die "Missing regular expression.\n" if ! $ARGV[0]; my $regex = shift; my @ps_out = qx{ ps -eo pid,vsz,args }; my @proc_lines = grep { m/$regex/ } @ps_out; my %pids = map { (split)[0,1] } @proc_lines; delete $pids{$$}; my $total; my $len = length((sort { $b <=> $a } values %pids)[0]); for my $pid (keys %pids) { $total += $pids{$pid}; printf "%s = %${len}s\n", $pid, $pids{$pid} if $debug; } $len = length($total); print "=" x ($len + 11); print "\n"; print "total KB = $total\n" if $debug; my $mb_total = int($total / 1024); printf "total MB = %${len}s\n", $mb_total;
My original and very inefficient and inelegant version.
use strict;
use warnings;
use Getopt::Long;
my $debug;
GetOptions('debug|verbose|d|v' => \$debug);
die "Missing regular expression.\n" if ! $ARGV[0];
my $regex = shift;
my @ps_out = qx{ ps -ef };
my @proc_lines = grep { m/$regex/ } @ps_out;
my %pids;
for my $line (@proc_lines) {
my $pid = (split /\s+/, $line)[1];
my @out = qx{ ps -o vsz -p $pid };
chomp @out;
my $vsz = $out[-1];
$vsz =~ s/\s+//;
$pids{$pid} = $vsz;
}
my $total;
my $len = length((sort { $b <=> $a } values %pids)[0]);
for my $pid (keys %pids) {
$total += $pids{$pid};
printf "%s = %${len}s\n", $pid, $pids{$pid} if $debug;
}
$len = length($total);
print "=" x ($len + 11);
print "\n";
print "total KB = $total\n" if $debug;
my $mb_total = int($total / 1024);
printf "total MB = %${len}s\n", $mb_total;
Here is me using it.
$ ./1.pl --debug '/httpd\.conf' 5293 = 10696 5298 = 290096 5294 = 7408 5296 = 289124 ================= total KB = 597324 total MB = 583
Would it not be a lot more efficient to get the size in the 1st ps command rather than running ps for each matching process ? A bad regex could dump hundreds of fork execs on a busy system.
ReplyDeleteperl -e'map { printf "%-8d = %8d\n",(split)[0,1] } grep { /$ARGV[0]/ } qx{ ps -eo pid,sz,args };' apache
Thanks a bunch, John, for pointing out all my wasteful use of ps. I've updated the original post.
ReplyDelete