A few months ago, I had the need to check what the swap usage was on my Linux system.
(Update 2014-10-26: This can also be checked with the excellent smem tool)
I encountered a little bash script by a guy called Erik Ljungstrom, who had written a small script that iterates through the /proc system, takes the name for the PID and adds up the swap space.
Here’s the original script.
#!/bin/bash
# Get current swap usage for all running processes
# Erik Ljungstrom 27/05/2011
SUM=0
OVERALL=0
for DIR in `find /proc/ -maxdepth 1 -type d | egrep "^/proc/[0-9]"`
do
PID=`echo $DIR | cut -d / -f 3`
PROGNAME=`ps -p $PID -o comm --no-headers`
for SWAP in `grep Swap $DIR/smaps 2>/dev/null| awk '{ print $2 }'`
do
let SUM=$SUM+$SWAP
done
echo "PID=$PID - Swap used: $SUM - ($PROGNAME )"
let OVERALL=$OVERALL+$SUM
SUM=0
done
echo "Overall swap used: $OVERALL"
It’s not the fasted script, but it does its job, and you can do a
# ./getswap.sh | sort -n -k 5
to have the values sorted in ascending order.
And as it was a free day, I needed to brush up some basic Perl skillz again.
Here’s the result:
#!/usr/bin/perl -w
#
# Get current swap usage for all running processes
#
# Based on a bash script by Erik Ljungstrom 27/05/2011
#
# Author = Christopher Ranschaert - 07/07/2012
#
# Parses pids in /proc, collects the name from /proc/$pid/comm and
# calculates the swapsize from /proc/$pid/smaps
#
# Warning: Needs root permissions to read swap values, will otherwise return 0.
# If you don't trust this, learn some Perl and check the code :-)
# Something I'd suggest you to do anyway!
use strict;
my $overall = 0;
my $dirname = "/proc";
my %names = ();
my %swaps = ();
my $processname = '';
my $pidnumber = '';
my $swapsizenumber = '';
# Open /proc directory and parse for PIDs and store them in hash.
opendir(DIR, $dirname) or die "Couldn't open $dirname: $!";
while ( defined ( my $pid = readdir DIR )){
next unless $pid =~ /^\d+$/; # PIDs are digits only, skip the rest
if (-d "$dirname/$pid") {
$names{$pid} = &read_processname_from($pid);
$swaps{$pid} = &get_swapsize_from($pid);
}
}
closedir(DIR);
format STDOUT =
@<<<<<< | @<<<<< | @<<<<<<<<<<<<<<< |
$pidnumber,$swapsizenumber,$processname
.
print "-------------------------------------\n";
print "Processes and their swapsizes\n";
print "-------------------------------------\n";
print " PID | SWAP | PROCESSNAME |\n";
print "-------------------------------------\n";
my @pids = sort { $swaps{$a} <=> $swaps{$b} } (keys %swaps);
foreach my $pid ( @pids ){
$pidnumber = $pid;
$processname = $names{$pid};
$swapsizenumber = $swaps{$pid};
$overall += $swapsizenumber;
write(STDOUT);
}
print "-------------------------------------\n";
print "Overall Swap used: $overall KiB\n";
exit 0;
sub read_processname_from {
my $pid = shift;
my $procnamefile = "$dirname/$pid/comm";
open (FH, $procnamefile) or die "Can't open $procnamefile: $!";
my $procname = <FH>;
chomp $procname;
close(FH);
return $procname;
}
sub get_swapsize_from {
my $pid = shift;
my $sum = 0;
my $smapsfile = "$dirname/$pid/smaps";
open (FH, $smapsfile) or die "Can't open $smapsfile: $!";
while (<FH>){
next unless /^Swap/;
$_ =~ m/^Swap:\s+(\d+)\s+kB*$/;
my $swapsize = $1;
$sum += $swapsize;
}
close (FH);
return $sum;
}
It already includes sorting so the extra sort command is no longer needed.
Output sample:
# ./getswap.pl
-------------------------------------
Processes and their swapsizes
-------------------------------------
PID | SWAP | PROCESSNAME |
-------------------------------------
27007 | 0 | migration/2 |
...
429 | 832 | udevd |
3169 | 832 | puppet |
3327 | 1048 | sensord |
2382 | 1800 | colord |
-------------------------------------
Overall Swap used: 24072 KiB
In case you find it interesting, you can also find the script itself at my bitbucket repository:
https://bitbucket.org/haploc/perlscripts/src/ecd4ad1e974a/getswap.pl
Feel free to leave comments on how it sucks, but do inform me of your great improvements!