I only started looking into it yesterday for my needs, below is what I've found so far:
SWAP_USED = Used_by_Processes + SwapCached + Part_of_Tmpfs + something_else
Short story:
Used_by_Processes – data that has been swapped out from memory completely.
SwapCached – data that has been swapped to disk, but still remains in memory.
Part_of_Tmpfs – some portion of tmpfs data.
Long story:
Used_by_Processes – there are many instructions published on how to mis-calculate this one ;) E.g. if we sum up all VmSwap entries from /proc/*/status or Swap entries from /proc/*/smaps - we will get an overestimate (shared swapped pages could get counted more than once). If we don't run it from root user or our OS - the underestimate will be silently returned. I don't have a proper way of identifying shared pages, but splashing of same 'maps' gives much better approximation than other approaches: (note that cat below is not useless and actually needs a 2>/dev/null)
[root@a:~]# cat /proc/*/status|awk ' /^VmSwap/{ s+=$2 }END{print s}' 32048 [root@a:~]# cat /proc/*/smaps|awk ' /^Swap/{ s+=$2 }END{print s}' 32048 [root@a:~]# cat /proc/*/smaps|awk '/-/{r=$0}/^Swap/{if(R[r]!=1)s+=$2;R[r]=1}END{print s}' 14940 [root@a:~]# free -k|grep -e Swap -e used total used free shared buffers cached Swap: 8388600 15508 8373092
SwapCached – this one is straightforward and can be cleanly extracted from /proc/meminfo. Some people wouldn't expect this to be counted as "used" swap, since a duplicate (non-dirty) copy of same page in both RAM and Swap can be freed on either side quite instantly (in case if demand comes) thus making one of the copies "freed".
Part_of_Tmpfs – the bright side is that when all Your tmpfs data is many-days-untouched and swappiness is non-zero - it's quite likely that entire tmpfs is swapped-out (and vice-versa for recently-used data). The downside is I've found no API to reliably calculate the threshold or percentage of how much of it IS swapped, though if there's enough RAM - we can copy entire tmpfs data into /dev/null and thus get some clue of how much of it WAS swapped.
Common mistakes made during calculation of tmpfs size are - assuming that /dev/shm is the only tmpfs configured or trying to do it by recursive per-file scanning (not only implementations tend to omit hidden files or do it from non-root, but it also un-swaps some pages during traversing). Much easier way is to use good old df.
something_else – see the "diff 385 MB" below, needs a dive into kernel sources. See my script:
#!/bin/bash TMPFS=`df -kP |awk ' /^tmpfs/{ s+=$3 }END{print int( s/1024)}'` PROCS=`cat /proc/*/smaps|awk '/-/{r=$0} /^Swap/{if(R[r]!=1)s+=$2;R[r]=1}END{print int( s/1024)}'` SCACH=`cat /proc/meminfo|awk ' /^SwapCached/ {print int($2/1024)}'` TOTAL=`free -k |awk ' /^Swap/ {print int($3/1024)}'` echo -e " df $TMPFS\t smaps $PROCS \tSwapCache $SCACH\t| $TOTAL\tswap | diff $[TOTAL-TMPFS-PROCS-SCACH]\tMB"
and the output from different boxes:
xa002: df 0 smaps 271 SwapCache 3858 | 4120 swap | diff -9 MB sg003: df 0 smaps 234 SwapCache 3876 | 4111 swap | diff 1 MB sg001: df 0 smaps 245 SwapCache 3845 | 4093 swap | diff 3 MB sg002: df 0 smaps 244 SwapCache 3843 | 4091 swap | diff 4 MB dm001: df 2 smaps 971 SwapCache 728 | 1707 swap | diff 6 MB hm012: df 270 smaps 161 SwapCache 29 | 454 swap | diff -6 MB hm003: df 274 smaps 142 SwapCache 27 | 440 swap | diff -3 MB hm006: df 262 smaps 150 SwapCache 29 | 437 swap | diff -4 MB hm002: df 265 smaps 120 SwapCache 28 | 412 swap | diff -1 MB hm009: df 258 smaps 124 SwapCache 33 | 410 swap | diff -5 MB hm011: df 262 smaps 118 SwapCache 28 | 406 swap | diff -2 MB hm008: df 245 smaps 122 SwapCache 32 | 396 swap | diff -3 MB hm005: df 247 smaps 120 SwapCache 33 | 396 swap | diff -4 MB dp001: df 0 smaps 0 SwapCache 0 | 386 swap | diff 386 MB hm014: df 184 smaps 134 SwapCache 34 | 343 swap | diff -9 MB hm007: df 0 smaps 132 SwapCache 32 | 158 swap | diff -6 MB bm002: df 0 smaps 121 SwapCache 25 | 141 swap | diff -5 MB dm002: df 2 smaps 70 SwapCache 71 | 139 swap | diff -4 MB bm001: df 3 smaps 102 SwapCache 28 | 131 swap | diff -2 MB bm004: df 0 smaps 98 SwapCache 29 | 126 swap | diff -1 MB hm013: df 0 smaps 100 SwapCache 30 | 124 swap | diff -6 MB bm006: df 0 smaps 103 SwapCache 15 | 122 swap | diff 4 MB hm010: df 0 smaps 102 SwapCache 24 | 122 swap | diff -4 MB hm001: df 0 smaps 101 SwapCache 25 | 121 swap | diff -5 MB bm003: df 0 smaps 98 SwapCache 15 | 107 swap | diff -6 MB bm005: df 0 smaps 70 SwapCache 17 | 85 swap | diff -2 MB sg004: df 0 smaps 72 SwapCache 14 | 83 swap | diff -3 MB sg001: df 0 smaps 41 SwapCache 33 | 78 swap | diff 4 MB sg005: df 0 smaps 59 SwapCache 20 | 75 swap | diff -4 MB sg003: df 0 smaps 58 SwapCache 18 | 72 swap | diff -4 MB sg006: df 0 smaps 56 SwapCache 13 | 65 swap | diff -4 MB sg002: df 0 smaps 54 SwapCache 12 | 64 swap | diff -2 MB xa001: df 0 smaps 56 SwapCache 5 | 55 swap | diff -6 MB
And a small experiment as the bonus:
[root@hm012:~]# df -h|grep -e '^Filesystem' -e '^tmpfs' Filesystem Size Used Avail Use% Mounted on tmpfs 12G 271M 12G 3% /dev/shm tmpfs 8.0G 84K 8.0G 1% /tmp [root@hm012:~]# ./get_swap.sh df 270 smaps 161 SwapCache 29 | 454 swap | diff -6 MB [root@hm012:~]# rm -rf /dev/shm/* [root@hm012:~]# df -h|grep -e '^Filesystem' -e '^tmpfs' Filesystem Size Used Avail Use% Mounted on tmpfs 12G 0 12G 0% /dev/shm tmpfs 8.0G 84K 8.0G 1% /tmp [root@hm012:~]# ./get_swap.sh df 0 smaps 161 SwapCache 29 | 185 swap | diff -5 MB
P.S. aside from the approximation mentioned above - there are other sources of error, like rounding of KB into MB, theoretical possibility of a mismatch between block-sizes of RAM and Swap, etc. I'm not sure it covers everything, but hoping this helps to some extent :)