real memory usage of process

From cm3l1k1, 5 Years ago, written in Bash, viewed 766 times.
URL http://paste.security-portal.cz/view/5e0b6a8c Shorturl http://gw.gd/74Bz Embed
Download Paste or View Raw
  1. #!/usr/bin/perl
  2. # meminfo.pl - show real memory use by processes, or as close to it as possible
  3. # Copyright (C) 2009 Peter Willis <peterwwillis@yahoo.com>
  4. #
  5. # Stop guessing about how much memory is being used by processes on your system.
  6. # Use this tool to find out for real how much real memory is being used.
  7. # Requires a kernel with 'smaps' support (cat /proc/$$/smaps to check yours)
  8. #
  9. # Usage is fairly simple: pass it a pid on the command line and it will gather
  10. # memory stats from them and report them.
  11. #
  12. # If you're trying to get the total memory of a multi-process application, just
  13. # pass all the PIDs and look at the Private RSS. That will include all pages
  14. # used by your application. It *won't* include shared memory from libraries which
  15. # might be used by yet-another-program, but it'll give you a good minimum size
  16. # of your app. To find all pages used by other programs, use --find-all-memory.
  17. #
  18. # If your kernel supports Pss stats, that is the best example of how much real
  19. # memory a process is using (it's the private rss combined with 'its share' of
  20. # shared memory, so add all the Pss's of your application's processes up and you
  21. # will know how much memory they are using, or at least a little more accurately)
  22. #
  23. # You may need to be root to make this script really useful.
  24.  
  25.  
  26. use strict;
  27. $|=1;
  28.  
  29. if ( ! @ARGV ) {
  30.     die "Usage: $0 PID|TCOMM [..]\nPass a pid or a process executable name.\nTotals and reports on per-process memory usage.\n";
  31. }
  32.  
  33. # Global Vars
  34. my @smaps_names = qw(Size Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Swap);
  35. my $MEG = 1024; # in kilobytes
  36. my $GIG = $MEG*1024; # in kilobytes
  37. my %procs;
  38. my %procstat;
  39. my $counted_pids = 0;
  40.  
  41. # Main
  42.  
  43. # Collect process information
  44. foreach my $arg (@ARGV) {
  45.     my @pids = ( $arg );
  46.     if ( $arg !~ /^\d+$/ ) {
  47.         @pids = grep_pids($arg, \%procstat);
  48.     }
  49.  
  50.     foreach my $pid (@pids) {
  51.         if ( !exists $procstat{$pid} ) {
  52.             $procstat{$pid} = getstat($pid);
  53.         }
  54.         if ( keys %{ $procstat{$pid} } ) {
  55.             my @a = calc_smaps_pid($pid);
  56.             if ( @a ) {
  57.                 $procs{$pid} = \@a;
  58.                 $counted_pids++;
  59.             }
  60.         }
  61.     }
  62. }
  63.  
  64. # Summarize
  65.  
  66. summarize_pids(\%procs, \%procstat, \@ARGV);
  67. my @totals = summarize_totals(\%procs);
  68.  
  69. format_print("\nSummary:\n\tTotal Size =>\t\t\t%f\n\tTotal Rss =>\t\t\t%f\n\tTotal Pss =>\t\t\t%f\n\tTotal Shared_Clean =>\t\t%f\n\tTotal Shared_Dirty =>\t\t%f\n\tTotal Private_Clean =>\t\t%f\n\tTotal Private_Dirty =>\t\t%f\n\tTotal Referenced =>\t\t%f\n\tTotal Swap =>\t\t\t%f\n", @totals);
  70.  
  71. # Make some guesstimations
  72.  
  73. # Shared Clean + Private Clean + Private Dirty (Shared Clean may still be an innacurate addition of multiple shared pages!) 1 - 3 4
  74. #my $guessed_mem = ($totals[3] + $totals[5] + $totals[6]);
  75. my $guessed_mem = ( $totals[1] - ($totals[3] + $totals[4]) );
  76. print "\nAverages:\n";
  77. format_print("\tTotal Rss - Shared Rss:\t\t%f\n\tNumber of PIDs:\t\t\t$counted_pids\n\tAverage memory per PID:\t\t%f\n", $guessed_mem, ($guessed_mem/$counted_pids));
  78.  
  79. exit 0;
  80.  
  81.  
  82. # Subroutines
  83.  
  84.  
  85. # By default searches *every pid on the system*
  86. sub grep_pids {
  87.     my $arg = shift;
  88.     my $pstat_ref = shift;
  89.     my @foundpids;
  90.  
  91.     opendir(DIR, "/proc/") || die "Error: let me read /proc/ !!!\n";
  92.     my @dirs = grep(/^\d+$/, readdir(DIR) );
  93.     closedir(DIR);
  94.  
  95.     # Each of these dirs should be a pid, according to grep above
  96.     foreach my $dir (@dirs) {
  97.         if ( !exists $pstat_ref->{$dir} ) {
  98.             $pstat_ref->{$dir} = getstat($dir);
  99.         }
  100.         if ( keys %$pstat_ref and $pstat_ref->{$dir}->{'tcomm'} eq $arg ) {
  101.             push(@foundpids, $dir);
  102.         }
  103.     }
  104.     return @foundpids;
  105. }
  106.  
  107.  
  108. sub getstat {
  109.     my $pid = shift;
  110.  
  111.     if ( ! open(FILE, "/proc/$pid/stat") ) {
  112.         print STDERR "Could not read stat for $pid: $!\n" if (exists $ENV{VERBOSE});
  113.         return( {} );
  114.     }
  115.     my @stat = split(/\s+/, <FILE>);
  116.     close(FILE);
  117.  
  118.     my $hashref = { 'tcomm' => $stat[1], 'state' => $stat[2], 'ppid' => $stat[3], 'pgrp' => $stat[4], 'sid' => $stat[5] };
  119.     $hashref->{'tcomm'} =~ tr/()//d;
  120.     return $hashref;
  121. }
  122.  
  123.  
  124. sub summarize_pids {
  125.     my $procs_ref = shift;
  126.     my $pstat_ref = shift;
  127.     my $pids = shift;
  128.  
  129.     foreach my $pid (keys %$procs_ref) {
  130.         print "Pid $pid ($pstat_ref->{$pid}->{tcomm}) :\n";
  131.         for ( my $i=0 ; $i < @{$procs_ref->{$pid}} ; $i++ ) {
  132.             format_print("\t$smaps_names[$i] => %f\n", $procs_ref->{$pid}->[$i]);
  133.         }
  134.     }
  135. }
  136.  
  137. # Summarize all proc totals
  138. sub summarize_totals {
  139.     my $procs = shift;
  140.     my ($size, $rss, $pss, $shared_clean, $shared_dirty, $private_clean, $private_dirty, $referenced, $swap) = ( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
  141.     foreach my $proc ( keys %$procs ) {
  142.         $size += $procs->{$proc}->[0];
  143.         $rss += $procs->{$proc}->[1];
  144.         $pss += $procs->{$proc}->[2];
  145.         $shared_clean += $procs->{$proc}->[3];
  146.         $shared_dirty += $procs->{$proc}->[4];
  147.         $private_clean += $procs->{$proc}->[5];
  148.         $private_dirty += $procs->{$proc}->[6];
  149.         $referenced += $procs->{$proc}->[7];
  150.         $swap += $procs->{$proc}->[8];
  151.     }
  152.     return ($size, $rss, $pss, $shared_clean, $shared_dirty, $private_clean, $private_dirty, $referenced, $swap);
  153. }
  154.  
  155.  
  156. # Yes, I know about Linux::Smaps.
  157. sub calc_smaps_pid {
  158.     my $pid = shift;
  159.     my ($size, $rss, $pss, $shared_clean, $shared_dirty, $private_clean, $private_dirty, $referenced, $swap) = ( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
  160.  
  161.     if ( ! open(FILE,"</proc/$pid/smaps") ) {
  162.         print STDERR "Could not read smaps for $pid: $!\n" if (exists $ENV{VERBOSE});
  163.         return ();
  164.     }
  165.     my @smaps = map { chomp $_; $_ } <FILE>;
  166.     close(FILE);
  167.  
  168.     # FYI: by default these are all kilobytes, assume it'll always be that way...
  169.     for ( my $i=0; $i<@smaps; $i++ ) {
  170.         if ( $smaps[$i] =~ /^Size:\s+(\d+)/ ) {
  171.             $size += $1;
  172.         } elsif ( $smaps[$i] =~ /^Rss:\s+(\d+)/ ) {
  173.             $rss += $1;
  174.         } elsif ( $smaps[$i] =~ /^Pss:\s+(\d+)/ ) {
  175.             $pss += $1;
  176.         } elsif ( $smaps[$i] =~ /^Shared_Clean:\s+(\d+)/ ) {
  177.             $shared_clean += $1;
  178.         } elsif ( $smaps[$i] =~ /^Shared_Dirty:\s+(\d+)/ ) {
  179.             $shared_dirty += $1;
  180.         } elsif ( $smaps[$i] =~ /^Private_Clean:\s+(\d+)/ ) {
  181.             $private_clean += $1;
  182.         } elsif ( $smaps[$i] =~ /^Private_Dirty:\s+(\d+)/ ) {
  183.             $private_dirty += $1;
  184.         } elsif ( $smaps[$i] =~ /^Referenced:\s+(\d+)/ ) {
  185.             $referenced += $1;
  186.         } elsif ( $smaps[$i] =~ /^Swap:\s+(\d+)/ ) {
  187.             $swap += $1;
  188.         }
  189.     }
  190.  
  191.     return ($size, $rss, $pss, $shared_clean, $shared_dirty, $private_clean, $private_dirty, $referenced, $swap);
  192. }
  193.  
  194. # Hack to pretty-format any numbers automatically
  195. sub format_print {
  196.     my $format = shift;
  197.     my @args = @_;
  198.     my $c = 0;
  199.  
  200.     # I suck at formatting
  201.     $format =~ s<\%f>| $args[$c] > $GIG ? sprintf("%.4G GB",$args[$c++]/1024/1024) : $args[$c] > $MEG ? sprintf("%.4G MB",$args[$c++]/1024) : sprintf("%.4G KB",$args[$c++]) |eg;
  202.  
  203.     print $format;
  204. }
  205.  
  206.  

Reply to "real memory usage of process"

Here you can reply to the paste above