2 # llstat is a utility that takes stats files as input with optional
3 # clear-flag. The clear-flag is used to clear the stats file before
4 # printing stats information. The stats files may be in /proc/fs/lustre
5 # or /sys/kernel/debug/lustre. This first reads the required statistics
6 # information from specified stat file, process the information and prints
7 # the output after every interval specified by user.
9 # Subroutine for printing usages information
12 print STDERR "Monitor operation count/rate of a subsystem\n";
13 print STDERR "Usage: $pname [-c] [-d] [-g] [-h] [-i <interval>] [-n count] <stats_file>\n";
14 print STDERR " stats_file : Lustre 'stats' file to watch\n";
15 print STDERR " -i interval: polling period in seconds\n";
16 print STDERR " -c : clear stats file first\n";
17 print STDERR " -d : debug mode\n";
18 print STDERR " -g : graphable output format\n";
19 print STDERR " -h : help, display this information\n";
20 print STDERR " -n count : number of samples printed\n";
21 print STDERR "example: $pname -i 1 ost_io (ost.OSS.ost_io.stats)\n";
22 print STDERR "Use CTRL + C to stop statistics printing\n";
29 my $obdstats = "stats";
33 my $statspath = "None";
34 my $statsname = "stats";
44 my $counter = 999999999;
47 # Command line parameter parsing
49 getopts('cdghi:w:') or usage();
52 $debug = $opt_d if $opt_d;
53 $graphable = 1 if $opt_g;
54 $interval = $opt_i if $opt_i;
55 $counter = $opt_n if $opt_n;
56 $width = $opt_w if $opt_w;
64 print "ERROR: extra argument $_\n";
69 print "ERROR: Need to specify stats_file\n";
74 my $procpath = "/sys/kernel/debug/lustre";
75 foreach my $param ( "$obddev", "$obddev*/$obdstats", "$obddev*/*/$obdstats",
76 "*/$obddev*/$obdstats", "*/*/$obddev*/$obdstats" ) {
78 print "trying $procpath/$param\n";
80 my $st = glob("$procpath/$param");
82 print "glob $procpath/$param = $st\n";
86 $statsname = `lctl list_param $param | head -n 1`;
88 print "using '$statsname' from $statspath\n"
93 if ($statspath =~ /^None$/) {
94 # some older stats are kept in /proc, but don't look there first
95 $procpath = "/proc/fs/lustre";
97 foreach my $param ( "$obddev", "$obddev*/$obdstats", "$obddev*/*/$obdstats",
98 "*/$obddev*/$obdstats", "*/*/$obddev*/$obdstats" ) {
100 print "trying $procpath/$param\n";
102 $st = glob("$procpath/$param");
104 print "glob $procpath/$param = $st\n";
108 $statsname = `lctl list_param $param | head -n 1`;
110 print "using $statspath\n"
115 if ($statspath =~ /^None$/) {
116 die "Cannot locate stat file for: $obddev\n";
123 if (!$printed_once && $interval) {
124 printf "Timestamp [Name Count Rate Total Unit]...";
125 printf "\n--------------------------------------------------------------------";
128 if ($cc && !$starttime) {
131 printf "\n%-5lu", ($cc - $starttime);
133 printf "$statsname @ $cc\n";
135 printf "%-20s %-6s %-9s", "Name", "Rate", "#Events";
137 printf "%-23s %-6s %-6s %-10s", "Name", "Count", "Rate", "#Events";
140 printf "%-7s %8s %6s %8s %10s", "Unit", "last", "min", "avg", "max";
142 if ($anysumsquare && $width >= 100) {
143 printf " %8s", "stddev";
149 # known units are: reqs, bytes, usec, bufs, regs, pages
150 # readstat subroutine reads and processes statistics from stats file.
151 # This subroutine gets called after every interval specified by user.
157 ($name, $cumulcount, $samples, $unit, $min, $max, $sum, $sumsquare) =
159 $prevcount = $cumulhash->{$name};
160 if (defined($prevcount)) {
161 $diff = $cumulcount - $prevcount;
162 if ($name =~ /^snapshot_time/) {
164 &print_headings($cumulcount);
167 $tdiff = 1; # avoid division by zero
170 elsif ($cumulcount!=0) {
176 $myname = $myname . "_rq";
178 printf " %s %lu %lu %lu %s", $myname, $diff,
179 ($diff/$tdiff), $cumulcount, $myunit;
182 printf "%-20.20s %-6lu %-9lu",
183 $name, ($diff/$tdiff), $cumulcount;
185 printf "%-23.23s %-6lu %-6lu %-10lu", $name,
186 $diff, ($diff/$tdiff), $cumulcount;
191 my $sum_diff = $sum - $sumhash->{$name};
193 printf " %s %lu %lu %lu %s", $name,
194 $diff ? ($sum_diff / $diff) : 0,
195 ($sum_diff/$tdiff), $sum, $unit;
197 printf "%-7s %8lu %6lu %8lu %10lu", $unit,
198 $diff ? ($sum_diff / $diff) : 0, $min,
199 ($sum/$cumulcount), $max;
201 if (defined($sumsquare) && $width >= 100) {
202 my $s = $sumsquare - (($sum_orig * $sum_orig) /
205 my $cnt = ($cumulcount >= 2) ?
207 my $stddev = sqrt($s/($cnt - 1));
209 printf " %8lu", $stddev;
220 if ($cumulcount != 0) {
221 # print info when interval is not specified.
222 printf "%-25s $cumulcount\n", $name
227 if (defined($sumsquare)) {
231 $cumulhash->{$name} = $cumulcount;
232 $sumhash->{$name} = $sum;
240 # check if Term::ReadKey is installed for efficient tty size, but OK if missing
241 eval "require Term::ReadKey" or $have_readkey = 0;
243 print "have_readkey=$have_readkey\n";
246 eval "use Term::ReadKey";
249 # Clears stats file before printing information in intervals
251 open(STATS, "> $statspath") || die "Cannot clear $statspath: $!\n";
257 $hostname = `lctl list_nids | head -1 2> /dev/null`;
259 printf "%s: %s at %s on %s\n", $pname, $statsname, `date`, $hostname;
260 open(STATS, $statspath) || die "Cannot open $statspath: $!\n";
262 # find the terminal width
265 ($width, $height, $wpixels, $hpixels) = GetTerminalSize();
267 ($height, $width) = split / /, `stty size 2> /dev/null`;
268 #$width = 120 if ! $width
276 } while ($interval && $counter-- > 0);