#!/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 <results_filename> [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 <results_filename> [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 = <PFILE>;
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 = <STDIN>;
# 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 = <DATAFILE>;
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";
