#!/usr/bin/perl # # swapinfo Print Virtual Memory statistics (swap). Solaris 9+. # # Prints swap usage details for RAM and disk based swap. This can be run # as any user as it uses the Perl Kstat library and "swap -l". # # 28-Nov-2004 ver 0.61 (UNDER CONSTRUCTION, check for newer versions) # # # USAGE: swapinfo [ -h ] # swapinfo # print stats # swapinfo -h # print help # # This program appears to pause for a second while calculating values - # this is necessary as some of the variables used are counters that are # incremented every second. # # FIELDS: # RAM Total Total RAM installed # RAM Unusable RAM consumed by the OBP and TSBs # RAM Kernel Kernel resident in RAM (and usually locked) # RAM Locked Locked memory pages from swap (Anon) # RAM Used Anon, Exec + Libs, Page cache # RAM Avail Free memory that can be immediately used # Disk Total Total disk swap configured # Disk Alloc Disk swap allocated (used by pageouts) # Disk Free Disk swap free # Swap Total Total swap usable # Swap Alloc swap allocated (used) # Swap Unalloc swap reserved but not allocated # Swap Avail swap available for reservation # Swap MinFree swap kept free from reservations # # NOTE: Due to limited info from Kstat some assumptions needed to be made. # Under some circumstances (swapped out kernel pages) Ram Kernel and Ram Locked # may not be accurate. I assume swapfs_minfree hasn't been changed from the # default. This is the best I can do from Kstat alone (and without access to # the Solaris source code!). For other techniques see the "SEE ALSO" section. # # REFERENCE: http://www.brendangregg.com/k9toolkit.html - the swap diagram. # # SEE ALSO: vmstat 1 2; swap -s; echo ::memstat | mdb -k # RMCmem - The MemTool Package # RICHPse - The SE Toolkit # "Clearing up swap space confusion" Unix Insider, Adrian Cockcroft # "Solaris Internals", Jim Mauro, Richard McDougall # /usr/include/vm/anon.h, /usr/include/sys/systm.h # # COPYRIGHT: Copyright (c) 2004 Brendan Gregg. # # 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 2 # 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, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # (http://www.gnu.org/copyleft/gpl.html) # # 08-Aug-2004 Brendan Gregg Created this. # 15-Aug-2004 " " Included a "swap -l" for more accurate values. use Sun::Solaris::Kstat; my $Kstat = Sun::Solaris::Kstat->new(); # # --- Process command line args --- # if ($ARGV[0] eq "-h" || $ARGV[0] eq "--help") { &usage(); } $DEBUG = 0; $DEBUG = 1 if $ARGV[0] eq "-d"; # # --- Fetch Hardware info --- # ### pagesize $ENV{PATH} = "/usr/bin"; chomp($PAGESIZE = `pagesize`); $PAGETOMB = $PAGESIZE / (1024 * 1024); $BLOCKTOP = 512 / $PAGESIZE; ### RAM total $ram_total = 0; foreach $i (keys(%{$Kstat->{lgrp}})) { # instance foreach $c (keys(%{$Kstat->{lgrp}->{$i}})) { # class $ram_total += $Kstat->{lgrp}->{$i}->{$c}->{"pages installed"}; } } ### RAM available for the OS $physmem = $Kstat->{unix}->{0}->{system_pages}->{physmem}; $pagestotal = $Kstat->{unix}->{0}->{system_pages}->{pagestotal}; # # --- Fetch VM info --- # foreach $count (0..12) { # # The values are counters that increment each second, here we # check them several times and look for the value changing. # (reading them once then again a second later was not reliable). # foreach $var ("swap_resv","swap_avail","swap_alloc","swap_free", "freemem") { $VMnow{$var} = $Kstat->{unix}->{0}->{vminfo}->{$var}; unless ($count) { $VMold{$var} = $VMnow{$var}; next; } if (($VMnow{$var} != $VMold{$var}) && (! $VMinfo{$var})) { $VMinfo{$var} = $VMnow{$var} - $VMold{$var}; } } select(undef, undef, undef, 0.1); $Kstat->update(); } $freemem = $Kstat->{unix}->{0}->{system_pages}->{freemem}; $availrmem = $Kstat->{unix}->{0}->{system_pages}->{availrmem}; $pageslocked = $Kstat->{unix}->{0}->{system_pages}->{pageslocked}; $pp_kernel = $Kstat->{unix}->{0}->{system_pages}->{pp_kernel}; # # --- Fetch Disk Swap --- # ($disk_total,$disk_free) = &SwapList(); # # --- Calculations --- # ### Swap $swap_resv = $VMinfo{swap_resv}; $swap_free = $VMinfo{swap_free}; $swap_avail = $VMinfo{swap_avail}; $swap_alloc = $VMinfo{swap_alloc}; $swap_unalloc = $swap_free - $swap_avail; $swap_total = $swap_resv + $swap_avail; # assume this hasn't been tuned, $swapfs_minfree = int($physmem / 8); ### RAM $ram_unusable = $ram_total - $pagestotal; if ($pp_kernel < $pageslocked) { # here we assume all pp_kernel pages are in memory, $ram_kernel = $pp_kernel; $ram_locked = $pageslocked - $pp_kernel; } else { # here we assume pageslocked is entirerly kernel, $ram_kernel = $pageslocked; $ram_locked = 0; } $ram_used = $pagestotal - $freemem - $ram_kernel - $ram_locked; ### Disk # "swap -l" technique, $disk_alloc = $disk_total - $disk_free; # Kstat only technique (inaccurate, and only printed in debug mode), $disk_totalb = $swap_total - $availrmem - $ram_locked + $swapfs_minfree; $disk_avail = $swap_avail + $swapfs_minfree - $freemem; # assumptions here for $disk_avail = $disk_totalb if $disk_avail > $disk_total; # swapfs_minfree usage $disk_resv = $disk_totalb - $disk_avail; ### format values @Values = qw(disk_total disk_free disk_alloc disk_totalb disk_avail disk_resv freemem availrmem physmem pagestotal pageslocked pp_kernel ram_total ram_kernel ram_used ram_unusable ram_locked swap_unalloc swap_total swap_resv swap_avail swap_alloc swap_free swapfs_minfree); foreach $var (@Values) { # nothing to see here, move along, move along, ... ${"${var}_Mb"} = sprintf("%7.1f Mb",$$var * $PAGETOMB); } # # --- Print Debug --- # if ($DEBUG) { print < /dev/null`; unshift(@Lines); # drop header foreach $line (@Lines) { ($total,$free) = $line =~ /(\d+)\s+(\d+)$/; next unless $total; $sum_total += $total; $sum_free += $free; } ### Return as pages return ($sum_total * $BLOCKTOP,$sum_free * $BLOCKTOP); } # usage - print usage message and exit. # sub usage { print STDERR <