#!/usr/bin/perl -w
use strict;
# $Id: swapwho 75 2015-01-27 12:56:27Z sanders $

die "Run me as root.\n" if ($< != 0 or $> != 0);

opendir(DIR, "/proc") or die "Can't readdir /proc: $!\n";
my @pids = grep { /^\d+$/ && -d "/proc/$_" } readdir DIR;
closedir(DIR);

my $swaps = {};
foreach my $pid (@pids) {
    my $data = "";
    if (open (FD, "</proc/$pid/smaps")) {
        local $/ = undef;
        $data = <FD>; close(FD);
    } else {
        warn "Can't read /proc/$pid/smaps: $!\n";
        next;
    }

    if (not defined $data) {
        print "No data for $pid\n";
        next;
    }

    my $ttlswap = 0;
    while ($data =~ m#^Swap:.+?(\d+)#mgs) {
        next if not defined $1 or $1 == 0;
        $ttlswap += $1;
    }
    next if $ttlswap == 0;

    my $pname = `/bin/ps -p $pid -o comm --no-headers`; chomp($pname);
    $$swaps{$pid}{swapped} = $ttlswap;
    $$swaps{$pid}{name} = $pname;
}

my @sort_by_swapsize = sort { $$swaps{$a}{swapped} <=> $$swaps{$b}{swapped} } keys %$swaps;
if (not scalar @sort_by_swapsize) {
    print "No processed with swapped out data.";
    exit 0;
}

my $ttlswap = 0;
foreach my $pid (@sort_by_swapsize) {
    printf "PID %5d swapped %5d kB (%s)\n", $pid, $$swaps{$pid}{swapped}, $$swaps{$pid}{name};
    $ttlswap += $$swaps{$pid}{swapped};
}
print "Total swapped memory: $ttlswap kB\n";

__END__
# Source:
#
#!/bin/bash 
# Get current swap usage for all running processes
# Erik Ljungstrom 27/05/2011
# Modified by Mikko Rantalainen 2012-08-09
# Pipe the output to "sort -nk3" to get sorted output
SUM=0
OVERALL=0
for DIR in `find /proc/ -maxdepth 1 -type d -regex "^/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
    if (( $SUM > 0 )); then
        echo "PID=$PID swapped $SUM KB ($PROGNAME)"
    fi
    let OVERALL=$OVERALL+$SUM
    SUM=0
done
echo "Overall swap used: $OVERALL KB"
