#!/usr/local/bin/perl -sT -w use strict; use POSIX; ################################################################# # # Geek : smellysocks # Contact : via www.perlmonks.com. my ID is smellysocks # http://www.perlmonks.com/index.pl?node_id=275665 # Purpose : Find out how to get a process to die gracefully when # it believes it may run out of memory... # Notes : This should prob be a module... # # I tried to use an exit and was forced to use POSIX:_exit # routine instead. Do a "perldoc -f exit" to see why. # pay particular attention to this section: # "The exit() function does not always exit immediately" # It was news to me! # Bugs : No bugs, they are all intentional features! # Assumtion that everything is a-ok at startup and # prior to first memory check. # ################################################################# # # Functions/Subroutines: # memusage($PID) : Return how much memory is in use by $PID # memavail(); : Return how much mem is available $ENV{PATH}="/usr/bin:/usr/sbin:/usr/local/bin:/usr/ccs/bin:/usr/openwin/bin:/usr/local/sbin"; # yeah, yeah, yeah. I could have typed in 2^20, etc., etc. etc # this is here to make everyone's life easier. my $OneMB=1048576; my $OneGig=1073741824; # CHANGE ME FOR YOUR ENVIRONMENT!!!! my $TOTALMEM=(2 * $OneGig ); #my $PERCENT_MAX=80; my $PERCENT_MAX=50; my $PID=$$; ############################################################ # Global Stuff my @MEMHOG; my $PMAP="/usr/proc/bin/pmap"; # Assume everything is peachy before these are set. my $PERCENT_USED=0; my $PERCENT_AVAIL=100; my $LASTMEMUSAGE=0; my $loopcount=0; ##################################################################### sub memusage { my ($PID)=@_; my $MEMUSAGE=0; open ( PMAP,"$PMAP $PID|") || return $MEMUSAGE; while ( ) { next unless ( /^\s+total\s+(\d+)K.*$/ ); $MEMUSAGE=+($1 * 1024); } # end of while close PMAP; return $MEMUSAGE; } # end of memusage; ##################################################################### sub memavail { # lose some time here.... :-( better way then vmstat? open ( VMSTAT,"vmstat 1 2|" ) || return -1; my @vmstat=(); close VMSTAT; @vmstat=split /\s+/,$vmstat[3]; return ( $vmstat[4] * 1024 ); } # end of memavail ############################################################ # # Main Stuff/ Start Working # ############################################################ print "I am pid: $PID. I'll be running $PMAP $PID many times\n"; open(LARGEFILE,"/kernel/genunix") || die "Unable to open $!"; my @LARGEFILE=(); close LARGEFILE; # Magnify size of largefile for ( my $i=0; $i < 3; $i++ ) { push @LARGEFILE,@LARGEFILE; } while ( 1 ) { $loopcount++; my $MEMUSAGE=memusage $PID; # usage of pmap is mutually exclusive (one 1 process at a time) # Protect/helps against multiple pmaps steping on each other. if ( $MEMUSAGE == 0 ) { $MEMUSAGE= $LASTMEMUSAGE; } # Print and do expensive work only every N lines/loopcount if ( ! ( $loopcount % 10 ) ) { my $AVAILMEM=memavail; # lose a few seconds here... $PERCENT_USED=( ( $MEMUSAGE / $TOTALMEM ) * 100 ); $PERCENT_AVAIL=( ( $AVAILMEM / $TOTALMEM ) * 100 ); # I hate line wraps... my $TIME=localtime(time()); # yuk. ugly temp var printf "The Time is: %s\n", $TIME; printf "Mem Used: %s Percent Used: %3d%% Percent Left: %3d%%", $MEMUSAGE,$PERCENT_USED,$PERCENT_AVAIL; printf " cnt: %s\n\n", $loopcount; if ( $PERCENT_AVAIL < ( 100 - $PERCENT_MAX ) ) { print "-=" x 30, "\n"; print "The Hog has eaten everything in sight. "; print "Time for the slaughter.\n"; print "-=" x 30, "\n"; POSIX:_exit(1); } } # grab some memory -> should have found a better way to do this. push @MEMHOG,@LARGEFILE; } # Sample PMAP output: #FF1D0000 8K read/write/exec [ anon ] #FF1E0000 16K read/exec /usr/lib/libmp.so.2 #FF1F4000 8K read/write/exec /usr/lib/libmp.so.2 #FF200000 984K read/exec /usr/local/.... # ... # total 816K