#!/usr/bin/perl -w
# Report generation for plot-sgpdd
# ================================
#        The plot-sgpdd script is used to generate csv file and
# instructions files for gnuplot from the output of sgpdd-survey script.
#
#        The 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
# $ 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];
	print "generating plot $file-$rsz-$op.png\n";
	open ( SCRFILE, "> $file-$rsz-$op.scr" ) or die "Can't open scr file for writing";
	if ($op eq "rd") {
		$rwlabel = "Read";
	}
	if ($op eq "wr") {
		$rwlabel = "Write";
	}
	
	if ($opt_rdtitle || $opt_wrtitle) {
		if ($op eq "rd") {
			print SCRFILE "set title \"@GraphTitle\\n$rwlabel, Rsize = $rsz KBytes, $opt_rdtitle\"\n";
		}
		if ($op eq "wr") {
			print SCRFILE "set title \"@GraphTitle\\n$rwlabel, Rsize = $rsz KBytes, $opt_wrtitle\"\n";
		}
	} else {
		print SCRFILE "set title \"@GraphTitle\\n$rwlabel, Rsize = $rsz KBytes\"\n";
	}
	print SCRFILE "set xlabel \"Threads\"\n";
	print SCRFILE "set ylabel \"Speeds(MB/s)\"\n";
	print SCRFILE "set logscale x\n";
	print SCRFILE "set grid\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;
	my @numrgs = split " ", $regions;
	$xrange = 1;
	# generate instructions for gnuplot, with adjusting X-axes ranges
	
	foreach my $j (sort numerically split " ", $threads) {
		if ($op eq "wr") {
			$using = ( $i < $#numrgs ) ? $i : $#numrgs;
			printf SCRFILE "$plot \"$file-$rsz-$op.dat\" using 1:$using axes x%dy1 title \"write-obj$j\" with line\n", $xrange;
		}
		if ($op eq "rd") {
			$using = ( $i < $#numrgs ) ? $i : $#numrgs;
			printf SCRFILE "$plot \"$file-$rsz-$op.dat\" using 1:$using axes x%dy1 title \"read-obj$j\" with line\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");
}

sub check_data_file () {
        my $file=shift;
        my @values;
        my @tmp;

        open ( FILE, "< $file" ) or die "Can't open $file for reading";
        while ( <FILE> ) {
                @tmp = split;
                push @values, [ @tmp ];
        }
        close FILE;

        for ( $j = 0; $j <= $#tmp; $j++) {
                my $sum=0;
                for ($i = 2; $i <= $#values ; $i ++) {
                        $values [$i][$j] =~ "-" or $sum = $sum + $values [$i][$j];
                }
                die "File: $file : $j column contains no data.\n" unless $sum != 0;
        }
}

sub numerically { $a <=> $b; }

#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", "0";
	
	foreach my $j (sort numerically split " ", $regions) {
		printf DATAFILE "%-8s", "$op$j";
	}

	# threads, line [7], strings
	foreach my $i (sort numerically split " ", $threads) {
	        printf DATAFILE "\n%-6s", $i;

		# regions, line [5], column
		foreach my $j (sort numerically split " ", $regions) {
			if (($op eq "rd" && $rdwr) || ($op eq "wr" && $wrrd) || ($readop) || ($writeop)) {
				if ( $out{$i}{$j} ) {
					printf DATAFILE "%-8s", $out{$i}{$j};
				} else {
					printf DATAFILE "%-8s", "-";
				}
			} else {
				if (($j <= 1 && $out{$i}{$j - 1})) {
					printf DATAFILE "%-8s", $out{$i}{$j - 1};
				}elsif ($out{$i}{$j + 1} && $j > 1) {
					printf DATAFILE "%-8s", $out{$i}{$j + 1};
				} else {
					printf DATAFILE "%-8s", "-";
				}
			}
		}
	}
	close DATAFILE;
	&check_data_file ( $datafile );		
}

if ( !$ARGV[0] ) {
	usage();
}
$regions = "";
$threads = "";
$count = 0;
$wrrd = 0;
$rdwr = 0;
$writeop = 0;
$readop = 0;
$rsz = 0;
$opt_rdtitle = "";
$opt_wrtitle = "";
$opt_y = 0;
# 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;
	@line = split( /\s+/ );
	if ($line[27] && $count != 0) {
		print "invalid file format\n";
		exit 1;	
	} 
	if ($count == 0) {
		@GraphTitle = @line;
		$count++;
		next LABEL;
	}
	if ($line[8]) {
		if ($line[8] eq "ENOMEM") {
			next LABEL;
		}
	}
	if (!$rsz && $line[3]) {
		$rsz = $line[3];
	}
	if ($rsz != $line[3]) {
		if($readop) {
			&write_dat_file("rd");
			&write_scr_file("rd");
		}
		if($writeop) {
			&write_dat_file("wr");
			&write_scr_file("wr");
		}
		if ($wrrd || $rdwr) {
			&write_dat_file("rd");
			&write_scr_file("rd");
			&write_dat_file("wr");
			&write_scr_file("wr");
		}
		$rsz = $line[3];		
		$regions = "";
		$threads = "";
	}
	#print "rg$line[5] th$line[7] w$line[9] r$line[$rindex]\n";
	$rindex = 18;
	if ($line[18]) {
		if ($line[10] eq "failed") {
                	$rindex = 12;
		}
		if ($line[8] eq "write" && $line[17] eq "read") {
			$wrrd = 1;
		}
		if ($line[8] eq "read" && $line[17] eq "write") {
			$rdwr = 1;
		}
	} else {
		if ($line[8] eq "write" && $line[9]) {
			$writeop = 1;
		}
		if ($line[8] eq "read" && $line[9]) {
			$readop = 1;
		}
		
	}
	if ($wrrd || $rdwr) {
		$out{$line[7]}{$line[5]} = $line[9];
		if ($line[$rindex+1]) {
			if (!($line[$rindex+1] eq "failed")) {	
				goto LABEL2;	
			}
		} else {
LABEL2:			if ($line[5] <= 1 ) {
				$out{$line[7]}{$line[5] - 1} = $line[$rindex];
			} else {
				$out{$line[7]}{$line[5] + 1} = $line[$rindex];
			}
		}
	}
	if ($writeop) {
		$out{$line[7]}{$line[5]} = $line[9];	
	}
	if ($readop) {
		$out{$line[7]}{$line[5]} = $line[9];
	}
	$regions .= " $line[5]" unless $regions =~ $line[5];
	$threads .= " $line[7]" unless $threads =~ $line[7];
	$count++;
}
close PFILE;
if ($count > 1 && $rsz) {
	if($readop) {
		&write_dat_file("rd");
		&write_scr_file("rd");
	}
	if($writeop) {
		&write_dat_file("wr");
		&write_scr_file("wr");
	}
	if ($wrrd || $rdwr) {
		&write_dat_file("rd");
		&write_scr_file("rd");
		&write_dat_file("wr");
		&write_scr_file("wr");
	}
} else {
	print "Invalid log file format\n";
}
