Major improvements in the graph output code. Mostly adding more
options, making existing options more visible and dealing with holes in data better. util/stats/barchart.py: - move the options for BarChart to a base class ChartOptions so they can be more easily set and copied. - add an option to set the chart size (so you can adjust the aspect ratio) - don't do the add_subplot thing, use add_axes directly so we can affect the size of the figure itself to make room for the legend - make the initial array bottom floating point so we don't lose precision - add an option to set the limits on the y axis - use a figure legend instead of an axes legend so we can put the legend outside of the actual chart. Also add an option to set the fontsize of the legend. - initial hack at outputting csv files util/stats/db.py: don't print out an error when the run is missing from the database just return None, the error will be print elsewhere. util/stats/output.py: - make StatOutput derive from ChartOptions so that it's easier to set default chart options. - make the various output functions (graph, display, etc.) take the name of the data as a parameter instead of making it a parameter to __init__. This allows me to create the StatOutput object with generic parameters while still being able to specialize the name after the fact - add support for graph_group and graph_bars to be applied to multiple configuration groups. This results in a cross product of the groups to be generated and used. - flush the html file output as we go so that we can load the file while graphs are still being generated. - make the proxy a parameter to the graph function so the proper system's data can be graphed - for any groups or bars that are completely missing, remove them from the graph. This way, if we decide not to do a set of runs, there won't be holes in the data. - output eps and ps by default in addition to the png. util/stats/profile.py: - clean up the data structures that are used to store the function profile information and try our best to avoid keeping extra data around that isn't used. - make get() return None if a job is missing so we know it was missing rather than the all zeroes thing. - make the function profile categorization stuff total up to 100% - Fixup the x-axis and y-axis labels. - fix the dot file output stuff. util/stats/stats.py: support the new options stuff for StatOutput --HG-- extra : convert_revision : fae35df8c57a36257ea93bc3e0a0e617edc46bb7
This commit is contained in:
parent
7819ca6b97
commit
c0a4836077
6 changed files with 297 additions and 146 deletions
|
@ -28,28 +28,19 @@
|
|||
# Lisa Hsu
|
||||
|
||||
import matplotlib, pylab
|
||||
from matplotlib.font_manager import FontProperties
|
||||
from matplotlib.numerix import array, arange, reshape, shape, transpose, zeros
|
||||
from matplotlib.numerix import Float
|
||||
|
||||
matplotlib.interactive(False)
|
||||
|
||||
class BarChart(object):
|
||||
def __init__(self, **kwargs):
|
||||
self.init(**kwargs)
|
||||
from chart import ChartOptions
|
||||
|
||||
def init(self, **kwargs):
|
||||
self.colormap = 'jet'
|
||||
class BarChart(ChartOptions):
|
||||
def __init__(self, default=None, **kwargs):
|
||||
super(BarChart, self).__init__(default, **kwargs)
|
||||
self.inputdata = None
|
||||
self.chartdata = None
|
||||
self.xlabel = None
|
||||
self.ylabel = None
|
||||
self.legend = None
|
||||
self.xticks = None
|
||||
self.yticks = None
|
||||
self.title = None
|
||||
|
||||
for key,value in kwargs.iteritems():
|
||||
self.__setattr__(key, value)
|
||||
|
||||
def gen_colors(self, count):
|
||||
cmap = matplotlib.cm.get_cmap(self.colormap)
|
||||
|
@ -129,8 +120,8 @@ class BarChart(object):
|
|||
if self.chartdata is None:
|
||||
raise AttributeError, "Data not set for bar chart!"
|
||||
|
||||
self.figure = pylab.figure()
|
||||
self.axes = self.figure.add_subplot(111)
|
||||
self.figure = pylab.figure(figsize=self.chart_size)
|
||||
self.axes = self.figure.add_axes(self.figure_size)
|
||||
|
||||
dim = len(shape(self.inputdata))
|
||||
cshape = shape(self.chartdata)
|
||||
|
@ -158,7 +149,7 @@ class BarChart(object):
|
|||
|
||||
bars = []
|
||||
for i,stackdata in enumerate(self.chartdata):
|
||||
bottom = array([0] * len(stackdata[0]))
|
||||
bottom = array([0.0] * len(stackdata[0]), Float)
|
||||
stack = []
|
||||
for j,bardata in enumerate(stackdata):
|
||||
bardata = array(bardata)
|
||||
|
@ -181,6 +172,8 @@ class BarChart(object):
|
|||
ticks = arange(nticks) / (nticks - 1) * (ymax - ymin) + ymin
|
||||
self.axes.set_yticks(ticks)
|
||||
self.axes.set_yticklabels(self.yticks)
|
||||
elif self.ylim is not None:
|
||||
self.axes.set_ylim(self.ylim)
|
||||
|
||||
if self.xticks is not None:
|
||||
self.axes.set_xticks(arange(cshape[2]) + .5)
|
||||
|
@ -195,7 +188,8 @@ class BarChart(object):
|
|||
number = len(bars[0])
|
||||
lbars = [ bars[0][number - j - 1][0] for j in xrange(number)]
|
||||
|
||||
self.axes.legend(lbars, self.legend, loc='best')
|
||||
self.figure.legend(lbars, self.legend, self.legend_loc,
|
||||
prop=FontProperties(size=self.legend_size))
|
||||
|
||||
if self.title is not None:
|
||||
self.axes.set_title(self.title)
|
||||
|
@ -203,7 +197,32 @@ class BarChart(object):
|
|||
def savefig(self, name):
|
||||
self.figure.savefig(name)
|
||||
|
||||
def savecsv(self, name):
|
||||
f = file(name, 'w')
|
||||
data = array(self.inputdata)
|
||||
dim = len(data.shape)
|
||||
|
||||
if dim == 1:
|
||||
#if self.xlabel:
|
||||
# f.write(', '.join(list(self.xlabel)) + '\n')
|
||||
f.write(', '.join([ '%f' % val for val in data]) + '\n')
|
||||
if dim == 2:
|
||||
#if self.xlabel:
|
||||
# f.write(', '.join([''] + list(self.xlabel)) + '\n')
|
||||
for i,row in enumerate(data):
|
||||
ylabel = []
|
||||
#if self.ylabel:
|
||||
# ylabel = [ self.ylabel[i] ]
|
||||
f.write(', '.join(ylabel + [ '%f' % val for val in row]) + '\n')
|
||||
if dim == 3:
|
||||
f.write("don't do 3D csv files\n")
|
||||
pass
|
||||
|
||||
f.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from random import randrange
|
||||
import random, sys
|
||||
|
||||
dim = 3
|
||||
|
@ -234,13 +253,17 @@ if __name__ == '__main__':
|
|||
chart1.xticks = [ 'xtick%d' % x for x in xrange(myshape[0]) ]
|
||||
chart1.title = 'this is the title'
|
||||
chart1.graph()
|
||||
#chart1.savefig('/tmp/test1.png')
|
||||
chart1.savefig('/tmp/test1.png')
|
||||
chart1.savefig('/tmp/test1.ps')
|
||||
chart1.savefig('/tmp/test1.eps')
|
||||
chart1.savecsv('/tmp/test1.csv')
|
||||
|
||||
if False:
|
||||
chart2 = BarChart()
|
||||
chart2.data = data
|
||||
chart2.colormap = 'gray'
|
||||
chart2.graph()
|
||||
#chart2.savefig('/tmp/test2.png')
|
||||
chart2.savefig('/tmp/test2.png')
|
||||
chart2.savefig('/tmp/test2.ps')
|
||||
|
||||
pylab.show()
|
||||
#pylab.show()
|
||||
|
|
84
util/stats/chart.py
Normal file
84
util/stats/chart.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Copyright (c) 2005 The Regents of The University of Michigan
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met: redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer;
|
||||
# redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution;
|
||||
# neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Authors: Nathan Binkert
|
||||
# Lisa Hsu
|
||||
|
||||
class ChartOptions(object):
|
||||
defaults = { 'chart_size' : (8, 4),
|
||||
'figure_size' : [0.1, 0.1, 0.6, 0.85],
|
||||
'title' : None,
|
||||
'legend' : None,
|
||||
'legend_loc' : 'upper right',
|
||||
'legend_size' : 6,
|
||||
'colormap' : 'jet',
|
||||
'xlabel' : None,
|
||||
'ylabel' : None,
|
||||
'xticks' : None,
|
||||
'yticks' : None,
|
||||
'ylim' : None,
|
||||
}
|
||||
|
||||
def __init__(self, options=None, **kwargs):
|
||||
self.init(options, **kwargs)
|
||||
|
||||
def clear(self):
|
||||
self.options = {}
|
||||
|
||||
def init(self, options=None, **kwargs):
|
||||
self.clear()
|
||||
self.update(options, **kwargs)
|
||||
|
||||
def update(self, options=None, **kwargs):
|
||||
if options is not None:
|
||||
if not isinstance(options, ChartOptions):
|
||||
raise AttributeError, \
|
||||
'attribute options of type %s should be %s' % \
|
||||
(type(options), ChartOptions)
|
||||
self.options.update(options.options)
|
||||
|
||||
for key,value in kwargs.iteritems():
|
||||
if key not in ChartOptions.defaults:
|
||||
raise AttributeError, \
|
||||
"%s instance has no attribute '%s'" % (type(self), key)
|
||||
self.options[key] = value
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr in self.options:
|
||||
return self.options[attr]
|
||||
|
||||
if attr in ChartOptions.defaults:
|
||||
return ChartOptions.defaults[attr]
|
||||
|
||||
raise AttributeError, \
|
||||
"%s instance has no attribute '%s'" % (type(self), attr)
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if attr in ChartOptions.defaults:
|
||||
self.options[attr] = value
|
||||
else:
|
||||
super(ChartOptions, self).__setattr__(attr, value)
|
||||
|
|
@ -155,7 +155,6 @@ class Database(object):
|
|||
def get(self, job, stat):
|
||||
run = self.allRunNames.get(job.name, None)
|
||||
if run is None:
|
||||
print 'run "%s" not found' % job
|
||||
return None
|
||||
|
||||
from info import scalar, vector, value, values, total, len
|
||||
|
|
|
@ -26,21 +26,22 @@
|
|||
#
|
||||
# Authors: Nathan Binkert
|
||||
|
||||
class StatOutput(object):
|
||||
def __init__(self, name, jobfile, info, stat=None, binstats=None):
|
||||
self.name = name
|
||||
from chart import ChartOptions
|
||||
|
||||
class StatOutput(ChartOptions):
|
||||
def __init__(self, jobfile, info, stat=None, binstats=None):
|
||||
super(StatOutput, self).__init__()
|
||||
self.jobfile = jobfile
|
||||
self.stat = stat
|
||||
self.binstats = None
|
||||
self.label = self.name
|
||||
self.invert = False
|
||||
self.info = info
|
||||
|
||||
def printdata(self, bin = None, printmode = 'G'):
|
||||
def printdata(self, name, bin = None, printmode = 'G'):
|
||||
import info
|
||||
|
||||
if bin:
|
||||
print '%s %s stats' % (self.name, bin)
|
||||
print '%s %s stats' % (name, bin)
|
||||
|
||||
if self.binstats:
|
||||
for stat in self.binstats:
|
||||
|
@ -69,70 +70,78 @@ class StatOutput(object):
|
|||
valstring = ', '.join([ valformat % val for val in value ])
|
||||
print '%-50s %s' % (job.name + ':', valstring)
|
||||
|
||||
def display(self, binned = False, printmode = 'G'):
|
||||
def display(self, name, binned = False, printmode = 'G'):
|
||||
if binned and self.binstats:
|
||||
self.printdata('kernel', printmode)
|
||||
self.printdata('idle', printmode)
|
||||
self.printdata('user', printmode)
|
||||
self.printdata('interrupt', printmode)
|
||||
self.printdata(name, 'kernel', printmode)
|
||||
self.printdata(name, 'idle', printmode)
|
||||
self.printdata(name, 'user', printmode)
|
||||
self.printdata(name, 'interrupt', printmode)
|
||||
|
||||
print '%s total stats' % self.name
|
||||
self.printdata(printmode=printmode)
|
||||
print '%s total stats' % name
|
||||
self.printdata(name, printmode=printmode)
|
||||
|
||||
def graph(self, graphdir):
|
||||
def graph(self, name, graphdir, proxy=None):
|
||||
from os.path import expanduser, isdir, join as joinpath
|
||||
from barchart import BarChart
|
||||
from matplotlib.numerix import Float, array, zeros
|
||||
import os, re
|
||||
import os, re, urllib
|
||||
from jobfile import crossproduct
|
||||
|
||||
confgroups = self.jobfile.groups()
|
||||
ngroups = len(confgroups)
|
||||
skiplist = [ False ] * ngroups
|
||||
groupopts = None
|
||||
baropts = None
|
||||
groupopts = []
|
||||
baropts = []
|
||||
groups = []
|
||||
for i,group in enumerate(confgroups):
|
||||
if group.flags.graph_group:
|
||||
if groupopts is not None:
|
||||
raise AttributeError, \
|
||||
'Two groups selected for graph group'
|
||||
groupopts = group.subopts()
|
||||
groupopts.append(group.subopts())
|
||||
skiplist[i] = True
|
||||
elif group.flags.graph_bars:
|
||||
if baropts is not None:
|
||||
raise AttributeError, \
|
||||
'Two groups selected for graph bars'
|
||||
baropts = group.subopts()
|
||||
baropts.append(group.subopts())
|
||||
skiplist[i] = True
|
||||
else:
|
||||
groups.append(group)
|
||||
|
||||
if groupopts is None:
|
||||
if not groupopts:
|
||||
raise AttributeError, 'No group selected for graph group'
|
||||
|
||||
if baropts is None:
|
||||
if not baropts:
|
||||
raise AttributeError, 'No group selected for graph bars'
|
||||
|
||||
groupopts = [ group for group in crossproduct(groupopts) ]
|
||||
baropts = [ bar for bar in crossproduct(baropts) ]
|
||||
|
||||
directory = expanduser(graphdir)
|
||||
if not isdir(directory):
|
||||
os.mkdir(directory)
|
||||
html = file(joinpath(directory, '%s.html' % self.name), 'w')
|
||||
html = file(joinpath(directory, '%s.html' % name), 'w')
|
||||
print >>html, '<html>'
|
||||
print >>html, '<title>Graphs for %s</title>' % self.name
|
||||
print >>html, '<title>Graphs for %s</title>' % name
|
||||
print >>html, '<body>'
|
||||
html.flush()
|
||||
|
||||
for options in self.jobfile.options(groups):
|
||||
chart = BarChart(self)
|
||||
|
||||
data = zeros((len(groupopts), len(baropts)), Float)
|
||||
data = [ [ None ] * len(baropts) for i in xrange(len(groupopts)) ]
|
||||
enabled = False
|
||||
stacked = 0
|
||||
for g,gopt in enumerate(groupopts):
|
||||
for b,bopt in enumerate(baropts):
|
||||
job = self.jobfile.job(options + [ gopt, bopt ])
|
||||
job = self.jobfile.job(options + gopt + bopt)
|
||||
if not job:
|
||||
continue
|
||||
|
||||
if proxy:
|
||||
import db
|
||||
proxy.dict['system'] = self.info[job.system]
|
||||
val = self.info.get(job, self.stat)
|
||||
if val is None:
|
||||
print 'stat "%s" for job "%s" not found' % \
|
||||
(self.stat, job)
|
||||
|
||||
if isinstance(val, (list, tuple)):
|
||||
if len(val) == 1:
|
||||
val = val[0]
|
||||
|
@ -151,7 +160,7 @@ class StatOutput(object):
|
|||
for j in xrange(len(baropts)):
|
||||
val = data[i][j]
|
||||
if val is None:
|
||||
data[i][j] = [] * stacked
|
||||
data[i][j] = [ 0.0 ] * stacked
|
||||
elif len(val) != stacked:
|
||||
raise ValueError, "some stats stacked, some not"
|
||||
|
||||
|
@ -159,29 +168,52 @@ class StatOutput(object):
|
|||
if data.sum() == 0:
|
||||
continue
|
||||
|
||||
bar_descs = [ opt.desc for opt in baropts ]
|
||||
group_descs = [ opt.desc for opt in groupopts ]
|
||||
if stacked:
|
||||
try:
|
||||
legend = self.info.rcategories
|
||||
except:
|
||||
legend = [ str(i) for i in xrange(stacked) ]
|
||||
else:
|
||||
legend = bar_descs
|
||||
x = data.shape[0]
|
||||
y = data.shape[1]
|
||||
xkeep = [ i for i in xrange(x) if data[i].sum() != 0 ]
|
||||
ykeep = [ i for i in xrange(y) if data[:,i].sum() != 0 ]
|
||||
data = data.take(xkeep, axis=0)
|
||||
data = data.take(ykeep, axis=1)
|
||||
chart.data = data
|
||||
|
||||
chart = BarChart(data=data, xlabel='Benchmark', ylabel=self.label,
|
||||
legend=legend, xticks=group_descs)
|
||||
gopts = [ groupopts[i] for i in xkeep ]
|
||||
bopts = [ baropts[i] for i in ykeep ]
|
||||
|
||||
bdescs = [ ' '.join([o.desc for o in opt]) for opt in bopts]
|
||||
gdescs = [ ' '.join([o.desc for o in opt]) for opt in gopts]
|
||||
|
||||
if chart.legend is None:
|
||||
if stacked:
|
||||
try:
|
||||
chart.legend = self.info.rcategories
|
||||
except:
|
||||
chart.legend = [ str(i) for i in xrange(stacked) ]
|
||||
else:
|
||||
chart.legend = bdescs
|
||||
|
||||
if chart.xticks is None:
|
||||
chart.xticks = gdescs
|
||||
chart.graph()
|
||||
|
||||
names = [ opt.name for opt in options ]
|
||||
descs = [ opt.desc for opt in options ]
|
||||
|
||||
filename = '%s-%s.png' % (self.name, ':'.join(names))
|
||||
if names[0] == 'run':
|
||||
names = names[1:]
|
||||
descs = descs[1:]
|
||||
|
||||
basename = '%s-%s' % (name, ':'.join(names))
|
||||
desc = ' '.join(descs)
|
||||
filepath = joinpath(directory, filename)
|
||||
chart.savefig(filepath)
|
||||
filename = re.sub(':', '%3A', filename)
|
||||
print >>html, '''%s<br><img src="%s"><br>''' % (desc, filename)
|
||||
|
||||
pngname = '%s.png' % basename
|
||||
psname = '%s.eps' % re.sub(':', '-', basename)
|
||||
epsname = '%s.ps' % re.sub(':', '-', basename)
|
||||
chart.savefig(joinpath(directory, pngname))
|
||||
chart.savefig(joinpath(directory, epsname))
|
||||
chart.savefig(joinpath(directory, psname))
|
||||
html_name = urllib.quote(pngname)
|
||||
print >>html, '''%s<br><img src="%s"><br>''' % (desc, html_name)
|
||||
html.flush()
|
||||
|
||||
print >>html, '</body>'
|
||||
print >>html, '</html>'
|
||||
|
|
|
@ -27,19 +27,39 @@
|
|||
from orderdict import orderdict
|
||||
import output
|
||||
|
||||
class FileData(dict):
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
fd = file(filename)
|
||||
current = []
|
||||
for line in fd:
|
||||
line = line.strip()
|
||||
if line.startswith('>>>'):
|
||||
current = []
|
||||
self[line[3:]] = current
|
||||
else:
|
||||
current.append(line)
|
||||
fd.close()
|
||||
|
||||
class RunData(dict):
|
||||
def __init__(self, filename=None):
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
|
||||
def __getattr__(self, attr):
|
||||
def __getattribute__(self, attr):
|
||||
if attr == 'total':
|
||||
total = 0.0
|
||||
for value in self.itervalues():
|
||||
total += value
|
||||
return total
|
||||
|
||||
if attr == 'filedata':
|
||||
return FileData(self.filename)
|
||||
|
||||
if attr == 'maxsymlen':
|
||||
return max([ len(sym) for sym in self.iterkeys() ])
|
||||
|
||||
return super(RunData, self).__getattribute__(attr)
|
||||
|
||||
def display(self, output=None, limit=None, maxsymlen=None):
|
||||
if not output:
|
||||
import sys
|
||||
|
@ -62,24 +82,12 @@ class RunData(dict):
|
|||
for number,name in symbols:
|
||||
print >>output, symbolf % (name, 100.0 * (float(number) / total))
|
||||
|
||||
|
||||
|
||||
class PCData(RunData):
|
||||
def __init__(self, filename=None, categorize=None, showidle=True):
|
||||
super(PCData, self).__init__(self, filename)
|
||||
if filename is None:
|
||||
return
|
||||
|
||||
fd = file(filename)
|
||||
|
||||
for line in fd:
|
||||
if line.strip() == '>>>PC data':
|
||||
break
|
||||
|
||||
for line in fd:
|
||||
if line.startswith('>>>'):
|
||||
break
|
||||
|
||||
filedata = self.filedata['PC data']
|
||||
for line in filedata:
|
||||
(symbol, count) = line.split()
|
||||
if symbol == "0x0":
|
||||
continue
|
||||
|
@ -94,30 +102,21 @@ class PCData(RunData):
|
|||
|
||||
self[category] = count
|
||||
|
||||
fd.close()
|
||||
|
||||
class FuncNode(object):
|
||||
def __new__(cls, filename = None):
|
||||
if filename is None:
|
||||
def __new__(cls, filedata=None):
|
||||
if filedata is None:
|
||||
return super(FuncNode, cls).__new__(cls)
|
||||
|
||||
fd = file(filename, 'r')
|
||||
fditer = iter(fd)
|
||||
nodes = {}
|
||||
for line in fditer:
|
||||
if line.strip() == '>>>function data':
|
||||
break
|
||||
|
||||
for line in fditer:
|
||||
if line.startswith('>>>'):
|
||||
break
|
||||
|
||||
data = line.split()
|
||||
node_id = int(data[0], 16)
|
||||
for line in filedata['function data']:
|
||||
data = line.split(' ')
|
||||
node_id = long(data[0], 16)
|
||||
node = FuncNode()
|
||||
node.symbol = data[1]
|
||||
node.count = int(data[2])
|
||||
node.children = [ int(child, 16) for child in data[3:] ]
|
||||
if node.symbol == '':
|
||||
node.symbol = 'unknown'
|
||||
node.count = long(data[2])
|
||||
node.children = [ long(child, 16) for child in data[3:] ]
|
||||
nodes[node_id] = node
|
||||
|
||||
for node in nodes.itervalues():
|
||||
|
@ -128,13 +127,10 @@ class FuncNode(object):
|
|||
child.parent = node
|
||||
node.children = tuple(children)
|
||||
if not nodes:
|
||||
print filename
|
||||
print filedata.filename
|
||||
print nodes
|
||||
return nodes[0]
|
||||
|
||||
def __init__(self, filename=None):
|
||||
pass
|
||||
|
||||
def total(self):
|
||||
total = self.count
|
||||
for child in self.children:
|
||||
|
@ -198,9 +194,14 @@ class FuncNode(object):
|
|||
class FuncData(RunData):
|
||||
def __init__(self, filename, categorize=None):
|
||||
super(FuncData, self).__init__(filename)
|
||||
self.tree = FuncNode(filename)
|
||||
self.tree.aggregate(self, categorize, incategory=False)
|
||||
self.total = self.tree.total()
|
||||
tree = self.tree
|
||||
tree.aggregate(self, categorize, incategory=False)
|
||||
self.total = tree.total()
|
||||
|
||||
def __getattribute__(self, attr):
|
||||
if attr == 'tree':
|
||||
return FuncNode(self.filedata)
|
||||
return super(FuncData, self).__getattribute__(attr)
|
||||
|
||||
def displayx(self, output=None, maxcount=None):
|
||||
if output is None:
|
||||
|
@ -274,6 +275,7 @@ class Profile(object):
|
|||
try:
|
||||
return self.data[run][cpu]
|
||||
except KeyError:
|
||||
print run, cpu
|
||||
return None
|
||||
|
||||
def alldata(self):
|
||||
|
@ -289,12 +291,16 @@ class Profile(object):
|
|||
cpu = '%s.run%d' % (job.system, self.cpu)
|
||||
data = self.getdata(run, cpu)
|
||||
if not data:
|
||||
return [ 0.0 for c in self.categories ]
|
||||
return None
|
||||
|
||||
values = []
|
||||
for category in self.categories:
|
||||
values.append(data.get(category, 0.0))
|
||||
return values
|
||||
val = float(data.get(category, 0.0))
|
||||
if val < 0.0:
|
||||
raise ValueError, 'value is %f' % val
|
||||
values.append(val)
|
||||
total = sum(values)
|
||||
return [ v / total * 100.0 for v in values ]
|
||||
|
||||
def dump(self):
|
||||
for run,cpu,data in self.alldata():
|
||||
|
@ -382,7 +388,6 @@ if __name__ == '__main__':
|
|||
import getopt, re, sys
|
||||
from os.path import expanduser
|
||||
from output import StatOutput
|
||||
from jobfile import JobFile
|
||||
|
||||
# default option values
|
||||
numsyms = 10
|
||||
|
@ -393,7 +398,7 @@ if __name__ == '__main__':
|
|||
funcdata = True
|
||||
jobfilename = 'Test.py'
|
||||
dodot = False
|
||||
dotformat = 'raw'
|
||||
dotfile = None
|
||||
textout = False
|
||||
threshold = 0.01
|
||||
inputfile = None
|
||||
|
@ -409,7 +414,7 @@ if __name__ == '__main__':
|
|||
elif o == '-c':
|
||||
categorize = True
|
||||
elif o == '-D':
|
||||
dotformat = a
|
||||
dotfile = a
|
||||
elif o == '-d':
|
||||
dodot = True
|
||||
elif o == '-f':
|
||||
|
@ -434,20 +439,24 @@ if __name__ == '__main__':
|
|||
usage(1)
|
||||
|
||||
if inputfile:
|
||||
data = FuncData(inputfile)
|
||||
catfunc = None
|
||||
if categorize:
|
||||
catfunc = func_categorize
|
||||
data = FuncData(inputfile, categorize=catfunc)
|
||||
|
||||
if dodot:
|
||||
import pydot
|
||||
dot = pydot.Dot()
|
||||
data.dot(dot, threshold=threshold)
|
||||
data.tree.dot(dot, threshold=threshold)
|
||||
#dot.orientation = 'landscape'
|
||||
#dot.ranksep='equally'
|
||||
#dot.rank='samerank'
|
||||
dot.write(dotfile, format=dotformat)
|
||||
dot.write(dotfile, format='png')
|
||||
else:
|
||||
data.display(limit=numsyms)
|
||||
|
||||
else:
|
||||
from jobfile import JobFile
|
||||
jobfile = JobFile(jobfilename)
|
||||
|
||||
if funcdata:
|
||||
|
@ -466,8 +475,11 @@ if __name__ == '__main__':
|
|||
name = 'funcstacks%d' % cpu
|
||||
else:
|
||||
name = 'stacks%d' % cpu
|
||||
output = StatOutput(name, jobfile, info=profile)
|
||||
output.graph(graph)
|
||||
output = StatOutput(jobfile, info=profile)
|
||||
output.xlabel = 'System Configuration'
|
||||
output.ylabel = '% CPU utilization'
|
||||
output.stat = name
|
||||
output.graph(name, graph)
|
||||
|
||||
if dodot:
|
||||
for cpu in cpus:
|
||||
|
|
|
@ -259,14 +259,9 @@ def commands(options, command, args):
|
|||
print 'only displaying sample %s' % options.ticks
|
||||
source.ticks = [ int(x) for x in options.ticks.split() ]
|
||||
|
||||
import output
|
||||
|
||||
def display():
|
||||
if options.graph:
|
||||
output.graph(options.graphdir)
|
||||
else:
|
||||
output.display(options.binned, options.printmode)
|
||||
|
||||
from output import StatOutput
|
||||
output = StatOutput(options.jobfile, source)
|
||||
output.xlabel = 'System Configuration'
|
||||
|
||||
if command == 'stat' or command == 'formula':
|
||||
if len(args) != 1:
|
||||
|
@ -278,17 +273,18 @@ def commands(options, command, args):
|
|||
stats = eval(args[0])
|
||||
|
||||
for stat in stats:
|
||||
output = output.StatOutput(stat.name, options.jobfile, source)
|
||||
output.stat = stat
|
||||
output.label = stat.name
|
||||
display()
|
||||
output.ylabel = stat.name
|
||||
if options.graph:
|
||||
output.graph(stat.name, options.graphdir)
|
||||
else:
|
||||
output.display(stat.name, options.binned, options.printmode)
|
||||
|
||||
return
|
||||
|
||||
if len(args):
|
||||
raise CommandException
|
||||
|
||||
system = source.__dict__[options.system]
|
||||
from info import ProxyGroup
|
||||
sim_seconds = source['sim_seconds']
|
||||
proxy = ProxyGroup(system = source[options.system])
|
||||
|
@ -300,7 +296,11 @@ def commands(options, command, args):
|
|||
packets = etherdev.rxPackets + etherdev.txPackets
|
||||
bps = etherdev.rxBandwidth + etherdev.txBandwidth
|
||||
|
||||
output = output.StatOutput(command, options.jobfile, source)
|
||||
def display():
|
||||
if options.graph:
|
||||
output.graph(command, options.graphdir, proxy)
|
||||
else:
|
||||
output.display(command, options.binned, options.printmode)
|
||||
|
||||
if command == 'usertime':
|
||||
import copy
|
||||
|
@ -308,7 +308,7 @@ def commands(options, command, args):
|
|||
user.bins = 'user'
|
||||
|
||||
output.stat = user / system.run0.numCycles
|
||||
output.label = 'User Fraction'
|
||||
output.ylabel = 'User Fraction'
|
||||
|
||||
display()
|
||||
return
|
||||
|
@ -338,13 +338,13 @@ def commands(options, command, args):
|
|||
|
||||
if command == 'pps':
|
||||
output.stat = packets / sim_seconds
|
||||
output.label = 'Packets/s'
|
||||
output.ylabel = 'Packets/s'
|
||||
display()
|
||||
return
|
||||
|
||||
if command == 'bpt' or command == 'tpb':
|
||||
output.stat = bytes / system.run0.numCycles * 8
|
||||
output.label = 'bps / Hz'
|
||||
output.ylabel = 'bps / Hz'
|
||||
output.invert = command == 'tpb'
|
||||
display()
|
||||
return
|
||||
|
@ -357,37 +357,38 @@ def commands(options, command, args):
|
|||
if command == 'bps':
|
||||
output.stat = bps / 1e9
|
||||
|
||||
output.label = 'Bandwidth (Gbps)'
|
||||
output.ylabel = 'Bandwidth (Gbps)'
|
||||
output.ylim = [ 0.0, 10.0 ]
|
||||
display()
|
||||
return
|
||||
|
||||
if command == 'bpp':
|
||||
output.stat = bytes / packets
|
||||
output.label = 'Bytes / Packet'
|
||||
output.ylabel = 'Bytes / Packet'
|
||||
display()
|
||||
return
|
||||
|
||||
if command == 'rxbpp':
|
||||
output.stat = etherdev.rxBytes / etherdev.rxPackets
|
||||
output.label = 'Receive Bytes / Packet'
|
||||
output.ylabel = 'Receive Bytes / Packet'
|
||||
display()
|
||||
return
|
||||
|
||||
if command == 'txbpp':
|
||||
output.stat = etherdev.txBytes / etherdev.txPackets
|
||||
output.label = 'Transmit Bytes / Packet'
|
||||
output.ylabel = 'Transmit Bytes / Packet'
|
||||
display()
|
||||
return
|
||||
|
||||
if command == 'rtp':
|
||||
output.stat = etherdev.rxPackets / etherdev.txPackets
|
||||
output.label = 'rxPackets / txPackets'
|
||||
output.ylabel = 'rxPackets / txPackets'
|
||||
display()
|
||||
return
|
||||
|
||||
if command == 'rtb':
|
||||
output.stat = etherdev.rxBytes / etherdev.txBytes
|
||||
output.label = 'rxBytes / txBytes'
|
||||
output.ylabel = 'rxBytes / txBytes'
|
||||
display()
|
||||
return
|
||||
|
||||
|
@ -395,14 +396,14 @@ def commands(options, command, args):
|
|||
|
||||
if command == 'misses':
|
||||
output.stat = misses
|
||||
output.label = 'Overall MSHR Misses'
|
||||
output.ylabel = 'Overall MSHR Misses'
|
||||
display()
|
||||
return
|
||||
|
||||
if command == 'mpkb':
|
||||
output.stat = misses / (bytes / 1024)
|
||||
output.binstats = [ misses ]
|
||||
output.label = 'Misses / KB'
|
||||
output.ylabel = 'Misses / KB'
|
||||
display()
|
||||
return
|
||||
|
||||
|
@ -410,7 +411,7 @@ def commands(options, command, args):
|
|||
interrupts = system.run0.kern.faults[4]
|
||||
output.stat = interrupts / kbytes
|
||||
output.binstats = [ interrupts ]
|
||||
output.label = 'Interrupts / KB'
|
||||
output.ylabel = 'Interrupts / KB'
|
||||
display()
|
||||
return
|
||||
|
||||
|
|
Loading…
Reference in a new issue