Whamcloud - gitweb
LU-11407 obdclass: add start time to stats files
[fs/lustre-release.git] / lustre / utils / llobdstat
1 #!/usr/bin/perl
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.
5
6 my $pname = $0;
7 my $obddev = "";
8 my $obdstats = "stats";
9 my $statspath = "None";
10 my $statsname = $obdstats;
11 my $interval = 0;
12 my $counter = 999999999;
13 my $debug = 0;
14 my $have_readkey = 1;
15 my $width = 120;
16 my $height = 25;
17
18 sub usage()
19 {
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";
29         exit 1;
30 }
31
32 # Command line parameter parsing
33 use Getopt::Std;
34 getopts('dhi:n:') or usage();
35 usage() if $opt_h;
36 $debug = $opt_d if $opt_d;
37 $interval = $opt_i if $opt_i;
38 $counter = $opt_n if $opt_n;
39
40 my $i = 0;
41 foreach (@ARGV) {
42         if ($i == 0) {
43                 $obddev = $_;
44                 $obddev =~ s/\./\//g;
45         } elsif ($i == 1) {
46                 $interval = $_;
47         } elsif ($i == 2) {
48                 $counter = $_;
49         } else {
50                 print "ERROR: extra argument $_\n";
51                 usage();
52         }
53         $i++;
54 }
55 if ( !$obddev ) {
56         print "ERROR: Need to specify stats_file\n";
57         usage();
58 }
59
60 # Process arguments
61 my $procpath = "/proc/fs/lustre";
62 foreach my $param ( "$obddev", "$obddev*/$obdstats", "$obddev*/*/$obdstats",
63                     "*/$obddev*/$obdstats", "*/*/$obddev*/$obdstats" ) {
64         if ($debug) {
65                 printf "trying $procpath/$param\n";
66         }
67         my $st = glob("$procpath/$param");
68         if ( -f "$st" ) {
69                 $statspath = $st;
70                 $statsname = `lctl list_param $param | head -n 1`;
71                 if ($debug) {
72                         print "using $statspath\n"
73                 }
74                 last;
75         }
76 }
77 if ($statspath =~ /^None$/) {
78         # server stats are currently in /proc/fs/lustre, but may move eventually
79         $procpath = "/sys/kernel/debug/lustre";
80
81         foreach my $param ( "$obddev", "$obddev*/$obdstats", "$obddev*/*/$obdstats",
82                             "*/$obddev*/$obdstats", "*/*/$obddev*/$obdstats" ) {
83                 if ($debug) {
84                         print "trying $procpath/$param\n";
85                 }
86                 $st = glob("$procpath/$param");
87                 if ($debug) {
88                         print "glob $procpath/$param = $st\n";
89                 }
90                 if (-f "$st") {
91                         $statspath = $st;
92                         $statsname = `lctl list_param $param | head -n 1`;
93                         if ($debug) {
94                                 print "using $statspath\n"
95                         }
96                         last;
97                 }
98         }
99         if ($statspath =~ /^None$/) {
100                 die "Cannot locate stat file for: $obddev\n";
101         }
102 }
103
104 # check if Term::ReadKey is installed for efficient tty size, but OK if missing
105 eval "require Term::ReadKey" or $have_readkey = 0;
106 if ($debug) {
107         print "have_readkey=$have_readkey\n";
108 }
109 if ($have_readkey) {
110         eval "use Term::ReadKey";
111 }
112
113 print "$pname on $statsname\n";
114
115 my %cur;
116 my %last;
117
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",
123          "snapshot_time");
124
125 my @extinfo = ($create, $destroy, $statfs, $punch);
126 my %shortname = ($create => "cx", $destroy => "dx", $statfs => "st", $punch => "pu");
127
128 # read statistics from the stats file.
129 # This subroutine gets called after every interval specified by user.
130 sub readstat()
131 {
132     my $prevcount;
133     my @iodata;
134
135     seek STATS, 0, 0;
136     while (<STATS>) {
137         chop;
138         @iodata = split(/\s+/, $_);
139         my $name = $iodata[0];
140
141         $prevcount = $cur{$name};
142         if (defined($prevcount)) {
143             $last{$name} = $prevcount;
144         }
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"};
150             }
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"};
156             }
157             $cur{"write_ops"} = $iodata[1];
158             $cur{$name} = $iodata[6];
159         } else {
160             $cur{$name} = $iodata[1];
161         }
162     }
163 }
164
165 # process stats information read from the stats file.
166 # This subroutine gets called after every interval specified by user.
167 sub process_stats()
168 {
169     my $delta;
170     my $data;
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";
177     } else {
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;
185
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";
190             if ($have_readkey) {
191                 ($width, $height, $wpixels, $hpixels) = GetTerminalSize();
192             } else {
193                 ($height, $width) = split / /, `stty size 2> /dev/null`;
194                 #$width = 120 if ! $width
195             }
196         }
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;
200
201         $delta = $cur{$getattr} - $last{$getattr};
202         if ( $delta != 0 ) {
203             $rdelta = int ($delta/$timespan);
204             print " ga:$delta,$rdelta/s";
205         }
206
207         for $data ( @extinfo ) {
208             $delta = $cur{$data} - $last{$data};
209             if ($delta != 0) {
210                 print " $shortname{$data}:$delta";
211             }
212         }
213         print "\n";
214         $| = 1;
215     }
216 }
217
218 #Open the stat file with STATS
219 open(STATS, $statspath) || die "Cannot open $statspath: $!\n";
220 do {
221     # read the statistics from stat file.
222     readstat();
223     process_stats();
224     if ($interval) {
225         sleep($interval);
226         %last = %cur;
227     }
228     # Repeat the statistics printing after every "interval" specified in
229     # command line, up to counter times, if specified
230 } while ($interval && $counter-- > 0);
231 close STATS;