xref: /aosp_15_r20/external/blktrace/btt/btt_plot.py (revision 1a3d31e37cc95e9919fd86900a2b6a555f55952c)
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