List all processes and how much swap they use

Sometimes I see that my computer uses a lot of swap space, but none of the system monitors (e.g. ps, Gnome’s System Monitor, top, btop) show which processes are to blame. There’re several memory metrics (e.g. total swap usage), but never per process swap usage. 😠

There’s a StackExchange question that asks the same thing, but the solutions are all not well scripted, slow or “meh” for other reasons … so I tackled the problem myself. 😝

All the information is basically buried in the /proc/*/status files. Among other things they contain the amount of swap a process uses, its PID and even better: its name. So we have to go through all the files, grep the useful lines, extract the data from those lines and recombine them.

I tried different combinations of grep and sed and Bash string interpolation … and while it worked, it was even slower than the StackExchange suggestions. 😯😅😞 This looked more and more like a “if I knew grep/sed/awk better I wouldn’t need to invoke 4 sub shells/pipes/processes for each file” kind of problem. I remembered Bryan Cantrill making an offhanded remark once that awk had a simple and concise language and a great manual.

If you get the awk programming language manual…you’ll read it in about two hours and then you’re done. That’s it. You know all of awk.

Bryan Cantrill

I had put off diving in for too long. So I started reading and roughly 20 minutes in I knew enough to solve the whole problem (almost) entirely in awk (it still needs the shell for filename globbing 😕🤷). And … it’s blazingly fast! And … you can also combine it with sort and head to quickly find the worst offenders. 😎

You can find the code in this Gist. There’s a simpler version in an earlier revision. 😉

#!/bin/bash
#
# Riyad Preukschas <riyad@informatik.uni-bremen.de>
# License: Mozilla Public License 2.0
# SPDX-License-Identifier: MPL-2.0
#
# List all processes and how much swap they use.
# The output format is: "<swap used> : <pid> : <process name>"
#
# To get the top 10 processes using swap you can run:
# lsswap | sort -hr | head -n10
files=(/proc/*/status)
exec awk '
BEGINFILE {
# skip files that cannot be opened
if ( ERRNO != "" ) {
nextfile
}
}
/^VmSwap:/ {
vmswap = $2;
vmswap_unit = $3;
# force conversion to a number
vmswap += 0
# make units more human readable
if (vmswap_unit == "kB" && vmswap > 1000) {
vmswap /= 1000
vmswap_unit = "MB"
}
if (vmswap_unit == "MB" && vmswap > 1000) {
vmswap /= 1000
vmswap_unit = "GB"
}
}
/^Name:/ { name = $2 }
/^Pid:/ { pid = $2 }
ENDFILE {
# skip processes that cannot be swapped or are not using swap at all
if (length(vmswap) != 0 && vmswap != 0) {
printf "%1.1f%s : %d : %s\n", vmswap, vmswap_unit, pid, name
}
}
' "${files[@]}"
view raw lsswap hosted with ❤ by GitHub

Leave a Reply

Your email address will not be published. Required fields are marked *