--- /dev/null
+#!/usr/bin/perl
+
+my $pname = $0;
+
+my $defaultpath = "/proc/fs/lustre";
+my $obdstats = "stats";
+
+sub usage()
+{
+ print STDERR "Usage: $pname <stats_file> [<interval>]\n";
+ print STDERR "example: $pname help (to get help message)\n";
+ print STDERR "example: $pname ost1 1 (monitor /proc/fs/lustre/ost1/obd_stats once per second\n";
+ exit 1;
+}
+
+my $statspath = "None";
+my $interval = 0;
+
+if (($#ARGV < 0) || ($#ARGV > 1)) {
+ usage();
+} else {
+ if ( $ARGV[0] =~ /help$/ ) {
+ 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;
+ if ( -f "$st" ) {
+ $statspath = $st;
+ }
+ }
+ if ( $statspath =~ /^None$/ ) {
+ die "Cannot locate stat file for: $ARGV[0]\n";
+ }
+ if ($#ARGV == 1) {
+ $interval = $ARGV[1];
+ }
+}
+
+print "$pname on $statspath\n";
+
+my %cur;
+my %last;
+my $mhz = 0;
+my ($read_bytes, $read, $write_bytes, $write, $getattr, $setattr, $open, $close, $create, $destroy, $statfs, $punch, $snapshot_time) =
+ ("read_bytes", "read", "write_bytes", "write", "getattr", "setattr", "open", "close", "create", "destroy", "statfs", "punch", "snapshot_time");
+
+my @extinfo = ($setattr, $open, $close, $create, $destroy, $statfs, $punch);
+my %shortname = ($setattr => "sa", $open => "op", $close => "cl",
+ $create => "cx", $destroy => "dx", $statfs => "st", $punch => "pu");
+
+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; }
+ close CPUINFO;
+}
+
+get_cpumhz();
+print "Processor counters run at $mhz MHz\n";
+
+sub readall()
+{
+ my $prevcount;
+ my @iodata;
+
+ seek STATS, 0, 0;
+ while (<STATS>) {
+ 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];
+ }
+ }
+}
+sub process_stats()
+{
+ my $delta;
+ my $data;
+ my $last_time = $last{$snapshot_time};
+ if (!defined($last_time)) {
+ printf "R %-g/%-g W %-g/%-g attr %-g/%-g open %-g/%-g create %-g/%-g stat %-g punch %-g\n",
+ $cur{$read_bytes}, $cur{$read},
+ $cur{$write_bytes}, $cur{$write},
+ $cur{$getattr}, $cur{$setattr},
+ $cur{$open}, $cur{$close},
+ $cur{$create}, $cur{$destroy},
+ $cur{$statfs}, $cur{$punch};
+ }
+ else {
+ my $timespan = $cur{$snapshot_time} - $last{$snapshot_time};
+
+ my $rdelta = $cur{$read} - $last{$read};
+ my $rvdelta = int ($rdelta / $timespan);
+ my $rrate = ($cur{$read_bytes} - $last{$read_bytes}) /
+ ($timespan * ( 1 << 20 ));
+ my $wdelta = $cur{$write} - $last{$write};
+ my $wvdelta = int ($wdelta / $timespan);
+ my $wrate = ($cur{$write_bytes} - $last{$write_bytes}) /
+ ($timespan * ( 1 << 20 ));
+ printf "R %6lu (%5lu %6.2fMb)/s W %6lu (%5lu %6.2fMb)/s",
+ $rdelta, $rvdelta, $rrate,
+ $wdelta, $wvdelta, $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";
+ }
+}
+
+open(STATS, $statspath) || die "Cannot open $statspath: $!\n";
+do {
+ readall();
+ process_stats();
+ if ($interval) {
+ sleep($interval);
+ %last = %cur;
+ }
+} while ($interval);
+close STATS;
+