#!/usr/bin/perl -w # GPL HEADER START # # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 only, # as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License version 2 for more details (a copy is included # in the LICENSE file that accompanied this code). # # You should have received a copy of the GNU General Public License # version 2 along with this program; If not, see # http://www.gnu.org/licenses/gpl-2.0.html # # GPL HEADER END # # Copyright 2008 Sun Microsystems, Inc. All rights reserved # Use is subject to license terms. # # Copyright (c) 2013, 2014, Intel Corporation. # # This file is part of Lustre, http://www.lustre.org/ # Lustre is a trademark of Sun Microsystems, Inc. # # Author: Jitendra Pawar # Report generation for iokit-plot-obdfilter # ==================================== # The iokit-plot-obdfilter script is used to generate csv file and # instructions files for gnuplot from the output of obdfilter-survey script. # # The iokit-plot-obdfilter 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: # $ obdfilter-survey > log_filename # $ iokit-plot-obdfilter # [Note: 1. Please use the .summary file generated by obdfilter-survey as log_file. # It is generally available at /tmp/obdfilter_survey_.summary # 2. This script may need modifications whenever there will be # modifications in output format of obdfilter-survey script. # 3. Gnuplot version 4.0 or above is required.] my @GraphTitle; sub usage() { print "Usage: $0 [--st=] [--y0=]\n"; print " The $0 parses and plots graphs for output of obdfilter-survey using gnuplot.\n"; print " It generates -.dat and\n"; print " --.scr files.\n"; print " Those will be used for graphing the results\n"; print "OPTIONS:\n"; print " --st: SubTitle for the graph\n"; print " --y0: Start point of Y-axis, Default value automatically taken based on Y-axis values ranges\n"; print " log_file: use the .summary file generated by obdfilter-survey as log_file.\n"; print " It is generally available at /tmp/obdfilter_survey_.summary\n"; print "e.g. # $0 obdfilter-log --st=\"Sub-Title\" --y0=50\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"; #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 ($subtitle) { print SCRFILE "set title \"@GraphTitle\\n$rwlabel, Rsize = $rsz KBytes, $subtitle\"\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_y0 != -9999) { print SCRFILE "set yrange [ $opt_y0: ]\n"; } my $plot = "plot"; $i = 2; $xrange = 1; # generate instructions for gnuplot, with adjusting X-axes ranges for ($j = $first_obj; $j <= $obj ; $j = $j + $j) { printf SCRFILE "$plot \"$file-$rsz-$op.dat\" using 1:$i axes x%dy1 title \"$rwlabel-obj$j\" with line\n", $xrange; $i++; $plot = "replot"; } print SCRFILE "set output \"$file-$rsz-$op.png\"\n"; print SCRFILE "replot\n"; close SCRFILE; $graphgen = 1; # 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. open ( DATAFILE, "> $file-$rsz-$op.dat" ) or die "Can't open csv file for writing"; printf DATAFILE "%-6s", "thrd"; for ($j = $first_obj; $j <= $obj; $j = $j + $j) { printf DATAFILE "%-10s", "$op-obj$j"; } for ( $i = $first_thread; $i <= $thread; $i = $i + $i ) { printf DATAFILE "\n%-6s", $i; for ($j = $first_obj; $j <= $obj; $j = $j + $j) { # switch-case can be used instead if else 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", "-"; } } elsif ($op eq "rwr" ) { if ( $arwr{$i}{$j} ) { printf DATAFILE "%-10s", $arwr{$i}{$j}; } else { printf DATAFILE "%-10s", "-"; } } elsif ($op eq "rrd" ) { if ( $arrd{$i}{$j} ) { printf DATAFILE "%-10s", $arrd{$i}{$j}; } else { printf DATAFILE "%-10s", "-"; } } elsif ($op eq "rwa" ) { if ( $arwa{$i}{$j} ) { printf DATAFILE "%-10s", $arwa{$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) { # switch-case can be used instead if else 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"); } elsif ($operations[$cnt] eq "reread") { &write_dat_file("rrd"); &write_scr_file("rrd", "reread"); } elsif ($operations[$cnt] eq "rewrite") { &write_dat_file("rwr"); &write_scr_file("rwr", "rewrite"); } elsif ($operations[$cnt] eq "rewrite_again") { &write_dat_file("rwa"); &write_scr_file("rwa", "rewrite_again"); } } } if ( !$ARGV[0] ) { usage(); } $file = $ARGV[0]; $obj = 0; $thread = 0; $first_obj = 1; $first_thread = 1; $count = 0; $rsz = 0; $subtitle = ""; $opt_y0 = -9999; $cnt = 0; @operations = (); $graphgen = 0; # Command line parameter parsing use Getopt::Long; GetOptions ('help' => \$opt_help, 'st=s' => \$subtitle, 'y0=i' => \$opt_y0) or usage(); if ($opt_help) { usage(); } open ( PFILE, "$file") or die "Can't open results"; LABEL: while ( ) { chomp; @line = split( /\s+/ ); if ($count == 0) { @GraphTitle = @line; $count++; next LABEL; } $linelen = @line; if ($linelen > 26 || $linelen < 11) { print "invalid file format at line $count\n"; exit 1; } if (!$rsz && $line[5]) { $cnt = 0; $rsz = $line[5]; $first_obj = $line[7]; $first_thread = $line[9]; for ($i = 10; $i <= $linelen; $i = $i + 5) { if ($line[$i]) { $operations[$cnt] = $line[$i]; $cnt++; } } } if ($rsz ne $line[5]) { &write_files(); $rsz = $line[5]; $first_obj = $line[7]; $first_thread = $line[9]; @operations = (); $cnt = 0; for ($i = 10; $i <= $linelen; $i = $i + 5) { if ($line[$i]) { $operations[$cnt] = $line[$i]; $cnt++; } } $obj = 0; $thread = 0; } for ($i = 0; $i < @operations; $i++) { # switch-case can be used instead if else 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]; } elsif ($operations[$i] eq "reread") { $arrd{$line[9]}{$line[7]} = $line[$i * 5 + 11]; } elsif ($operations[$i] eq "rewrite") { $arwr{$line[9]}{$line[7]} = $line[$i * 5 + 11]; } elsif ($operations[$i] eq "rewrite_again") { $arwa{$line[9]}{$line[7]} = $line[$i * 5 + 11]; } } if ( $obj < $line[9] ) { $obj = $line[9]; } if ( $thread < $line[7] ) { $thread = $line[7]; } $count++; } close PFILE; if ($count > 1 && $rsz) { &write_files(); } if (!$graphgen) { print "Invalid log file format\n"; }