#!/usr/bin/perl # # loaddisk - print disk load averages (operations in wait queues). Solaris 8+. # # This Perl program uses the Sun::Solaris::Kstat library to fetch values. # # 22-Sep-2005, ver 0.82 (check for new versions, http://www.brendangregg.com) # # # USAGE: loaddisk [-h] | [interval [count]] # loaddisk # print a 1 second sample # loaddisk -h # print help # loaddisk 1 # print continually, every 1 second # loaddisk 1 5 # print 5 times, every 1 second # # The load averages are based on taking the total length of the wait # queues for all the disks, averaged across the interval. A load average # of 1.00 would indicate there was an average of one operation waiting to be # serviced (usually this is bad). 2.00 would indicate an average of two # operations in wait queues. # # A load of 0.00 indicates the disk transactions are not waiting to # be serviced, however this does not mean the disks are idle - they # may be busy but not saturated. (see iostat). # # The total number of disks needs to be taken into acocunt. A load of 1.00 # on a single disk server is probably a problem, however a load of 1.00 # on a server with ten disks only indicates that further investigation # is required (iostat, sar, ...); perhaps a single disk has a load of 1.00, # or perhaps each of the ten disks has a load of 0.10, adding to 1.00. # Currently this command does not display load on a disk by disk basis # (use iostat for now). # # NOTE: If you have an unusual disk, check it's instance name is listed # in this code (a few lines beneath this comment block). # # # SEE ALSO: kstat -m dad [interval [count]] # iostat -xnmp [interval [count]] # # REFERENCE: "How do disks really work" Adrian Cockcroft, swol-06-1996 # # 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) # # Author: Brendan Gregg [Sydney, Australia] # # 22-Mar-2004 Brendan Gregg Created this. use Sun::Solaris::Kstat; my $Kstat = Sun::Solaris::Kstat->new(); # # Disk instance names # @Disk = qw(cmdk dad sd ssd); # # --- Process command line args --- # if ($ARGV[0] eq "-h" || $ARGV[0] eq "--help" || $ARGV[0] eq "0") { &usage(); } $sleep = $ARGV[0]; $loop = $ARGV[1]; if ($sleep eq "") { $sleep = 1; $loop = 1; } elsif ($loop eq "") { $loop = 2**32; } $PAGESIZE = 20; # max lines per header $lines = $PAGESIZE; # counter for lines printed $| = 1; $Disk{$_} = 1 foreach (@Disk); # # --- Main --- # while (1) { if ($lines++ >= $PAGESIZE) { $lines = 0; printf("%8s %6s %6s %6s %6s %6s %6s\n", "Dsk Time","1sec","5sec","15sec","1min","5min","15min"); } # # Store old and get new values # unshift(@Wait,$wait); unshift(@Update,$update); ($wait,$update) = fetch(); # # Calculate load averages # $sec1 = ratio($wait,$Wait[0],$update,$Update[0]); $sec5 = ratio($wait,$Wait[4],$update,$Update[4]); $sec15 = ratio($wait,$Wait[14],$update,$Update[14]); $min1 = ratio($wait,$Wait[59],$update,$Update[59]); $min5 = ratio($wait,$Wait[299],$update,$Update[299]); $min15 = ratio($wait,$Wait[899],$update,$Update[899]); # # Print load averages # if ($sec1 ne "" && (($count % $sleep) == 0)) { @Time = localtime(); printf("%02d:%02d:%02d %6s %6s %6s %6s %6s %6s\n",$Time[2], $Time[1],$Time[0],$sec1,$sec5,$sec15,$min1,$min5,$min15); ### Check for end last if ++$printed == $loop; } $count++; ### Interval sleep (1); ### Memory cleanup pop(@Wait) if $count > 901; pop(@Update) if $count > 901; } # # --- Subroutines --- # # fetch - fetch KStat values for the disks. The values used are wlentime # and wlastupdate. # sub fetch { my ($wait,$time,$driver,$instance,$category); my (%Driver,%Instance,%Category); $wait = 0; $Kstat->update(); foreach $driver (keys(%$Kstat)) { ### Check that this is a disk structure, next unless $Disk{$driver}; $Driver = $Kstat->{$driver}; foreach $instance (keys(%$Driver)) { $Instance = $Driver->{$instance}; foreach $category (keys(%$Instance)) { ### Check that this isn't a slice next if $category =~ /,/; $Category = $Instance->{$category}; if (defined $$Category{wlentime}) { $wait += $$Category{wlentime}; # use the last wlastupdate value found, $time = $$Category{wlastupdate}; } } } } return ($wait,$time); } # ratio - calculate the ratio of the count delta over time delta; # given count and oldcount, time and oldtime. Returns a string # of the value, or a null string if not enough data was given. # sub ratio { my ($count,$oldcount,$time,$oldtime) = @_; return "" unless defined $oldtime; $countd = $count - $oldcount; $timed = $time - $oldtime; if ($timed > 0) { $ratio = $countd / $timed; } else { $ratio = 0; } return sprintf("%.2f",$ratio); } # usage - print usage and exit. # sub usage { print STDERR <