X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fllobdstat;h=7a3a4ba98b9514a691f1e8683004b28d59378707;hb=cd4caef54f;hp=300c9d882bbc56ab548eb9124fcd6a19325b9d16;hpb=073e67f1647008c721d452ee3862c3f643f6c248;p=fs%2Flustre-release.git diff --git a/lustre/utils/llobdstat b/lustre/utils/llobdstat old mode 100644 new mode 100755 index 300c9d8..7a3a4ba --- a/lustre/utils/llobdstat +++ b/lustre/utils/llobdstat @@ -1,170 +1,231 @@ #!/usr/bin/perl -# llobdstat is a utility that parses obdfilter statistics files -# found at proc/fs/lustre//stats. -# It is mainly useful to watch the statistics change over time. +# llobdstat is a utility that parses OST statistics files +# found at e.g. obdfilter..stats or osc.*.stats. +# It is mainly useful to watch the bandwidth usage over time. my $pname = $0; - -my $defaultpath = "/proc/fs/lustre"; +my $obddev = ""; my $obdstats = "stats"; +my $statspath = "None"; +my $statsname = $obdstats; +my $interval = 0; +my $counter = 999999999; +my $debug = 0; +my $have_readkey = 1; +my $width = 120; +my $height = 25; sub usage() { - print STDERR "Usage: $pname []\n"; - print STDERR "where ost_name : ost name under $defaultpath/obdfilter\n"; - print STDERR " interval : sample interaval in seconds\n"; - print STDERR "example: $pname lustre-OST0000 2\n"; - print STDERR "Use CTRL + C to stop statistics printing\n"; - exit 1; + print STDERR "Monitor read/write bandwidth of an OST device\n"; + print STDERR "Usage: $pname [-h] [-i ] [-v] [ [}]\n"; + print STDERR " stats_file : Lustre 'stats' file to watch\n"; + print STDERR " -d : debug mode\n"; + print STDERR " -h : help, display this information\n"; + print STDERR " -i interval: polling period in seconds\n"; + print STDERR " -n count : number of samples printed\n"; + print STDERR "example: $pname -i 5 lustre-OST0000\n"; + print STDERR "Use CTRL + C to stop statistics printing\n"; + exit 1; } -my $statspath = "None"; -my $interval = 0; +# Command line parameter parsing +use Getopt::Std; +getopts('dhi:n:') or usage(); +usage() if $opt_h; +$debug = $opt_d if $opt_d; +$interval = $opt_i if $opt_i; +$counter = $opt_n if $opt_n; -if (($#ARGV < 0) || ($#ARGV > 1)) { - usage(); -} else { - if ( $ARGV[0] =~ /help$/ ) { +my $i = 0; +foreach (@ARGV) { + if ($i == 0) { + $obddev = $_; + $obddev =~ s/\./\//g; + } elsif ($i == 1) { + $interval = $_; + } elsif ($i == 2) { + $counter = $_; + } else { + print "ERROR: extra argument $_\n"; + usage(); + } + $i++; +} +if ( !$obddev ) { + print "ERROR: Need to specify stats_file\n"; usage(); - } - if ( -f $ARGV[0] ) { - $statspath = $ARGV[0]; - } elsif ( -f "$ARGV[0]/$obdstats" ) { - $statspath = "$ARGV[0]/$obdstats"; - } else { - my $st = `ls $defaultpath/*/$ARGV[0]/$obdstats 2> /dev/null`; - chop $st; +} + +# Process arguments +my $procpath = "/proc/fs/lustre"; +foreach my $param ( "$obddev", "$obddev*/$obdstats", "$obddev*/*/$obdstats", + "*/$obddev*/$obdstats", "*/*/$obddev*/$obdstats" ) { + if ($debug) { + printf "trying $procpath/$param\n"; + } + my $st = glob("$procpath/$param"); if ( -f "$st" ) { - $statspath = $st; + $statspath = $st; + $statsname = `lctl list_param $param | head -n 1`; + if ($debug) { + print "using $statspath\n" + } + last; + } +} +if ($statspath =~ /^None$/) { + # server stats are currently in /proc/fs/lustre, but may move eventually + $procpath = "/sys/kernel/debug/lustre"; + + foreach my $param ( "$obddev", "$obddev*/$obdstats", "$obddev*/*/$obdstats", + "*/$obddev*/$obdstats", "*/*/$obddev*/$obdstats" ) { + if ($debug) { + print "trying $procpath/$param\n"; + } + $st = glob("$procpath/$param"); + if ($debug) { + print "glob $procpath/$param = $st\n"; + } + if (-f "$st") { + $statspath = $st; + $statsname = `lctl list_param $param | head -n 1`; + if ($debug) { + print "using $statspath\n" + } + last; + } + } + if ($statspath =~ /^None$/) { + die "Cannot locate stat file for: $obddev\n"; } - } - if ( $statspath =~ /^None$/ ) { - die "Cannot locate stat file for: $ARGV[0]\n"; - } - if ($#ARGV == 1) { - $interval = $ARGV[1]; - } } -print "$pname on $statspath\n"; +# check if Term::ReadKey is installed for efficient tty size, but OK if missing +eval "require Term::ReadKey" or $have_readkey = 0; +if ($debug) { + print "have_readkey=$have_readkey\n"; +} +if ($have_readkey) { + eval "use Term::ReadKey"; +} + +print "$pname on $statsname\n"; my %cur; my %last; -my $mhz = 0; -#Removed some statstics like open, close that obdfilter don't contains. -#To add statistics parameters one need to specify parameter names in below declarations in same sequence. -my ($read_bytes, $write_bytes, $create, $destroy, $statfs, $punch, $snapshot_time) = - ("read_bytes", "write_bytes", "create", "destroy", "statfs", "punch", "snapshot_time"); +# Removed some statstics like open, close that the OST doesn't contain. +# To add statistics parameters one needs to specify parameter names in the +# below declarations in the same sequence. +my ($read_bytes, $write_bytes, $create, $destroy, $statfs, $punch, $timestamp) = + ("read_bytes", "write_bytes", "create", "destroy", "statfs", "punch", + "snapshot_time"); my @extinfo = ($create, $destroy, $statfs, $punch); my %shortname = ($create => "cx", $destroy => "dx", $statfs => "st", $punch => "pu"); -sub get_cpumhz() +# read statistics from the stats file. +# This subroutine gets called after every interval specified by user. +sub readstat() { - my $cpu_freq; - my $itc_freq; # On Itanium systems use this - if (open(CPUINFO, "/proc/cpuinfo")==0) { - return; - } - while () { - if (/^cpu MHz\s+:\s*([\d\.]+)/) { $cpu_freq=$1; } - elsif (/^itc MHz\s+:\s*([\d\.]+)/) { $itc_freq=$1; } - } - if (defined($itc_freq)) { $mhz = $itc_freq; } - elsif (defined($cpu_freq)) { $mhz = $cpu_freq; } - else { $mhz = 1; } - close CPUINFO; -} + my $prevcount; + my @iodata; -get_cpumhz(); -print "Processor counters run at $mhz MHz\n"; + seek STATS, 0, 0; + while () { + chop; + @iodata = split(/\s+/, $_); + my $name = $iodata[0]; -# readstats subroutine reads statistics from obdfilter stats file. -# This subroutine gets called after every interval specified by user. -sub readstat() -{ - my $prevcount; - my @iodata; - - seek STATS, 0, 0; - while () { - chop; -# ($name, $cumulcount, $samples, $unit, $min, $max, $sum, $sumsquare) - @iodata = split(/\s+/, $_); - my $name = $iodata[0]; - - $prevcount = $cur{$name}; - if (defined($prevcount)) { - $last{$name} = $prevcount; - } - if ($name =~ /^read_bytes$/ || $name =~ /^write_bytes$/) { - $cur{$name} = $iodata[6]; - } - elsif ($name =~ /^snapshot_time$/) { -# $cumulcount =~ /(\d+)/; - $cur{$name} = $iodata[1]; - } - else { - $cur{$name} = $iodata[1]; - } - } + $prevcount = $cur{$name}; + if (defined($prevcount)) { + $last{$name} = $prevcount; + } + if ($name =~ /^$timestamp$/) { + $cur{$name} = $iodata[1]; + } elsif ($name =~ /^$read_bytes$/) { + if (defined($cur{"read_ops"})) { + $last{"read_ops"} = $cur{"read_ops"}; + } + $cur{"read_ops"} = $iodata[1]; + $cur{$name} = $iodata[6]; + } elsif ($name =~ /^$write_bytes$/) { + if (defined($cur{"write_ops"})) { + $last{"write_ops"} = $cur{"write_ops"}; + } + $cur{"write_ops"} = $iodata[1]; + $cur{$name} = $iodata[6]; + } else { + $cur{$name} = $iodata[1]; + } + } } -# process_stats subroutine processes stats information read from obdfilter stats file. -# This subroutine gets called after every interval specified by user. + +# process stats information read from the stats file. +# This subroutine gets called after every interval specified by user. sub process_stats() { - my $delta; - my $data; - my $last_time = $last{$snapshot_time}; - if (!defined($last_time)) { - printf "Read: %-g, Write: %-g, create/destroy: %-g/%-g, stat: %-g, punch: %-g\n", - $cur{$read_bytes}, $cur{$write_bytes}, - $cur{$create}, $cur{$destroy}, - $cur{$statfs}, $cur{$punch}; - if ($interval) { - print "[NOTE: cx: create, dx: destroy, st: statfs, pu: punch ]\n\n"; - print "Timestamp Read-delta ReadRate Write-delta WriteRate\n"; - print "--------------------------------------------------------\n"; - } - } - else { - my $timespan = $cur{$snapshot_time} - $last{$snapshot_time}; - my $rdelta = $cur{$read_bytes} - $last{$read_bytes}; - my $rrate = ($rdelta) / ($timespan * ( 1 << 20 )); - my $wdelta = $cur{$write_bytes} - $last{$write_bytes}; - my $wrate = ($wdelta) / ($timespan * ( 1 << 20 )); - $rdelta = ($rdelta) / (1024 * 1024); - $wdelta = ($wdelta) / (1024 * 1024); - # This print repeats after every interval. - printf "%10lu %6.2fMB %6.2fMB/s %6.2fMB %6.2fMB/s", - $cur{$snapshot_time}, $rdelta, $rrate, $wdelta, $wrate; - - $delta = $cur{$getattr} - $last{$getattr}; - if ( $delta != 0 ) { - $rdelta = int ($delta/$timespan); - print " ga:$delta,$rdelta/s"; - } - - for $data ( @extinfo ) { - $delta = $cur{$data} - $last{$data}; - if ($delta != 0) { - print " $shortname{$data}:$delta"; - } - } - print "\n"; - $| = 1; - } + my $delta; + my $data; + my $last_time = $last{$timestamp}; + if (!defined($last_time)) { + printf "Read: %.1f GiB, Write: %.1f GiB, cr: %lu dx: %lu, st: %lu, pu: %lu\n", + $cur{$read_bytes} / (1 << 30), $cur{$write_bytes} / (1 << 30), + $cur{$create}, $cur{$destroy}, $cur{$statfs}, $cur{$punch}; + print "[NOTE: cx: create, dx: destroy, st: statfs, pu: punch]\n\n"; + } else { + my $timespan = $cur{$timestamp} - $last{$timestamp}; + my $rtot = ($cur{$read_bytes} - $last{$read_bytes}) / (1 << 20); + my $riops = ($cur{"read_ops"} - $last{"read_ops"}) / $timespan; + my $rrate = $rtot / $timespan; + my $wtot = ($cur{$write_bytes} - $last{$write_bytes}) / (1 << 20); + my $wiops = ($cur{"write_ops"} - $last{"write_ops"}) / $timespan; + my $wrate = $wtot / $timespan; + + # this is printed once per screen, like vmstat/iostat + if ($count++ % ($height - 2) == 0) { + print "Timestamp Read-MiB RdMiB/s WriteMiB WrMiB/s RdIOPS WrIOPS\n"; + print "---------- -------- ------- -------- ------- ------ ------\n"; + if ($have_readkey) { + ($width, $height, $wpixels, $hpixels) = GetTerminalSize(); + } else { + ($height, $width) = split / /, `stty size 2> /dev/null`; + #$width = 120 if ! $width + } + } + # This print repeats after every interval. + printf "%10lu %8.1f %7.1f %8.1f %7.1f %6lu %6lu", + $cur{$timestamp}, $rtot, $rrate, $wtot, $wrate, $riops, $wiops; + + $delta = $cur{$getattr} - $last{$getattr}; + if ( $delta != 0 ) { + $rdelta = int ($delta/$timespan); + print " ga:$delta,$rdelta/s"; + } + + for $data ( @extinfo ) { + $delta = $cur{$data} - $last{$data}; + if ($delta != 0) { + print " $shortname{$data}:$delta"; + } + } + print "\n"; + $| = 1; + } } -#Open the obdfilter stat file with STATS + +#Open the stat file with STATS open(STATS, $statspath) || die "Cannot open $statspath: $!\n"; do { - readstat(); # read the statistics from stat file. - process_stats(); - if ($interval) { - sleep($interval); - %last = %cur; - } -} while ($interval); # Repeat the statistics printing after every "interval" specified in command line. + # read the statistics from stat file. + readstat(); + process_stats(); + if ($interval) { + sleep($interval); + %last = %cur; + } + # Repeat the statistics printing after every "interval" specified in + # command line, up to counter times, if specified +} while ($interval && $counter-- > 0); close STATS; -# llobdfilter.pl ends here.