#!/usr/bin/perl -w # Report generation for llstat # =============================== # The plot-llstat script is used to generate csv file and # instructions files for gnuplot from the output of llstat script. # Since llstat is generic in nature, plot-llstat is also generic # script. # # Assume that: # operations = { open, close, read_bytes, write_bytes, connect, create, .. etc.} # parameters = { Rate, Total} # # plot-llstat script creates dat(csv) file using number of operations # specified by the user. Number of operations equals to number of columns in csv # file. And values in those columns are equals to the corresponding value of # the "$param_inx" parameter from the output file. # The plot-llstat also creates .scr file that contains instructions # for gnuplot to plot the graph. After generating .dat and .scr files this # script invokes gnuplot to display graph. # Featrues: # 1. This script is generic in nature, works with any operations names. # 2. User have option to setect operations of their choice for graph generation. # 3. This script automatically selects different y axes according to the ranges # of values of the parameter. # 4. One can change parameter to be consider for graphing # by changing value of $param_inx. # Syntax: # $ plot-llstat [parameter index (default=2, i.e. Rate)] # [Note: 1. The output filt given to this script must have been generated # with -g option to the llstat script. # 2. This script may need modifications whenever there will be # modifications in output format of llstat script.] # arg 0 is filename sub usages_msg(){ print "$0 parses and graphs the output of llstat using gnuplot,\n"; print "and generates .dat files for use in spreadsheets.\n"; print "Usage: $0 [parameter_index]\n"; print " where parameter_index is one of:\n"; print " 1 - Count per interval\n"; print " 2 - Rate (count per second) (default)\n"; print " 3 - Total count\n"; print "ex: # llstat -i2 -g -c lustre-OST0000 > log\n"; print " # $0 log 3\n"; exit 1; } my $count = 0; # count for number of rows in csv(.dat) file. my $jumpcolumn = -1; # Columns to be skiped to get op. name and the "$param_inx" param. my @columns; # Array for Operations names. my $columnvalues = ""; # Values of the "$param_inx" parameter for all operations. my @line; # To store recently read line from log file my $param_inx = 2; # Index of the parameter are you interested in graphing. # Default is 2 for Rate. my $GraphTitle; if ( !$ARGV[0] ) { usages_msg(); } if ( $ARGV[1] ) { $param_inx = $ARGV[1]; } $file = $ARGV[0]; # Open log file for reading open ( PFILE, "$file") or die "Can't open results log file"; @alllines = ; close PFILE; LABLE:while ( $count <= $#alllines ) { $line = $alllines[$count]; #print "$line\n"; chop($line); @line = split(/\s+/,$line); # splits line into tokens # This comparison may be changed if there will be changes log file. if( $line[0] eq "Timestamp" ) { # decide operations position in the logfile depends on num of # parameters(Rate, Total, etc.) present in this line. $jumpcolumn = $#line; $count = $count + 2; # skip the "---------" line from result file. last LABLE; } if ($line[1] eq "STATS" && $line[2] eq "on") { $GraphTitle = $line; @GraphTitle = split( /:/, $GraphTitle ); } $count++; } if ($jumpcolumn < 0) { print "Invalid logfile format\n"; exit 1; } $lastline = $alllines[-1]; @lastline = split(/\s+/,$lastline); my $allcolumns = ""; $i = 1; while ($i < $#lastline) { # display operations names for user selection. print "$lastline[$i] "; $allcolumns = "$allcolumns$lastline[$i] "; # capture the "$param_inx" parameter in $columnvalues, # used to define axes ranges depends on values. $columnvalues = "$columnvalues$lastline[$i + $param_inx] "; $i = $i + $jumpcolumn; } print "\nSelect columns(press return to select all): "; $columns = ; # consider all operations if user hit return. if ( $columns eq "\n" ) { $columns = $allcolumns; } chop ($columns); @columns = split (/\s+/, $columns); # Open .csv file for writting required columns from log file. open ( DATAFILE, "> $file.dat" ) or die "Can't open csv file for writting"; print DATAFILE "0 "; for ($i = 0; $i < $#lastline; $i++) { for ($j = 0; $j <= $#columns; $j++) { if ($columns[$j] eq $lastline[$i]) { print DATAFILE "$columns[$j]$lastline[$i + 4] "; } } } print DATAFILE "\n"; my $found = 0; # depends on $jumpcolumn, capture operation names and value of # the "$param_inx" parameter for that perticular operation. while ( $count <= $#alllines ) { $line = $alllines[$count]; #print "$line\n"; chop($line); @line = split(/\s+/,$line); # splits line into tokens # fill the csv(.dat) file with values of operations. print DATAFILE "$line[0]"; for ($j = 0; $j <= $#columns; $j++) { for ($i = 1; $i < $#line ; $i++) { if ($columns[$j] eq $line[$i]) { # capture the "$param_inx" parameter print DATAFILE " $line[$i + $param_inx]"; $found = 1; } } if (!$found) { print DATAFILE " 0"; } $found = 0; } print DATAFILE "\n"; $count = $count + 1; } close DATAFILE; # Open .csv file for reading columns titles. open ( DATAFILE, "$file.dat" ) or die "Can't open csv file for reading titles\n"; my $titles = ; close DATAFILE; chop($titles); @titles = split (/\s+/, $titles); # Open .scr file for writting instructions for gnuplot. open ( SCRFILE, "> $file.scr" ) or die "Can't open scr file for writting\n"; print SCRFILE "set title \"$GraphTitle[1]\"\n"; print SCRFILE "set xlabel \"time\"\n"; if ($param_inx == 1) { print SCRFILE "set ylabel \"units/interval\"\n"; } elsif ($param_inx == 3) { print SCRFILE "set ylabel \"units\"\n"; } else { print SCRFILE "set ylabel \"units/sec\"\n"; } my $plot = "plot"; # generate instructions for gnuplot for ($i = 2; $i <= ($#columns + 2); $i++) { print SCRFILE "$plot \"$file.dat\" using 1:$i axes x1y1 title \"$titles[$i - 1]\" with line\n"; $plot = "replot"; } print SCRFILE "pause -1\n"; close SCRFILE; # invoke gnuplot to display graph. system ("gnuplot $file.scr") == 0 or die "ERROR: while ploting graph.\nMake sure that gnuplot is working properly";