1*1a3d31e3SAndroid Build Coastguard Worker#! /usr/bin/env python 2*1a3d31e3SAndroid Build Coastguard Worker# 3*1a3d31e3SAndroid Build Coastguard Worker# btt_plot.py: Generate matplotlib plots for BTT generate data files 4*1a3d31e3SAndroid Build Coastguard Worker# 5*1a3d31e3SAndroid Build Coastguard Worker# (C) Copyright 2009 Hewlett-Packard Development Company, L.P. 6*1a3d31e3SAndroid Build Coastguard Worker# 7*1a3d31e3SAndroid Build Coastguard Worker# This program is free software; you can redistribute it and/or modify 8*1a3d31e3SAndroid Build Coastguard Worker# it under the terms of the GNU General Public License as published by 9*1a3d31e3SAndroid Build Coastguard Worker# the Free Software Foundation; either version 2 of the License, or 10*1a3d31e3SAndroid Build Coastguard Worker# (at your option) any later version. 11*1a3d31e3SAndroid Build Coastguard Worker# 12*1a3d31e3SAndroid Build Coastguard Worker# This program is distributed in the hope that it will be useful, 13*1a3d31e3SAndroid Build Coastguard Worker# but WITHOUT ANY WARRANTY; without even the implied warranty of 14*1a3d31e3SAndroid Build Coastguard Worker# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*1a3d31e3SAndroid Build Coastguard Worker# GNU General Public License for more details. 16*1a3d31e3SAndroid Build Coastguard Worker# 17*1a3d31e3SAndroid Build Coastguard Worker# You should have received a copy of the GNU General Public License 18*1a3d31e3SAndroid Build Coastguard Worker# along with this program; if not, write to the Free Software 19*1a3d31e3SAndroid Build Coastguard Worker# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20*1a3d31e3SAndroid Build Coastguard Worker# 21*1a3d31e3SAndroid Build Coastguard Worker 22*1a3d31e3SAndroid Build Coastguard Worker""" 23*1a3d31e3SAndroid Build Coastguard Workerbtt_plot.py: Generate matplotlib plots for BTT generated data files 24*1a3d31e3SAndroid Build Coastguard Worker 25*1a3d31e3SAndroid Build Coastguard WorkerFiles handled: 26*1a3d31e3SAndroid Build Coastguard Worker AQD - Average Queue Depth Running average of queue depths 27*1a3d31e3SAndroid Build Coastguard Worker 28*1a3d31e3SAndroid Build Coastguard Worker BNOS - Block numbers accessed Markers for each block 29*1a3d31e3SAndroid Build Coastguard Worker 30*1a3d31e3SAndroid Build Coastguard Worker Q2D - Queue to Issue latencies Running averages 31*1a3d31e3SAndroid Build Coastguard Worker D2C - Issue to Complete latencies Running averages 32*1a3d31e3SAndroid Build Coastguard Worker Q2C - Queue to Complete latencies Running averages 33*1a3d31e3SAndroid Build Coastguard Worker 34*1a3d31e3SAndroid Build Coastguard WorkerUsage: 35*1a3d31e3SAndroid Build Coastguard Worker btt_plot_aqd.py equivalent to: btt_plot.py -t aqd <type>=aqd 36*1a3d31e3SAndroid Build Coastguard Worker btt_plot_bnos.py equivalent to: btt_plot.py -t bnos <type>=bnos 37*1a3d31e3SAndroid Build Coastguard Worker btt_plot_q2d.py equivalent to: btt_plot.py -t q2d <type>=q2d 38*1a3d31e3SAndroid Build Coastguard Worker btt_plot_d2c.py equivalent to: btt_plot.py -t d2c <type>=d2c 39*1a3d31e3SAndroid Build Coastguard Worker btt_plot_q2c.py equivalent to: btt_plot.py -t q2c <type>=q2c 40*1a3d31e3SAndroid Build Coastguard Worker 41*1a3d31e3SAndroid Build Coastguard WorkerArguments: 42*1a3d31e3SAndroid Build Coastguard Worker [ -A | --generate-all ] Default: False 43*1a3d31e3SAndroid Build Coastguard Worker [ -L | --no-legend ] Default: Legend table produced 44*1a3d31e3SAndroid Build Coastguard Worker [ -o <file> | --output=<file> ] Default: <type>.png 45*1a3d31e3SAndroid Build Coastguard Worker [ -T <string> | --title=<string> ] Default: Based upon <type> 46*1a3d31e3SAndroid Build Coastguard Worker [ -v | --verbose ] Default: False 47*1a3d31e3SAndroid Build Coastguard Worker <data-files...> 48*1a3d31e3SAndroid Build Coastguard Worker 49*1a3d31e3SAndroid Build Coastguard Worker The -A (--generate-all) argument is different: when this is specified, 50*1a3d31e3SAndroid Build Coastguard Worker an attempt is made to generate default plots for all 5 types (aqd, bnos, 51*1a3d31e3SAndroid Build Coastguard Worker q2d, d2c and q2c). It will find files with the appropriate suffix for 52*1a3d31e3SAndroid Build Coastguard Worker each type ('aqd.dat' for example). If such files are found, a plot for 53*1a3d31e3SAndroid Build Coastguard Worker that type will be made. The output file name will be the default for 54*1a3d31e3SAndroid Build Coastguard Worker each type. The -L (--no-legend) option will be obeyed for all plots, 55*1a3d31e3SAndroid Build Coastguard Worker but the -o (--output) and -T (--title) options will be ignored. 56*1a3d31e3SAndroid Build Coastguard Worker""" 57*1a3d31e3SAndroid Build Coastguard Worker 58*1a3d31e3SAndroid Build Coastguard Worker__author__ = 'Alan D. Brunelle <[email protected]>' 59*1a3d31e3SAndroid Build Coastguard Worker 60*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 61*1a3d31e3SAndroid Build Coastguard Worker 62*1a3d31e3SAndroid Build Coastguard Workerimport matplotlib 63*1a3d31e3SAndroid Build Coastguard Workermatplotlib.use('Agg') 64*1a3d31e3SAndroid Build Coastguard Workerimport getopt, glob, os, sys 65*1a3d31e3SAndroid Build Coastguard Workerimport matplotlib.pyplot as plt 66*1a3d31e3SAndroid Build Coastguard Worker 67*1a3d31e3SAndroid Build Coastguard Workerplot_size = [10.9, 8.4] # inches... 68*1a3d31e3SAndroid Build Coastguard Worker 69*1a3d31e3SAndroid Build Coastguard Workeradd_legend = True 70*1a3d31e3SAndroid Build Coastguard Workergenerate_all = False 71*1a3d31e3SAndroid Build Coastguard Workeroutput_file = None 72*1a3d31e3SAndroid Build Coastguard Workertitle_str = None 73*1a3d31e3SAndroid Build Coastguard Workertype = None 74*1a3d31e3SAndroid Build Coastguard Workerverbose = False 75*1a3d31e3SAndroid Build Coastguard Worker 76*1a3d31e3SAndroid Build Coastguard Workertypes = [ 'aqd', 'q2d', 'd2c', 'q2c', 'live', 'bnos' ] 77*1a3d31e3SAndroid Build Coastguard Workerprogs = [ 'btt_plot_%s.py' % t for t in types ] 78*1a3d31e3SAndroid Build Coastguard Worker 79*1a3d31e3SAndroid Build Coastguard Workerget_base = lambda file: file[file.find('_')+1:file.rfind('_')] 80*1a3d31e3SAndroid Build Coastguard Worker 81*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 82*1a3d31e3SAndroid Build Coastguard Workerdef fatal(msg): 83*1a3d31e3SAndroid Build Coastguard Worker """Generate fatal error message and exit""" 84*1a3d31e3SAndroid Build Coastguard Worker 85*1a3d31e3SAndroid Build Coastguard Worker print >>sys.stderr, 'FATAL: %s' % msg 86*1a3d31e3SAndroid Build Coastguard Worker sys.exit(1) 87*1a3d31e3SAndroid Build Coastguard Worker 88*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 89*1a3d31e3SAndroid Build Coastguard Workerdef gen_legends(ax, legends): 90*1a3d31e3SAndroid Build Coastguard Worker leg = ax.legend(legends, 'best', shadow=True) 91*1a3d31e3SAndroid Build Coastguard Worker frame = leg.get_frame() 92*1a3d31e3SAndroid Build Coastguard Worker frame.set_facecolor('0.80') 93*1a3d31e3SAndroid Build Coastguard Worker for t in leg.get_texts(): 94*1a3d31e3SAndroid Build Coastguard Worker t.set_fontsize('xx-small') 95*1a3d31e3SAndroid Build Coastguard Worker 96*1a3d31e3SAndroid Build Coastguard Worker#---------------------------------------------------------------------- 97*1a3d31e3SAndroid Build Coastguard Workerdef get_data(files): 98*1a3d31e3SAndroid Build Coastguard Worker """Retrieve data from files provided. 99*1a3d31e3SAndroid Build Coastguard Worker 100*1a3d31e3SAndroid Build Coastguard Worker Returns a database containing: 101*1a3d31e3SAndroid Build Coastguard Worker 'min_x', 'max_x' - Minimum and maximum X values found 102*1a3d31e3SAndroid Build Coastguard Worker 'min_y', 'max_y' - Minimum and maximum Y values found 103*1a3d31e3SAndroid Build Coastguard Worker 'x', 'y' - X & Y value arrays 104*1a3d31e3SAndroid Build Coastguard Worker 'ax', 'ay' - Running average over X & Y -- 105*1a3d31e3SAndroid Build Coastguard Worker if > 10 values provided... 106*1a3d31e3SAndroid Build Coastguard Worker """ 107*1a3d31e3SAndroid Build Coastguard Worker #-------------------------------------------------------------- 108*1a3d31e3SAndroid Build Coastguard Worker def check(mn, mx, v): 109*1a3d31e3SAndroid Build Coastguard Worker """Returns new min, max, and float value for those passed in""" 110*1a3d31e3SAndroid Build Coastguard Worker 111*1a3d31e3SAndroid Build Coastguard Worker v = float(v) 112*1a3d31e3SAndroid Build Coastguard Worker if mn == None or v < mn: mn = v 113*1a3d31e3SAndroid Build Coastguard Worker if mx == None or v > mx: mx = v 114*1a3d31e3SAndroid Build Coastguard Worker return mn, mx, v 115*1a3d31e3SAndroid Build Coastguard Worker 116*1a3d31e3SAndroid Build Coastguard Worker #-------------------------------------------------------------- 117*1a3d31e3SAndroid Build Coastguard Worker def avg(xs, ys): 118*1a3d31e3SAndroid Build Coastguard Worker """Computes running average for Xs and Ys""" 119*1a3d31e3SAndroid Build Coastguard Worker 120*1a3d31e3SAndroid Build Coastguard Worker #------------------------------------------------------ 121*1a3d31e3SAndroid Build Coastguard Worker def _avg(vals): 122*1a3d31e3SAndroid Build Coastguard Worker """Computes average for array of values passed""" 123*1a3d31e3SAndroid Build Coastguard Worker 124*1a3d31e3SAndroid Build Coastguard Worker total = 0.0 125*1a3d31e3SAndroid Build Coastguard Worker for val in vals: 126*1a3d31e3SAndroid Build Coastguard Worker total += val 127*1a3d31e3SAndroid Build Coastguard Worker return total / len(vals) 128*1a3d31e3SAndroid Build Coastguard Worker 129*1a3d31e3SAndroid Build Coastguard Worker #------------------------------------------------------ 130*1a3d31e3SAndroid Build Coastguard Worker if len(xs) < 1000: 131*1a3d31e3SAndroid Build Coastguard Worker return xs, ys 132*1a3d31e3SAndroid Build Coastguard Worker 133*1a3d31e3SAndroid Build Coastguard Worker axs = [xs[0]] 134*1a3d31e3SAndroid Build Coastguard Worker ays = [ys[0]] 135*1a3d31e3SAndroid Build Coastguard Worker _xs = [xs[0]] 136*1a3d31e3SAndroid Build Coastguard Worker _ys = [ys[0]] 137*1a3d31e3SAndroid Build Coastguard Worker 138*1a3d31e3SAndroid Build Coastguard Worker x_range = (xs[-1] - xs[0]) / 100 139*1a3d31e3SAndroid Build Coastguard Worker for idx in range(1, len(ys)): 140*1a3d31e3SAndroid Build Coastguard Worker if (xs[idx] - _xs[0]) > x_range: 141*1a3d31e3SAndroid Build Coastguard Worker axs.append(_avg(_xs)) 142*1a3d31e3SAndroid Build Coastguard Worker ays.append(_avg(_ys)) 143*1a3d31e3SAndroid Build Coastguard Worker del _xs, _ys 144*1a3d31e3SAndroid Build Coastguard Worker 145*1a3d31e3SAndroid Build Coastguard Worker _xs = [xs[idx]] 146*1a3d31e3SAndroid Build Coastguard Worker _ys = [ys[idx]] 147*1a3d31e3SAndroid Build Coastguard Worker else: 148*1a3d31e3SAndroid Build Coastguard Worker _xs.append(xs[idx]) 149*1a3d31e3SAndroid Build Coastguard Worker _ys.append(ys[idx]) 150*1a3d31e3SAndroid Build Coastguard Worker 151*1a3d31e3SAndroid Build Coastguard Worker if len(_xs) > 1: 152*1a3d31e3SAndroid Build Coastguard Worker axs.append(_avg(_xs)) 153*1a3d31e3SAndroid Build Coastguard Worker ays.append(_avg(_ys)) 154*1a3d31e3SAndroid Build Coastguard Worker 155*1a3d31e3SAndroid Build Coastguard Worker return axs, ays 156*1a3d31e3SAndroid Build Coastguard Worker 157*1a3d31e3SAndroid Build Coastguard Worker #-------------------------------------------------------------- 158*1a3d31e3SAndroid Build Coastguard Worker global verbose 159*1a3d31e3SAndroid Build Coastguard Worker 160*1a3d31e3SAndroid Build Coastguard Worker db = {} 161*1a3d31e3SAndroid Build Coastguard Worker min_x = max_x = min_y = max_y = None 162*1a3d31e3SAndroid Build Coastguard Worker for file in files: 163*1a3d31e3SAndroid Build Coastguard Worker if not os.path.exists(file): 164*1a3d31e3SAndroid Build Coastguard Worker fatal('%s not found' % file) 165*1a3d31e3SAndroid Build Coastguard Worker elif verbose: 166*1a3d31e3SAndroid Build Coastguard Worker print 'Processing %s' % file 167*1a3d31e3SAndroid Build Coastguard Worker 168*1a3d31e3SAndroid Build Coastguard Worker xs = [] 169*1a3d31e3SAndroid Build Coastguard Worker ys = [] 170*1a3d31e3SAndroid Build Coastguard Worker for line in open(file, 'r'): 171*1a3d31e3SAndroid Build Coastguard Worker f = line.rstrip().split(None) 172*1a3d31e3SAndroid Build Coastguard Worker if line.find('#') == 0 or len(f) < 2: 173*1a3d31e3SAndroid Build Coastguard Worker continue 174*1a3d31e3SAndroid Build Coastguard Worker (min_x, max_x, x) = check(min_x, max_x, f[0]) 175*1a3d31e3SAndroid Build Coastguard Worker (min_y, max_y, y) = check(min_y, max_y, f[1]) 176*1a3d31e3SAndroid Build Coastguard Worker xs.append(x) 177*1a3d31e3SAndroid Build Coastguard Worker ys.append(y) 178*1a3d31e3SAndroid Build Coastguard Worker 179*1a3d31e3SAndroid Build Coastguard Worker db[file] = {'x':xs, 'y':ys} 180*1a3d31e3SAndroid Build Coastguard Worker if len(xs) > 10: 181*1a3d31e3SAndroid Build Coastguard Worker db[file]['ax'], db[file]['ay'] = avg(xs, ys) 182*1a3d31e3SAndroid Build Coastguard Worker else: 183*1a3d31e3SAndroid Build Coastguard Worker db[file]['ax'] = db[file]['ay'] = None 184*1a3d31e3SAndroid Build Coastguard Worker 185*1a3d31e3SAndroid Build Coastguard Worker db['min_x'] = min_x 186*1a3d31e3SAndroid Build Coastguard Worker db['max_x'] = max_x 187*1a3d31e3SAndroid Build Coastguard Worker db['min_y'] = min_y 188*1a3d31e3SAndroid Build Coastguard Worker db['max_y'] = max_y 189*1a3d31e3SAndroid Build Coastguard Worker return db 190*1a3d31e3SAndroid Build Coastguard Worker 191*1a3d31e3SAndroid Build Coastguard Worker#---------------------------------------------------------------------- 192*1a3d31e3SAndroid Build Coastguard Workerdef parse_args(args): 193*1a3d31e3SAndroid Build Coastguard Worker """Parse command line arguments. 194*1a3d31e3SAndroid Build Coastguard Worker 195*1a3d31e3SAndroid Build Coastguard Worker Returns list of (data) files that need to be processed -- /unless/ 196*1a3d31e3SAndroid Build Coastguard Worker the -A (--generate-all) option is passed, in which case superfluous 197*1a3d31e3SAndroid Build Coastguard Worker data files are ignored... 198*1a3d31e3SAndroid Build Coastguard Worker """ 199*1a3d31e3SAndroid Build Coastguard Worker 200*1a3d31e3SAndroid Build Coastguard Worker global add_legend, output_file, title_str, type, verbose 201*1a3d31e3SAndroid Build Coastguard Worker global generate_all 202*1a3d31e3SAndroid Build Coastguard Worker 203*1a3d31e3SAndroid Build Coastguard Worker prog = args[0][args[0].rfind('/')+1:] 204*1a3d31e3SAndroid Build Coastguard Worker if prog == 'btt_plot.py': 205*1a3d31e3SAndroid Build Coastguard Worker pass 206*1a3d31e3SAndroid Build Coastguard Worker elif not prog in progs: 207*1a3d31e3SAndroid Build Coastguard Worker fatal('%s not a valid command name' % prog) 208*1a3d31e3SAndroid Build Coastguard Worker else: 209*1a3d31e3SAndroid Build Coastguard Worker type = prog[prog.rfind('_')+1:prog.rfind('.py')] 210*1a3d31e3SAndroid Build Coastguard Worker 211*1a3d31e3SAndroid Build Coastguard Worker s_opts = 'ALo:t:T:v' 212*1a3d31e3SAndroid Build Coastguard Worker l_opts = [ 'generate-all', 'type', 'no-legend', 'output', 'title', 213*1a3d31e3SAndroid Build Coastguard Worker 'verbose' ] 214*1a3d31e3SAndroid Build Coastguard Worker 215*1a3d31e3SAndroid Build Coastguard Worker try: 216*1a3d31e3SAndroid Build Coastguard Worker (opts, args) = getopt.getopt(args[1:], s_opts, l_opts) 217*1a3d31e3SAndroid Build Coastguard Worker except getopt.error, msg: 218*1a3d31e3SAndroid Build Coastguard Worker print >>sys.stderr, msg 219*1a3d31e3SAndroid Build Coastguard Worker fatal(__doc__) 220*1a3d31e3SAndroid Build Coastguard Worker 221*1a3d31e3SAndroid Build Coastguard Worker for (o, a) in opts: 222*1a3d31e3SAndroid Build Coastguard Worker if o in ('-A', '--generate-all'): 223*1a3d31e3SAndroid Build Coastguard Worker generate_all = True 224*1a3d31e3SAndroid Build Coastguard Worker elif o in ('-L', '--no-legend'): 225*1a3d31e3SAndroid Build Coastguard Worker add_legend = False 226*1a3d31e3SAndroid Build Coastguard Worker elif o in ('-o', '--output'): 227*1a3d31e3SAndroid Build Coastguard Worker output_file = a 228*1a3d31e3SAndroid Build Coastguard Worker elif o in ('-t', '--type'): 229*1a3d31e3SAndroid Build Coastguard Worker if not a in types: 230*1a3d31e3SAndroid Build Coastguard Worker fatal('Type %s not supported' % a) 231*1a3d31e3SAndroid Build Coastguard Worker type = a 232*1a3d31e3SAndroid Build Coastguard Worker elif o in ('-T', '--title'): 233*1a3d31e3SAndroid Build Coastguard Worker title_str = a 234*1a3d31e3SAndroid Build Coastguard Worker elif o in ('-v', '--verbose'): 235*1a3d31e3SAndroid Build Coastguard Worker verbose = True 236*1a3d31e3SAndroid Build Coastguard Worker 237*1a3d31e3SAndroid Build Coastguard Worker if type == None and not generate_all: 238*1a3d31e3SAndroid Build Coastguard Worker fatal('Need type of data files to process - (-t <type>)') 239*1a3d31e3SAndroid Build Coastguard Worker 240*1a3d31e3SAndroid Build Coastguard Worker return args 241*1a3d31e3SAndroid Build Coastguard Worker 242*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 243*1a3d31e3SAndroid Build Coastguard Workerdef gen_title(fig, type, title_str): 244*1a3d31e3SAndroid Build Coastguard Worker """Sets the title for the figure based upon the type /or/ user title""" 245*1a3d31e3SAndroid Build Coastguard Worker 246*1a3d31e3SAndroid Build Coastguard Worker if title_str != None: 247*1a3d31e3SAndroid Build Coastguard Worker pass 248*1a3d31e3SAndroid Build Coastguard Worker elif type == 'aqd': 249*1a3d31e3SAndroid Build Coastguard Worker title_str = 'Average Queue Depth' 250*1a3d31e3SAndroid Build Coastguard Worker elif type == 'bnos': 251*1a3d31e3SAndroid Build Coastguard Worker title_str = 'Block Numbers Accessed' 252*1a3d31e3SAndroid Build Coastguard Worker elif type == 'q2d': 253*1a3d31e3SAndroid Build Coastguard Worker title_str = 'Queue (Q) To Issue (D) Average Latencies' 254*1a3d31e3SAndroid Build Coastguard Worker elif type == 'd2c': 255*1a3d31e3SAndroid Build Coastguard Worker title_str = 'Issue (D) To Complete (C) Average Latencies' 256*1a3d31e3SAndroid Build Coastguard Worker elif type == 'q2c': 257*1a3d31e3SAndroid Build Coastguard Worker title_str = 'Queue (Q) To Complete (C) Average Latencies' 258*1a3d31e3SAndroid Build Coastguard Worker 259*1a3d31e3SAndroid Build Coastguard Worker title = fig.text(.5, .95, title_str, horizontalalignment='center') 260*1a3d31e3SAndroid Build Coastguard Worker title.set_fontsize('large') 261*1a3d31e3SAndroid Build Coastguard Worker 262*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 263*1a3d31e3SAndroid Build Coastguard Workerdef gen_labels(db, ax, type): 264*1a3d31e3SAndroid Build Coastguard Worker """Generate X & Y 'axis'""" 265*1a3d31e3SAndroid Build Coastguard Worker 266*1a3d31e3SAndroid Build Coastguard Worker #---------------------------------------------------------------------- 267*1a3d31e3SAndroid Build Coastguard Worker def gen_ylabel(ax, type): 268*1a3d31e3SAndroid Build Coastguard Worker """Set the Y axis label based upon the type""" 269*1a3d31e3SAndroid Build Coastguard Worker 270*1a3d31e3SAndroid Build Coastguard Worker if type == 'aqd': 271*1a3d31e3SAndroid Build Coastguard Worker str = 'Number of Requests Queued' 272*1a3d31e3SAndroid Build Coastguard Worker elif type == 'bnos': 273*1a3d31e3SAndroid Build Coastguard Worker str = 'Block Number' 274*1a3d31e3SAndroid Build Coastguard Worker else: 275*1a3d31e3SAndroid Build Coastguard Worker str = 'Seconds' 276*1a3d31e3SAndroid Build Coastguard Worker ax.set_ylabel(str) 277*1a3d31e3SAndroid Build Coastguard Worker 278*1a3d31e3SAndroid Build Coastguard Worker #---------------------------------------------------------------------- 279*1a3d31e3SAndroid Build Coastguard Worker xdelta = 0.1 * (db['max_x'] - db['min_x']) 280*1a3d31e3SAndroid Build Coastguard Worker ydelta = 0.1 * (db['max_y'] - db['min_y']) 281*1a3d31e3SAndroid Build Coastguard Worker 282*1a3d31e3SAndroid Build Coastguard Worker ax.set_xlim(db['min_x'] - xdelta, db['max_x'] + xdelta) 283*1a3d31e3SAndroid Build Coastguard Worker ax.set_ylim(db['min_y'] - ydelta, db['max_y'] + ydelta) 284*1a3d31e3SAndroid Build Coastguard Worker ax.set_xlabel('Runtime (seconds)') 285*1a3d31e3SAndroid Build Coastguard Worker ax.grid(True) 286*1a3d31e3SAndroid Build Coastguard Worker gen_ylabel(ax, type) 287*1a3d31e3SAndroid Build Coastguard Worker 288*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 289*1a3d31e3SAndroid Build Coastguard Workerdef generate_output(type, db): 290*1a3d31e3SAndroid Build Coastguard Worker """Generate the output plot based upon the type and database""" 291*1a3d31e3SAndroid Build Coastguard Worker 292*1a3d31e3SAndroid Build Coastguard Worker #---------------------------------------------------------------------- 293*1a3d31e3SAndroid Build Coastguard Worker def color(idx, style): 294*1a3d31e3SAndroid Build Coastguard Worker """Returns a color/symbol type based upon the index passed.""" 295*1a3d31e3SAndroid Build Coastguard Worker 296*1a3d31e3SAndroid Build Coastguard Worker colors = [ 'b', 'g', 'r', 'c', 'm', 'y', 'k' ] 297*1a3d31e3SAndroid Build Coastguard Worker l_styles = [ '-', ':', '--', '-.' ] 298*1a3d31e3SAndroid Build Coastguard Worker m_styles = [ 'o', '+', '.', ',', 's', 'v', 'x', '<', '>' ] 299*1a3d31e3SAndroid Build Coastguard Worker 300*1a3d31e3SAndroid Build Coastguard Worker color = colors[idx % len(colors)] 301*1a3d31e3SAndroid Build Coastguard Worker if style == 'line': 302*1a3d31e3SAndroid Build Coastguard Worker style = l_styles[(idx / len(l_styles)) % len(l_styles)] 303*1a3d31e3SAndroid Build Coastguard Worker elif style == 'marker': 304*1a3d31e3SAndroid Build Coastguard Worker style = m_styles[(idx / len(m_styles)) % len(m_styles)] 305*1a3d31e3SAndroid Build Coastguard Worker 306*1a3d31e3SAndroid Build Coastguard Worker return '%s%s' % (color, style) 307*1a3d31e3SAndroid Build Coastguard Worker 308*1a3d31e3SAndroid Build Coastguard Worker #---------------------------------------------------------------------- 309*1a3d31e3SAndroid Build Coastguard Worker global add_legend, output_file, title_str, verbose 310*1a3d31e3SAndroid Build Coastguard Worker 311*1a3d31e3SAndroid Build Coastguard Worker if output_file != None: 312*1a3d31e3SAndroid Build Coastguard Worker ofile = output_file 313*1a3d31e3SAndroid Build Coastguard Worker else: 314*1a3d31e3SAndroid Build Coastguard Worker ofile = '%s.png' % type 315*1a3d31e3SAndroid Build Coastguard Worker 316*1a3d31e3SAndroid Build Coastguard Worker if verbose: 317*1a3d31e3SAndroid Build Coastguard Worker print 'Generating plot into %s' % ofile 318*1a3d31e3SAndroid Build Coastguard Worker 319*1a3d31e3SAndroid Build Coastguard Worker fig = plt.figure(figsize=plot_size) 320*1a3d31e3SAndroid Build Coastguard Worker ax = fig.add_subplot(111) 321*1a3d31e3SAndroid Build Coastguard Worker 322*1a3d31e3SAndroid Build Coastguard Worker gen_title(fig, type, title_str) 323*1a3d31e3SAndroid Build Coastguard Worker gen_labels(db, ax, type) 324*1a3d31e3SAndroid Build Coastguard Worker 325*1a3d31e3SAndroid Build Coastguard Worker idx = 0 326*1a3d31e3SAndroid Build Coastguard Worker if add_legend: 327*1a3d31e3SAndroid Build Coastguard Worker legends = [] 328*1a3d31e3SAndroid Build Coastguard Worker else: 329*1a3d31e3SAndroid Build Coastguard Worker legends = None 330*1a3d31e3SAndroid Build Coastguard Worker 331*1a3d31e3SAndroid Build Coastguard Worker keys = [] 332*1a3d31e3SAndroid Build Coastguard Worker for file in db.iterkeys(): 333*1a3d31e3SAndroid Build Coastguard Worker if not file in ['min_x', 'max_x', 'min_y', 'max_y']: 334*1a3d31e3SAndroid Build Coastguard Worker keys.append(file) 335*1a3d31e3SAndroid Build Coastguard Worker 336*1a3d31e3SAndroid Build Coastguard Worker keys.sort() 337*1a3d31e3SAndroid Build Coastguard Worker for file in keys: 338*1a3d31e3SAndroid Build Coastguard Worker dat = db[file] 339*1a3d31e3SAndroid Build Coastguard Worker if type == 'bnos': 340*1a3d31e3SAndroid Build Coastguard Worker ax.plot(dat['x'], dat['y'], color(idx, 'marker'), 341*1a3d31e3SAndroid Build Coastguard Worker markersize=1) 342*1a3d31e3SAndroid Build Coastguard Worker elif dat['ax'] == None: 343*1a3d31e3SAndroid Build Coastguard Worker continue # Don't add legend 344*1a3d31e3SAndroid Build Coastguard Worker else: 345*1a3d31e3SAndroid Build Coastguard Worker ax.plot(dat['ax'], dat['ay'], color(idx, 'line'), 346*1a3d31e3SAndroid Build Coastguard Worker linewidth=1.0) 347*1a3d31e3SAndroid Build Coastguard Worker if add_legend: 348*1a3d31e3SAndroid Build Coastguard Worker legends.append(get_base(file)) 349*1a3d31e3SAndroid Build Coastguard Worker idx += 1 350*1a3d31e3SAndroid Build Coastguard Worker 351*1a3d31e3SAndroid Build Coastguard Worker if add_legend and len(legends) > 0: 352*1a3d31e3SAndroid Build Coastguard Worker gen_legends(ax, legends) 353*1a3d31e3SAndroid Build Coastguard Worker plt.savefig(ofile) 354*1a3d31e3SAndroid Build Coastguard Worker 355*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 356*1a3d31e3SAndroid Build Coastguard Workerdef get_files(type): 357*1a3d31e3SAndroid Build Coastguard Worker """Returns the list of files for the -A option based upon type""" 358*1a3d31e3SAndroid Build Coastguard Worker 359*1a3d31e3SAndroid Build Coastguard Worker if type == 'bnos': 360*1a3d31e3SAndroid Build Coastguard Worker files = [] 361*1a3d31e3SAndroid Build Coastguard Worker for fn in glob.glob('*c.dat'): 362*1a3d31e3SAndroid Build Coastguard Worker for t in [ 'q2q', 'd2d', 'q2c', 'd2c' ]: 363*1a3d31e3SAndroid Build Coastguard Worker if fn.find(t) >= 0: 364*1a3d31e3SAndroid Build Coastguard Worker break 365*1a3d31e3SAndroid Build Coastguard Worker else: 366*1a3d31e3SAndroid Build Coastguard Worker files.append(fn) 367*1a3d31e3SAndroid Build Coastguard Worker else: 368*1a3d31e3SAndroid Build Coastguard Worker files = glob.glob('*%s.dat' % type) 369*1a3d31e3SAndroid Build Coastguard Worker return files 370*1a3d31e3SAndroid Build Coastguard Worker 371*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 372*1a3d31e3SAndroid Build Coastguard Workerdef do_bnos(files): 373*1a3d31e3SAndroid Build Coastguard Worker for file in files: 374*1a3d31e3SAndroid Build Coastguard Worker base = get_base(file) 375*1a3d31e3SAndroid Build Coastguard Worker title_str = 'Block Numbers Accessed: %s' % base 376*1a3d31e3SAndroid Build Coastguard Worker output_file = 'bnos_%s.png' % base 377*1a3d31e3SAndroid Build Coastguard Worker generate_output(t, get_data([file])) 378*1a3d31e3SAndroid Build Coastguard Worker 379*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 380*1a3d31e3SAndroid Build Coastguard Workerdef do_live(files): 381*1a3d31e3SAndroid Build Coastguard Worker global plot_size 382*1a3d31e3SAndroid Build Coastguard Worker 383*1a3d31e3SAndroid Build Coastguard Worker #---------------------------------------------------------------------- 384*1a3d31e3SAndroid Build Coastguard Worker def get_live_data(fn): 385*1a3d31e3SAndroid Build Coastguard Worker xs = [] 386*1a3d31e3SAndroid Build Coastguard Worker ys = [] 387*1a3d31e3SAndroid Build Coastguard Worker for line in open(fn, 'r'): 388*1a3d31e3SAndroid Build Coastguard Worker f = line.rstrip().split() 389*1a3d31e3SAndroid Build Coastguard Worker if f[0] != '#' and len(f) == 2: 390*1a3d31e3SAndroid Build Coastguard Worker xs.append(float(f[0])) 391*1a3d31e3SAndroid Build Coastguard Worker ys.append(float(f[1])) 392*1a3d31e3SAndroid Build Coastguard Worker return xs, ys 393*1a3d31e3SAndroid Build Coastguard Worker 394*1a3d31e3SAndroid Build Coastguard Worker #---------------------------------------------------------------------- 395*1a3d31e3SAndroid Build Coastguard Worker def live_sort(a, b): 396*1a3d31e3SAndroid Build Coastguard Worker if a[0] == 'sys' and b[0] == 'sys': 397*1a3d31e3SAndroid Build Coastguard Worker return 0 398*1a3d31e3SAndroid Build Coastguard Worker elif a[0] == 'sys' or a[2][0] < b[2][0]: 399*1a3d31e3SAndroid Build Coastguard Worker return -1 400*1a3d31e3SAndroid Build Coastguard Worker elif b[0] == 'sys' or a[2][0] > b[2][0]: 401*1a3d31e3SAndroid Build Coastguard Worker return 1 402*1a3d31e3SAndroid Build Coastguard Worker else: 403*1a3d31e3SAndroid Build Coastguard Worker return 0 404*1a3d31e3SAndroid Build Coastguard Worker 405*1a3d31e3SAndroid Build Coastguard Worker #---------------------------------------------------------------------- 406*1a3d31e3SAndroid Build Coastguard Worker def turn_off_ticks(ax): 407*1a3d31e3SAndroid Build Coastguard Worker for tick in ax.xaxis.get_major_ticks(): 408*1a3d31e3SAndroid Build Coastguard Worker tick.tick1On = tick.tick2On = False 409*1a3d31e3SAndroid Build Coastguard Worker for tick in ax.yaxis.get_major_ticks(): 410*1a3d31e3SAndroid Build Coastguard Worker tick.tick1On = tick.tick2On = False 411*1a3d31e3SAndroid Build Coastguard Worker for tick in ax.xaxis.get_minor_ticks(): 412*1a3d31e3SAndroid Build Coastguard Worker tick.tick1On = tick.tick2On = False 413*1a3d31e3SAndroid Build Coastguard Worker for tick in ax.yaxis.get_minor_ticks(): 414*1a3d31e3SAndroid Build Coastguard Worker tick.tick1On = tick.tick2On = False 415*1a3d31e3SAndroid Build Coastguard Worker 416*1a3d31e3SAndroid Build Coastguard Worker #---------------------------------------------------------------------- 417*1a3d31e3SAndroid Build Coastguard Worker fig = plt.figure(figsize=plot_size) 418*1a3d31e3SAndroid Build Coastguard Worker ax = fig.add_subplot(111) 419*1a3d31e3SAndroid Build Coastguard Worker 420*1a3d31e3SAndroid Build Coastguard Worker db = [] 421*1a3d31e3SAndroid Build Coastguard Worker for fn in files: 422*1a3d31e3SAndroid Build Coastguard Worker if not os.path.exists(fn): 423*1a3d31e3SAndroid Build Coastguard Worker continue 424*1a3d31e3SAndroid Build Coastguard Worker (xs, ys) = get_live_data(fn) 425*1a3d31e3SAndroid Build Coastguard Worker db.append([fn[:fn.find('_live.dat')], xs, ys]) 426*1a3d31e3SAndroid Build Coastguard Worker db.sort(live_sort) 427*1a3d31e3SAndroid Build Coastguard Worker 428*1a3d31e3SAndroid Build Coastguard Worker for rec in db: 429*1a3d31e3SAndroid Build Coastguard Worker ax.plot(rec[1], rec[2]) 430*1a3d31e3SAndroid Build Coastguard Worker 431*1a3d31e3SAndroid Build Coastguard Worker gen_title(fig, 'live', 'Active I/O Per Device') 432*1a3d31e3SAndroid Build Coastguard Worker ax.set_xlabel('Runtime (seconds)') 433*1a3d31e3SAndroid Build Coastguard Worker ax.set_ylabel('Device') 434*1a3d31e3SAndroid Build Coastguard Worker ax.grid(False) 435*1a3d31e3SAndroid Build Coastguard Worker 436*1a3d31e3SAndroid Build Coastguard Worker ax.set_xlim(-0.1, db[0][1][-1]+1) 437*1a3d31e3SAndroid Build Coastguard Worker ax.set_yticks([idx for idx in range(0, len(db))]) 438*1a3d31e3SAndroid Build Coastguard Worker ax.yaxis.set_ticklabels([rec[0] for rec in db]) 439*1a3d31e3SAndroid Build Coastguard Worker turn_off_ticks(ax) 440*1a3d31e3SAndroid Build Coastguard Worker 441*1a3d31e3SAndroid Build Coastguard Worker plt.savefig('live.png') 442*1a3d31e3SAndroid Build Coastguard Worker plt.savefig('live.eps') 443*1a3d31e3SAndroid Build Coastguard Worker 444*1a3d31e3SAndroid Build Coastguard Worker#------------------------------------------------------------------------------ 445*1a3d31e3SAndroid Build Coastguard Workerif __name__ == '__main__': 446*1a3d31e3SAndroid Build Coastguard Worker files = parse_args(sys.argv) 447*1a3d31e3SAndroid Build Coastguard Worker 448*1a3d31e3SAndroid Build Coastguard Worker if generate_all: 449*1a3d31e3SAndroid Build Coastguard Worker output_file = title_str = type = None 450*1a3d31e3SAndroid Build Coastguard Worker for t in types: 451*1a3d31e3SAndroid Build Coastguard Worker files = get_files(t) 452*1a3d31e3SAndroid Build Coastguard Worker if len(files) == 0: 453*1a3d31e3SAndroid Build Coastguard Worker continue 454*1a3d31e3SAndroid Build Coastguard Worker elif t == 'bnos': 455*1a3d31e3SAndroid Build Coastguard Worker do_bnos(files) 456*1a3d31e3SAndroid Build Coastguard Worker elif t == 'live': 457*1a3d31e3SAndroid Build Coastguard Worker do_live(files) 458*1a3d31e3SAndroid Build Coastguard Worker else: 459*1a3d31e3SAndroid Build Coastguard Worker generate_output(t, get_data(files)) 460*1a3d31e3SAndroid Build Coastguard Worker continue 461*1a3d31e3SAndroid Build Coastguard Worker 462*1a3d31e3SAndroid Build Coastguard Worker elif len(files) < 1: 463*1a3d31e3SAndroid Build Coastguard Worker fatal('Need data files to process') 464*1a3d31e3SAndroid Build Coastguard Worker else: 465*1a3d31e3SAndroid Build Coastguard Worker generate_output(type, get_data(files)) 466*1a3d31e3SAndroid Build Coastguard Worker sys.exit(0) 467