#!/usr/bin/env perl
use strict;
use warnings;
use Time::HiRes qw( gettimeofday tv_interval );
my $mask = shift || 18; ## report every 256k lines
my $size = shift || 2**20; ## 1Mb default
$mask = 2**$mask - 1;
my $lines = my $ll = 0;
$SIG{INT} = sub {
report(1);
exit;
};
system("ps l | egrep 'PID|$$' | grep -v egrep");
print "\n\nParsing nfsdstats records, performance report every "
. ($mask + 1)
. " lines\n";
print "\nPress Ctrl-C to stop with a final report (pid $$)\n\n";
my $buf = '';
my $offset = 0;
my ($ts, $type, $op, $bytes);
my $t0 = my $tl = [gettimeofday];
my $rr = my $rrl = 0;
### Original script counters
my (
$header1, %read_ops, %write_ops, %read_bytes,
%write_bytes, @req_ops, @res_ops, $date,
$h, $d, $m, $y
);
my ($read, $write, $nops) = (0, 0, 0);
my @opnames = (
'null', 'getattr', 'setattr', 'lookup', 'access', 'ireadlink',
'read', 'write', 'create', 'mkdir', 'symlink', 'mkdir',
'remove', 'rmdir', 'rename', 'link', 'readdir', 'readdir+',
'fsstat', 'fsinfo', 'pathconf', 'commit'
);
## discard first two lines
my $n;
do {
$n = sysread(\*STDIN, $buf, $size);
die "No lines, " unless $n > 0;
} until ($buf =~ s/^.+\n.+\n//);
while () {
$n = sysread(\*STDIN, $buf, $size, length($buf));
while ($buf =~ /(.+)\n/gc) {
$lines++;
$_ = $1;
/^(\d+)/gc; $ts = $1;
/(\w)\sV/gc; $type = $1;
/\s(\d+)\s\w/gc; $op = $1;
/\w\s(\d+)\s/gc; $bytes = $1;
print "!!! Unrecognized line >>$_<<\n", next
unless $ts && $type && $op && $bytes;
### do original bookkeeping
if ($type eq 't') {
$req_ops[$op]++;
if ($op == 7) {
$write += $bytes;
$ts -= $ts % 3600; # Normalize by the hour.
$write_ops{$ts}++;
$write_bytes{$ts} += $bytes;
}
}
elsif ($type eq 'e') {
$res_ops[$op]++;
if ($op == 6) {
$read += $bytes;
$ts -= $ts % 3600; # Normalize by the hour.
$read_ops{$ts}++;
$read_bytes{$ts} += $bytes;
}
}
report() unless $lines & $mask;
}
last unless $n > 0;
$buf = substr($buf, pos($buf));
$rr += $n;
}
report(1);
sub report {
my ($final) = @_;
my $now = [gettimeofday];
my $d = tv_interval(($final ? $t0 : $tl), $now);
$tl = $now;
my $l = $lines;
$l -= $ll unless $final;
$ll = $lines;
my $r = $rr;
$r -= $rrl unless $final;
$rrl = $rr;
$r >>= 20;
my $l_rate = $d ? int($l / $d) : 'na';
my $r_rate = $d ? $r / $d : 'na';
if ($final) {
original_report();
print "\n\nFINAL PERFORMANCE REPORT:\n\n";
}
print "elapsed $d, lines $lines, rate $l_rate lines/sec (read "
. ($rr >> 20)
. " MB, rate $r_rate MB/sec)\n";
if ($final) {
print "\n\n";
system("ps l | egrep 'PID|$$' | grep -v egrep");
}
}
### Rest of original script follows
sub get_date {
my $ts = shift;
my ($h, $d, $m, $y) = (localtime($ts))[2 .. 5];
my $date =
($y + 1900)
. ($m + 1 > 9 ? $m + 1 : '0' . ($m + 1))
. ($d > 9 ? $d : '0' . $d)
. ($h > 9 ? $h : '0' . $h);
return $date;
}
sub original_report {
print "\n\nNumber of NFSOps REQUESTS:\n";
# 0..21 -> 22 opnames
for (0 .. 21) {
if ($req_ops[$_]) {
print $opnames[$_], ": \t", $req_ops[$_], "\n";
$nops += $req_ops[$_];
}
}
print "\nNumber of NFSOps RESPONSES:\n";
foreach (0 .. 21) {
print $opnames[$_], ": \t", $res_ops[$_], "\n" if ($res_ops[$_]);
}
print "Total # of NFSOPs: \t", $nops, "\n";
print "Data Read (Gb): \t", sprintf("%.2f", ($read >> 20) / 1024),
" Gb\n";
print "Data Written (Gb):\t", sprintf("%.2f", ($write >> 20) / 1024),
" Gb\n";
print "Read/Write bytes ratio:\t", sprintf("%.2f", $read / $write), "x\n";
print "Read/Write ops ratio:\t", sprintf("%.2f", $req_ops[6] / $req_ops[7]),
"x\n\n\n";
print "Number of Read Operations:\n";
foreach my $key (keys %read_ops) {
print $date, ", ", $read_ops{$key}, "\n";
}
print "\nNumber of Read Mbytes:\n";
foreach my $key (keys %read_bytes) {
print get_date($key), ", ",
sprintf("%.2f", ($read_bytes{$key} >> 10) / 1024), "\n";
}
print "\nNumber of Write Operations:\n";
foreach my $key (keys %write_ops) {
print get_date($key), ", ", $write_ops{$key}, "\n";
}
print "\nNumber of Write Mbytes:\n";
foreach my $key (keys %write_bytes) {
print get_date($key), ", ",
sprintf("%.2f", ($write_bytes{$key} >> 10) / 1024), "\n";
}
print "\n";
}