#!/usr/bin/perl # # memstats lists processes memory usage # Copyright 2014 Grégory Soutadé # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # use POSIX (); use Getopt::Long; # Convert int to kilobytes, megabytes and gigabytes sub printPacked { my ($size) = @_; my $suffix = ""; if($size < 1024*1024) { $suffix = "k"; $size = int($size/1024); } elsif($size < 1024*1024*1024) { $suffix = "m"; $size = int($size/(1024*1024)); } else { $suffix = "g"; $size /= 1024*1024*1024; if ($size != int($size)) { $size = sprintf "%.2f", $size; } } return "$size$suffix"; } # Convert seconds in hours:minutes:seconds sub printTime { my ($time) = @_; my $res = ""; $seconds = $time % 60; $minutes = 0; $hours = 0; if ($time < 60) { $seconds = $time; $minutes = 0; $hours = 0; } else { $seconds = $time % 60; $time -= $seconds; $time /= 60; if ($time < 60) { $minutes = $time; $hours = 0; } else { $minutes = $time % 60; $time -= $minutes; $time /= 60; $hours = $time; } } $res = sprintf "%02d:%02d:%02d", $hours, $minute, $seconds; return $res; } # PID OWNER USER VIRT RES S TIME COMMAND my @sizes ; my @lines ; # Put line to column writer sub putLine { my ($line) = @_; push @lines, $line; @s = split(/ /, $line); if (scalar(@sizes) == 0) { foreach $v (@s) {push @sizes, length($v);} } else { for($i=0; $i $sizes[$i]); } } } # Compute column format sub computeFormat { my $format = ""; for($i=0; $i 0) { $format .= sprintf " %%%ds", $sizes[$i]; } else { $format .= sprintf "%%%ds", $sizes[$i]; } } $format .= "\n"; return $format; } # Get current start time in seconds sub getStartTime { open(FIC,"); close (FIC); return $infos[21]; } # Constants my $clock_ticks = POSIX::sysconf(&POSIX::_SC_CLK_TCK ); my $page_size = POSIX::sysconf(&POSIX::_SC_PAGESIZE); my $starttime = getStartTime(); my $NB_PROCESSES = 30; my $help; my $all; my $virt; # Process paramters my $program_name = $0; GetOptions ("nb_processes=i" => \$NB_PROCESSES, "all" => \$all, "virt" => \$virt, "help" => \$help); if ($help) { printf "Display processes memory usage\nusage: %s [--all|--nb_processes=NB_PROCESSES] [--virt]\n", $program_name; print "\t--all:\t\tList all processes\n"; print "\t--nb_processes:\tLimit list to NB_PROCESSES (default: 30)\n"; print "\t--virt:\t\tSort by virtual memory (RES by default)\n"; exit(0); } $NB_PROCESSES = -1 if ($all); ############ START ############ my @processes; # Analyze all processes opendir (DIR, "/proc") or die $!; while (my $pid = readdir(DIR)) { next if ($pid !~ /[0-9]+/); # Get owner name my $uid = 0; open(FIC," ) ) { if ($l =~ /Uid:\s+([0-9]+)\s+.*/) { $uid = $1; last; } } close (FIC); ($owner_name,$passwd,$uid,$gid, $quota,$comment,$gcos,$dir,$shell,$expire) = getpwuid($uid); # Get infos open(FIC,"); close (FIC); push @processes, {"pid" => $infos[0], "owner" => $owner_name, "comm" => $infos[1], "state" => $infos[2], "starttime" => $infos[21], "vsize" => $infos[22], "rss" => $infos[23], }; } # Sort in reverse order by memory usage if ($virt) { @p = sort {$b->{vsize} <=> $a->{vsize}} @processes; } else { @p = sort {$b->{rss} <=> $a->{rss}} @processes; } # Compute lines putLine("PID OWNER VIRT RES S TIME COMMAND"); foreach $e (@p) { $vsize = printPacked($$e{vsize}); $rss = printPacked($$e{rss}*$page_size); $time = int(($starttime-$$e{starttime}) / $clock_ticks); $time = printTime $time; $name = $$e{comm}; $name =~ s/\(//; $name =~ s/\)//; last if ($NB_PROCESSES > 0 && scalar(@lines) > $NB_PROCESSES); putLine("$$e{pid} $$e{owner} $vsize $rss $$e{state} $time $name"); } my $format = computeFormat; # Start display foreach $l (@lines) { printf $format, split(/ /, $l); }