Whamcloud - gitweb
land b1_5 onto HEAD
[fs/lustre-release.git] / lustre / utils / llstat.pl
index eb65e46..af22e69 100755 (executable)
 #!/usr/bin/perl
+# llstat.pl is a utility that takes stats files as input with optional 
+# clear-flag. The clear-flag is used to clear the stats file before 
+# printing stats information. The lustre stats files generally located
+# inside proc/fs/lustre/. This program first reads the required statistics
+# information from specified stat file, process the information and prints
+# the output after every interval specified by user.
 
-my $pname = $0;
-
+# Subroutine for printing usages information
 sub usage()
 {
-    print STDERR "Usage: $pname <stats_file> [<interval>]\n";
-    exit 1;
-}
-
-
-my $statspath;
-my $interval = 0;
-
-if (($#ARGV < 0) || ($#ARGV > 1)) {
-    usage();
-} else {
-    $statspath = $ARGV[0];
-    if ($#ARGV == 1) {
-       $interval = $ARGV[1];
-    } 
+       print STDERR "Usage: $pname [-c] [-g] [-i <interval>] [-h <help>] <stats_file>\n";
+       print STDERR "       stats_file : /proc/fs/lustre/.../stat\n";
+       print STDERR "       -i interval: polling period\n";
+       print STDERR "       -c         : clear stats file first\n";
+       print STDERR "       -g         : graphable output format\n";
+       print STDERR "       -h         : help, display this information\n";
+       print STDERR "example: $pname -i 1 ost (monitors /proc/fs/lustre/ost/OSS/ost/stats)\n";
+       print STDERR "Use CTRL + C to stop statistics printing\n";
+       exit 1;
 }
 
-
-
-my %namehash;
-my $anysum = 0;
-my $anysumsquare = 0;
-my $mhz = 0;
-
-sub get_cpumhz()
-{
-    my $cpu_freq;
-    my $itc_freq; # On Itanium systems use this
-    if (open(CPUINFO, "/proc/cpuinfo")==0) {
-       return;
-    }
-    while (<CPUINFO>) {
-       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; }
+sub print_headings()
+{      my $cc = $_[0];
+       if ($graphable) {
+               if ( $print_once && $interval ) {
+                       printf "Timestamp [Name Count Rate Total Unit]...";
+                       printf "\n--------------------------------------------------------------------";
+                       $print_once = 0;
+               }
+               if ($cc && !$starttime) {
+                       $starttime = $cc
+               }
+               printf "\n%-5.0f", ($cc - $starttime);
+       } else {
+               printf "$statspath @ $cc\n";
+               printf "%-25s %-10s %-10s %-10s", "Name", "Cur.Count", "Cur.Rate", "#Events";
+               if ( $anysum ) {
+                       printf "%-8s %10s %10s %12s %10s", "Unit", "last", "min", "avg", "max";
+               }
+               if ( $anysumsquare ) {
+                       printf "%10s", "stddev";
+               }
+               printf "\n";
+       }
 }
 
-get_cpumhz();
-print "Processor counters run at $mhz MHz\n";
-
+# known units are: reqs, bytes, usec, bufs, regs, pages
+# readstat subroutine reads and processes statistics from stats file.
+# This subroutine gets called after every interval specified by user.
 sub readstat()
 {
-    open(STATS, $statspath) || die "Cannot open $statspath: $!\n";
-    while (<STATS>) {
+       seek STATS, 0, 0;
+       while (<STATS>) {
        chop;
        ($name, $cumulcount, $samples, $unit, $min, $max, $sum, $sumsquare) 
-           = split(/\s+/, $_);
-
-       $prevcount = %namehash->{$name};
+               = split(/\s+/, $_);
+       $prevcount = %cumulhash->{$name};
        if (defined($prevcount)) {
-           $diff = $cumulcount - $prevcount;
-           if ($name eq "snapshot_time") {
-               $tdiff = $diff;
-               # printf "%-25s prev=$prevcount, cumul=$cumulcount diff=$diff, tdiff=$tdiff\n", $name;
-               printf "$statspath @ $cumulcount\n";
-               printf "%-25s %-10s %-10s %-10s", "Name", "Cur.Count", "Cur.Rate", "#Events";
-               if ($anysum) {
-                   printf "%-8s %10s %12s %10s", "Unit", "min", "avg", "max";
-               }
-               if ($anysumsquare) {
-                   printf "%10s", "stddev";
+               $diff = $cumulcount - $prevcount;
+               if ($name eq "snapshot_time") {
+                       $tdiff = int($diff);
+                       &print_headings($cumulcount);
+                       $| = 1;
+                       if ($tdiff == 0) {
+                           $tdiff = 1; # avoid division by zero
+                       }
                }
-                printf "\n";
-               $| = 1;
-           }
-           elsif ($cumulcount!=0) {
-               printf "%-25s %-10lu %-10lu %-10lu",
-                      $name, $diff, ($diff/$tdiff), $cumulcount;
-               
-               if (defined($sum)) {
-                   my $sum_orig = $sum;
-                   if (($unit eq "[cycles]") && ($mhz != 1)) {
-                       $unit = "[usecs]";
-                       $min = $min/$mhz;
-                       $sum = $sum/$mhz;
-                       $max = $max/$mhz;
-                   }
-                   printf "%-8s %10lu %12.2f %10lu", $unit, $min, ($sum/$cumulcount), $max;
-                   if (defined($sumsquare)) {
-                       my $s = $sumsquare - (($sum_orig*$sum_orig)/$cumulcount);
-                       if ($s >= 0) {
-                           my $cnt = ($cumulcount >= 2) ? $cumulcount : 2 ;
-                           my $stddev = sqrt($s/($cnt - 1));
-                           if (($unit eq "[usecs]") && ($mhz != 1)) {
-                               $stddev = $stddev/$mhz;
+               elsif ($cumulcount!=0) {
+                       if ($graphable) {
+                           my $myunit = $unit;
+                           my $myname = $name;
+                           if (defined($sum)) {
+                               $myunit = "[reqs]";
+                               $myname = $myname . "_rq";
                            }
-                           printf " %10.2f", $stddev;
+                           printf "   %s %lu %lu %lu %s", 
+                           $myname, $diff, ($diff/$tdiff), $cumulcount, $myunit;
+                       } else {
+                           printf "%-25s %-10lu %-10lu %-10lu",
+                           $name, $diff, ($diff/$tdiff), $cumulcount;
+                       }
+                       if (defined($sum)) {
+                               my $sum_orig = $sum;
+                               my $sum_diff = $sum - %sumhash->{$name};
+                               if ($graphable) {
+                                   printf "   %s %lu %.2f %lu %s",
+                                   $name, $sum_diff, ($sum_diff/$tdiff), $sum, $unit;
+                               } else {
+                                   printf "%-8s %10lu %10lu %12.2f %10lu", $unit, 
+                                   $sum_diff, $min, ($sum/$cumulcount), $max;
+                               }
+                               if (defined($sumsquare)) {
+                                       my $s = $sumsquare - (($sum_orig*$sum_orig)/$cumulcount);
+                                       if ($s >= 0) {
+                                               my $cnt = ($cumulcount >= 2) ? $cumulcount : 2 ;
+                                               my $stddev = sqrt($s/($cnt - 1));
+                                               if (!$graphable) {
+                                                       printf " %9.2f ", $stddev;
+                                               }
+                                       }
+                               }
                        }
-                   }
+                       if (!$graphable) {
+                               printf "\n";
+                       }
+                       $| = 1;
+               }
+       } else {
+               if ($cumulcount!=0) {
+                       # print info when interval is not specified.
+                       printf "%-25s $cumulcount\n", $name
+               }
+               if (defined($sum)) {
+                       $anysum = 1;
+               }
+               if (defined($sumsquare)) {
+                       $anysumsquare = 1;
                }
-               printf "\n";
-               $| = 1;
-           }
-       }
-       else {
-           if ($cumulcount!=0) {
-               printf "%-25s $cumulcount\n", $name     
-           }
-           if (defined($sum)) {
-               $anysum = 1;
-           }
-           if (defined($sumsquare)) {
-               $anysumsquare = 1;
-           }
        }
-       %namehash->{$name} = $cumulcount;
-    }
+       %cumulhash->{$name} = $cumulcount;
+       %sumhash->{$name} = $sum;
+       } #end of while
 }
 
+#Globals
+$pname = $0;
+$defaultpath = "/proc/fs/lustre";
+$obdstats = "stats";
+$clear = 0;
+$graphable = 0;
+$interval = 0;
+$statspath = "None";
+$anysumsquare = 0;
+$mhz = 0;
+$print_once = 1;
+%cumulhash;
+%sumhash;
+$anysum = 0;
+$obddev = "";
+$starttime = 0;
+$ONE_MB = 1048576;
+
+# Command line parameter parsing
+use Getopt::Std;
+getopts('hcgi:') or usage();
+usage() if $opt_h;
+$clear = 1 if $opt_c;
+$graphable = 1 if $opt_g;
+$interval = $opt_i if $opt_i;
+
+my $i = 0;
+foreach (@ARGV) {
+        $obddev = $_;
+        $i++;
+        if ($i > 1) {
+                print "ERROR: extra argument $_\n";
+                usage();
+        }
+}
+if ( !$obddev ) {
+       print "ERROR: Need to specify stats_file\n";
+       usage();
+}
+# Process arguments
+if ( -f $obddev ) {
+       $statspath = $obddev;
+} elsif ( -f "$obddev/$obdstats" ) {
+       $statspath = "$obddev/$obdstats";
+} else {
+       my $st = glob("$defaultpath/*/$obddev/$obdstats");
+       if ( -f "$st" ) {
+               $statspath = $st;
+       } else {
+               $st = glob("$defaultpath/*/*/$obddev/$obdstats");
+               if ( -f "$st" ) {
+                       $statspath = $st;
+               }
+       }
+}
+if ( $statspath =~ /^None$/ ) {
+       die "Cannot locate stat file for: $obddev\n";
+}
+# Clears stats file before printing information in intervals
+if ( $clear ) {
+       open ( STATS, "> $statspath") || die "Cannot clear $statspath: $!\n";
+       print STATS " ";
+       close STATS;
+       sleep($interval);           
+}
+use POSIX qw(strftime);
+$time_v = time();
+$hostname = `lctl list_nids | head -1`;
+chop($hostname);
+print "$pname: STATS on ", strftime("%D", localtime($time_v));
+print " $statspath on $hostname\n";
+open(STATS, $statspath) || die "Cannot open $statspath: $!\n";
 do {
-    readstat();
-    if ($interval) { 
-       sleep($interval);
-    }
+       readstat();
+       if ($interval) { 
+               sleep($interval);
+       }
 } while ($interval);
+close STATS;