#!/usr/bin/perl -w use strict; use Getopt::Std; use vars qw($VERSION $opt_h $opt_x $opt_n $opt_v $opt_e $lord $hdr @lines %ppidlut %pidname %metric @pids); ($VERSION) = ('$Revision: 1.4 $' =~ /([\d\.]+)/); getopts('hxnve:'); if ($opt_v) { die "xmemusage - process memory usage tool\n\t" . q$Id: xmemusage.pl,v 1.4 2002/10/03 20:06:40 piersk Exp $ . "\n"; } if ($opt_h) { require Pod::Usage; Pod::Usage::pod2usage(-verbose => 2); } my $lord; # the PID of the process that owns all other processes my $shownames = $opt_n; my $autoxdu = $opt_x; my $execit = $opt_e || 'xdu'; if ($^O eq 'linux') { # Linux systems - procps version 2 ($hdr, @lines) = `/bin/ps -Ao pid,ppid,vsize,cmd`; $lord = 1; } elsif ($^O eq 'solaris') { # solaris using normal ps(1) ($hdr, @lines) = `/usr/bin/ps -Ao pid,ppid,vsz,comm`; $lord = 0; } else { die "unsupported operating system - please update me!"; } foreach (@lines) { chomp; if (m/^\s*(\d+)\s+(\d+)\s+(\S+)\s+(.*)$/) { my $pid = $1; push @pids, $pid; $ppidlut{$1} = $2; $metric{$1} = $3; my $tpidname = $4 || ''; $tpidname =~ s/\s.*$//; # $tpidname =~ s!^.*/!!; $tpidname =~ tr:/:%:; $pidname{$pid} = $tpidname || 'NONAME'; } else { warn "No match for <$_>"; } } if ($autoxdu) { open(XDU, '|'.$execit) or die "Cannot open pipe to xdu - $!"; select XDU; } foreach (@pids) { my @bits = reverse(pid2heir($_)); my $shortname = $pidname{$_}; my $str = join('/', '', @bits, $shortname); print "$metric{$_}\t$str\n"; } sub pid2heir { my $pid = shift; if (($pid == $lord) || (! exists($ppidlut{$pid}))) { return ($lord . ($shownames ? '.'.$pidname{$lord} : '')); } else { return ($pid . ($shownames ? '.'.$pidname{$pid} : ''), pid2heir( $ppidlut{$pid} )); } } =pod =head1 NAME xmemusage - show heirarchy of processes' memory usage, including children =head1 SYNOPSIS xmemusage [ -h | -v ] [ -n ] [ -x [ -e PROGRAM ] ] -h - show this help -v - show the version -n - use PID and name in the 'directory' name -x - automatically execute xdu(1) and pass it input -e - specify the program to use instead of 'xdu', e.g. a full path or a clone of xdu. Requires -x I recommend you simply use 'xmemusage -xn' if you have xdu installed (see below). If you want to filter out certain processes, try this sort of construction: xmemusage.pl -n | grep -v oracle | xdu =head1 DESCRIPTION The utility xdu shows the size of directories including their children and files - very useful for finding out what is using disk space. We can do a similar thing for processes - each process itself uses memory and its children, if any, use memory too. By default this program prints a du-like listing to STDOUT, suitable for saving to a file or piping to xdu. The -x option invokes xdu automatically. =head1 XDU Originally written by Phil Dykstra, available from http://sd.wareonearth.com/~phil/xdu/ - although there is at least one enhanced version, http://xdiskusage.sourceforge.net/ This program is not incredibly useful without xdu, or similar, itself. =head1 EXAMPLES Default output, edited as an example, with just the PIDs as 'folder' names: 0 /0/sched 2264 /0/1/%etc%init 0 /0/2/pageout 2960 /0/1/193/17935/17938/%usr%local%bin%fvwm2 3848 /0/1/203/%usr%lib%autofs%automountd 1872 /0/1/21808/%usr%lib%nfs%lockd 2208 /0/1/193/16210/16211/20131/20133/bash 8920 /0/1/285/%usr%lib%ab2%dweb%sunos5%bin%dwhttpd 9536 /0/1/285/1229/%usr%lib%ab2%dweb%sunos5%bin%dwhttpd 1920 /0/1/578/713/830/832/893/896/928/929/10791/10792/10809/telnet So, the name of the process is the 'filename', and its PID is the name of the 'folder' it appears to be in. The root process is PID 0 and is called 'sched'. PID 2 is 'pageout' and it is a direct child of sched. /usr/lib/nfs/lockd is PID 1872 and is a child of init, PID 1. This example has the -n option on so we have the names, aswell as PIDs, of all processes in the 'path': 3000 /0.sched/1.%etc%init/11519.rxvt/11521.ssh/ssh 3928 /0.sched/1.%etc%init/481.%usr%lib%snmp%snmpdx/502.mibiisa/mibiisa 2232 /0.sched/1.%etc%init/8089.rxvt/8091.bash/bash 2416 /0.sched/1.%etc%init/25392.rxvt/25394.tcsh/tcsh 11616 /0.sched/1.%etc%init/373.dbsnmp/dbsnmp 4904 /0.sched/1.%etc%init/578.%usr%dt%bin%dtlogin/%usr%dt%bin%dtlogin 2144 /0.sched/1.%etc%init/297.%usr%dt%bin%sdt_shell/300.-bash/-bash 2272 /0.sched/1.%etc%init/1518.rxvt/rxvt =head1 PREREQUISITES Getopt::Std, Pod::Usage (for the usage/help message only) - or just put this file through perldoc or whatever POD viewer you like. =head1 COREQUISITES xdu or similar program. This program has only been tested on Linux and Solaris. =begin comment =pod OSNAMES Unix - tested on Linux and Solaris only. =pod SCRIPT CATEGORIES UNIX/System_administration =pod README See what processes are using memory with this usage of xdu to see usage in a hierarchy of parent and child processes. =end comment =head1 VERSION $Id: xmemusage.pl,v 1.4 2002/10/03 20:06:40 piersk Exp $ =cut