#!/usr/bin/perl -w
# Report generation for iokit-plot-sgpdd
# ======================================
# The iokit-plot-sgpdd script is used to generate csv file and
# instructions files for gnuplot from the output of sgpdd-survey script.
#
# iokit-plot-sgpdd 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.
#
# Syntax:
# $ sgpdd-survey > log_filename
# $ iokit-plot-sgpdd <log_filename>
# [Note: 1. This script may need modifications whenever there will be
#           modifications in output format of sgpdd-survey script.
#        2. Gnuplot version 4.0 or above is required.]

sub usage()
{
	print STDERR "Usage: $0 [options] <log_filename>\n";
	print STDERR "  $0 parses and plots graphs from the output of sgpdd-survey\n";
	print STDERR "  It generates text data files (.dat) and graphs (.png) using gnuplot.\n";
	print STDERR "options:\n";
	print STDERR "	--rt: Subtitle for read graphs\n";
	print STDERR "	--wt: Subtitle for write graphs\n";
	print STDERR "	--y: Y-axis scale\n";
	print STDERR "e.g. # $0 --rt=\"no prefetch\" --wt=\"WB disabled\" --y=500 sgpdd.summary\n";
	exit 1;
}

# check whether gnuplot exists?
system ("which gnuplot > /dev/null") == 0 or die "gnuplot does not exist, please install it and try again.\n";

# check whether gnuplot supports png
$pngsupport = "ldd `which gnuplot` | grep -q libpng";
system ("$pngsupport") == 0 or die "gnuplot installed does not support PNG.
	Please install gnuplot to support PNG and try again.\n";

my @GraphTitle;

#Subroutine to write .scr file that further used by gnuplot to plot the graph.
sub write_scr_file() {
	my $op = $_[0];
	my $rwlabel = $_[1];
	print "generating plot $file-$rsz-$op.png\n";
	open ( SCRFILE, "> $file-$rsz-$op.scr" ) or die "Can't open scr file for writing";

	if ($opt_rdtitle || $opt_wrtitle) {
		if ($op eq "rd") {
			print SCRFILE "set title \"@GraphTitle\\n$rwlabel, " .
				      "Rsize = $rsz, $lun LUNs, $opt_rdtitle\"\n";
		}
		if ($op eq "wr") {
			print SCRFILE "set title \"@GraphTitle\\n$rwlabel, " .
				      "Rsize = $rsz, $lun LUNs, $opt_wrtitle\"\n";
		}
	} else {
		print SCRFILE "set title \"@GraphTitle\\n$rwlabel, " .
			      "Rsize = $rsz, $lun LUNs\"\n";
	}
	print SCRFILE "set xlabel \"Threads/LUN\"\n";
	print SCRFILE "set ylabel \"Throughput (MiB/s)\"\n";
	print SCRFILE "set logscale x\n";
	print SCRFILE "set grid\n";
	print SCRFILE "set key right bottom\n";
	print SCRFILE "set terminal png\n";
	print SCRFILE "set output \"/dev/null\"\n";
	if ($opt_y != 0) {
		print SCRFILE "set yrange [ 0:$opt_y ]\n";
	} else {
		print SCRFILE "set yrange [ 0: ]\n";
	}

	my $plot = "plot";
	$i = 2;
	$xrange = 1;
	# generate instructions for gnuplot, with adjusting X-axes ranges
	for ($j = $first_crg; $j <= $crg ; $j = $j + $j) {
		$tmp=$j/$lun;
		printf SCRFILE "$plot \"$file-$rsz-$op.dat\" " .
			       "using 1:$i:xticlabels(1) axes x%dy1 " .
			       "title \"$tmp crg/LUN\" " .
			       "with linespoints lw 2\n", $xrange;
		$i++;
		$plot = "replot";
	}
	print SCRFILE "set output \"$file-$rsz-$op.png\"\n";
	print SCRFILE "replot\n";
	close SCRFILE;
	# invoke gnuplot to display graph.
	system ("gnuplot $file-$rsz-$op.scr") == 0 or die "ERROR: while ploting graph";
	system ("rm $file-$rsz-$op.scr");
}


#Subroutine to write .dat file that further used by gnuplot to plot the graph.
sub write_dat_file() {
	my $op = $_[0];
	print "writing data $file-$rsz-$op.dat\n";
	# Open .csv/.dat file for writing required columns from log file.
	my $datafile = "$file-$rsz-$op.dat";
	open ( DATAFILE, "> $datafile" ) or die "Can't open csv $datafile for writing";
	printf DATAFILE "%-6s", "thrd";
	for ($j = $first_crg; $j <= $crg ; $j = $j + $j) {
		$tmp = $j/$lun;
		printf DATAFILE "%-10s", "$tmp-crg";
	}
	for ( $i = $first_thread; $i <= $thread; $i = $i + $i ) {
	        printf DATAFILE "\n%-6s", $i/$lun;
		for ($j = $first_crg; $j <= $crg ; $j = $j + $j) {
			if ($op eq "rd") {
				if ( $ard{$i}{$j} ) {
					printf DATAFILE "%-10s", $ard{$i}{$j};
				} else {
					printf DATAFILE "%-10s", "-";
				}
			} elsif ($op eq "wr" ) {
				if ( $awr{$i}{$j} ) {
					printf DATAFILE "%-10s", $awr{$i}{$j};
				} else {
					printf DATAFILE "%-10s", "-";
				}
			}
		}
	}
	close DATAFILE;
}

#Subroutine to call .scr and .dat file write routines.
sub write_files() {
	for ($cnt = 0; $cnt < @operations; $cnt = $cnt + 1) {
		if($operations[$cnt] eq "read") {
			&write_dat_file("rd");
			&write_scr_file("rd", "read");
		} elsif ($operations[$cnt] eq "write") {
			&write_dat_file("wr");
			&write_scr_file("wr", "write");
		}
	}
}

if ( !$ARGV[0] ) {
	usage();
}
$crg = 0;
$thread = 0;
$first_crg = 1;
$first_thread = 1;
$count = 0;
$rsz = 0;
$opt_rdtitle = "";
$opt_wrtitle = "";
$opt_y = 0;
$cnt = 0;
@operations = ();
# Command line parameter parsing
use Getopt::Long;
GetOptions ('help' => \$opt_help, 'rt=s' => \$opt_rdtitle, 'wt=s' => \$opt_wrtitle, 'y=i' => \$opt_y) or usage();
if ($opt_help) {
	usage();
}
$file = $ARGV[0];

open ( PFILE, "$file") or die "Can't open $file";
LABEL: while ( <PFILE> ) {
	chomp;
	# replace error strings to ensure same ordering of line fields
	s/failed/failed . . . . ./g;
	@line = split( /\s+/ );
	if ($count == 0) {
		@GraphTitle = @line[0 .. 6];
		$count++;
		next LABEL;
	}
	# output format
	# dev  1 sz  1048576K rsz 1024K crg     1 thr     8 write  604.55 [  606.43,  606.43]  read  754.02 [  756.95,  756.95]
	$linelen = @line;
	if ($linelen < 11) {
		print "invalid file format at line $count\n";
		exit 1;
	}
	if ($line[10]) {
		if ($line[10] eq "ENOMEM") {
			next LABEL;
		}
	}
	if (!$rsz || $rsz ne $line[5]) {
		&write_files() unless !$rsz;
		$cnt = 0;
		$lun = $line[1];
		$rsz = $line[5];
		$first_crg = $line[7];
		$first_thread = $line[9];
		for ($i = 10; $i <= $linelen; $i = $i + 5) {
			if ($line[$i]) {
				$operations[$cnt] = $line[$i];
				$cnt++;
			}
		}
	}
	for ($i = 0; $i < @operations; $i++) {
		if ($operations[$i] eq "read") {
			$ard{$line[9]}{$line[7]} = $line[$i * 5 + 11];
		} elsif ($operations[$i] eq "write") {
			$awr{$line[9]}{$line[7]} = $line[$i * 5 + 11];
		}
	}
	if ( $crg < $line[7] ) {
		$crg = $line[7];
	}
	if ( $thread < $line[9] ) {
		$thread = $line[9];
	}
	$count++;
}
close PFILE;
if ($count > 1 && $rsz) {
	&write_files()
} else {
	print "Invalid log file format\n";
}
