2 # llobdstat is a utility that parses OST statistics files
3 # found at e.g. obdfilter.<ostname>.stats or osc.<ostname>*.stats.
4 # It is mainly useful to watch the bandwidth usage over time.
8 my $obdstats = "stats";
9 my $statspath = "None";
10 my $statsname = $obdstats;
12 my $counter = 999999999;
20 print STDERR "Monitor read/write bandwidth of an OST device\n";
21 print STDERR "Usage: $pname [-h] [-i <interval>] [-v] <ost_name> [<interval> [<count>}]\n";
22 print STDERR " stats_file : Lustre 'stats' file to watch\n";
23 print STDERR " -d : debug mode\n";
24 print STDERR " -h : help, display this information\n";
25 print STDERR " -i interval: polling period in seconds\n";
26 print STDERR " -n count : number of samples printed\n";
27 print STDERR "example: $pname -i 5 lustre-OST0000\n";
28 print STDERR "Use CTRL + C to stop statistics printing\n";
32 # Command line parameter parsing
34 getopts('dhi:n:') or usage();
36 $debug = $opt_d if $opt_d;
37 $interval = $opt_i if $opt_i;
38 $counter = $opt_n if $opt_n;
50 print "ERROR: extra argument $_\n";
56 print "ERROR: Need to specify stats_file\n";
61 my $procpath = "/proc/fs/lustre";
62 foreach my $param ( "$obddev", "$obddev*/$obdstats", "$obddev*/*/$obdstats",
63 "*/$obddev*/$obdstats", "*/*/$obddev*/$obdstats" ) {
65 printf "trying $procpath/$param\n";
67 my $st = glob("$procpath/$param");
70 $statsname = `lctl list_param $param | head -n 1`;
72 print "using $statspath\n"
77 if ($statspath =~ /^None$/) {
78 # server stats are currently in /proc/fs/lustre, but may move eventually
79 $procpath = "/sys/kernel/debug/lustre";
81 foreach my $param ( "$obddev", "$obddev*/$obdstats", "$obddev*/*/$obdstats",
82 "*/$obddev*/$obdstats", "*/*/$obddev*/$obdstats" ) {
84 print "trying $procpath/$param\n";
86 $st = glob("$procpath/$param");
88 print "glob $procpath/$param = $st\n";
92 $statsname = `lctl list_param $param | head -n 1`;
94 print "using $statspath\n"
99 if ($statspath =~ /^None$/) {
100 die "Cannot locate stat file for: $obddev\n";
104 # check if Term::ReadKey is installed for efficient tty size, but OK if missing
105 eval "require Term::ReadKey" or $have_readkey = 0;
107 print "have_readkey=$have_readkey\n";
110 eval "use Term::ReadKey";
113 print "$pname on $statsname\n";
118 # Removed some statstics like open, close that the OST doesn't contain.
119 # To add statistics parameters one needs to specify parameter names in the
120 # below declarations in the same sequence.
121 my ($read_bytes, $write_bytes, $create, $destroy, $statfs, $punch, $timestamp) =
122 ("read_bytes", "write_bytes", "create", "destroy", "statfs", "punch",
125 my @extinfo = ($create, $destroy, $statfs, $punch);
126 my %shortname = ($create => "cx", $destroy => "dx", $statfs => "st", $punch => "pu");
128 # read statistics from the stats file.
129 # This subroutine gets called after every interval specified by user.
138 @iodata = split(/\s+/, $_);
139 my $name = $iodata[0];
141 $prevcount = $cur{$name};
142 if (defined($prevcount)) {
143 $last{$name} = $prevcount;
145 if ($name =~ /^$timestamp$/) {
146 $cur{$name} = $iodata[1];
147 } elsif ($name =~ /^$read_bytes$/) {
148 if (defined($cur{"read_ops"})) {
149 $last{"read_ops"} = $cur{"read_ops"};
151 $cur{"read_ops"} = $iodata[1];
152 $cur{$name} = $iodata[6];
153 } elsif ($name =~ /^$write_bytes$/) {
154 if (defined($cur{"write_ops"})) {
155 $last{"write_ops"} = $cur{"write_ops"};
157 $cur{"write_ops"} = $iodata[1];
158 $cur{$name} = $iodata[6];
160 $cur{$name} = $iodata[1];
165 # process stats information read from the stats file.
166 # This subroutine gets called after every interval specified by user.
171 my $last_time = $last{$timestamp};
172 if (!defined($last_time)) {
173 printf "Read: %.1f GiB, Write: %.1f GiB, cr: %lu dx: %lu, st: %lu, pu: %lu\n",
174 $cur{$read_bytes} / (1 << 30), $cur{$write_bytes} / (1 << 30),
175 $cur{$create}, $cur{$destroy}, $cur{$statfs}, $cur{$punch};
176 print "[NOTE: cx: create, dx: destroy, st: statfs, pu: punch]\n\n";
178 my $timespan = $cur{$timestamp} - $last{$timestamp};
179 my $rtot = ($cur{$read_bytes} - $last{$read_bytes}) / (1 << 20);
180 my $riops = ($cur{"read_ops"} - $last{"read_ops"}) / $timespan;
181 my $rrate = $rtot / $timespan;
182 my $wtot = ($cur{$write_bytes} - $last{$write_bytes}) / (1 << 20);
183 my $wiops = ($cur{"write_ops"} - $last{"write_ops"}) / $timespan;
184 my $wrate = $wtot / $timespan;
186 # this is printed once per screen, like vmstat/iostat
187 if ($count++ % ($height - 2) == 0) {
188 print "Timestamp Read-MiB RdMiB/s WriteMiB WrMiB/s RdIOPS WrIOPS\n";
189 print "---------- -------- ------- -------- ------- ------ ------\n";
191 ($width, $height, $wpixels, $hpixels) = GetTerminalSize();
193 ($height, $width) = split / /, `stty size 2> /dev/null`;
194 #$width = 120 if ! $width
197 # This print repeats after every interval.
198 printf "%10lu %8.1f %7.1f %8.1f %7.1f %6lu %6lu",
199 $cur{$timestamp}, $rtot, $rrate, $wtot, $wrate, $riops, $wiops;
201 $delta = $cur{$getattr} - $last{$getattr};
203 $rdelta = int ($delta/$timespan);
204 print " ga:$delta,$rdelta/s";
207 for $data ( @extinfo ) {
208 $delta = $cur{$data} - $last{$data};
210 print " $shortname{$data}:$delta";
218 #Open the stat file with STATS
219 open(STATS, $statspath) || die "Cannot open $statspath: $!\n";
221 # read the statistics from stat file.
228 # Repeat the statistics printing after every "interval" specified in
229 # command line, up to counter times, if specified
230 } while ($interval && $counter-- > 0);