gem5/util/stats/info.py
Nathan Binkert ab10712341 stats python fixes for dealing with vectors better. graph tweaking
ipkb stat and formulas from the command line.

util/stats/info.py:
    no need to raise an attribute error if two values aren't found
    in the exact same set of runs.  Would be good to check that each
    run is the same though.
util/stats/stats.py:
    more graph tweaking
    command to execute a formula from the command line.
    add interrupts per kilobyte of data

--HG--
extra : convert_revision : 78d6b14d340d08edcbc69e4c1c5a4c1dd9bb10dd
2004-11-18 16:23:29 -05:00

721 lines
20 KiB
Python

from __future__ import division
import operator, re, types
source = None
display_run = 0
def issequence(t):
return isinstance(t, types.TupleType) or isinstance(t, types.ListType)
def total(f):
if isinstance(f, FormulaStat):
v = f.value
else:
v = f
f = FormulaStat()
if issequence(v):
f.value = reduce(operator.add, v)
else:
f.value = v
return f
def unaryop(op, f):
if isinstance(f, FormulaStat):
v = f.value
else:
v = f
if issequence(v):
return map(op, v)
else:
return op(v)
def zerodiv(lv, rv):
if rv == 0.0:
return 0.0
else:
return operator.truediv(lv, rv)
def wrapop(op, lv, rv):
if isinstance(lv, str):
return lv
if isinstance(rv, str):
return rv
return op(lv, rv)
def same(lrun, rrun):
for lx,rx in zip(lrun.keys(),rrun.keys()):
if lx != rx:
print 'lx != rx'
print lx, rx
print lrun.keys()
print rrun.keys()
return False
for ly,ry in zip(lrun[lx].keys(),rrun[rx].keys()):
if ly != ry:
print 'ly != ry'
print ly, ry
print lrun[lx].keys()
print rrun[rx].keys()
return False
return True
def binaryop(op, lf, rf):
result = {}
if isinstance(lf, FormulaStat) and isinstance(rf, FormulaStat):
lv = lf.value
rv = rf.value
theruns = []
for r in lv.keys():
if rv.has_key(r):
if same(lv[r], rv[r]):
theruns.append(r)
else:
raise AttributeError
for run in theruns:
result[run] = {}
for x in lv[run].keys():
result[run][x] = {}
for y in lv[run][x].keys():
result[run][x][y] = wrapop(op, lv[run][x][y],
rv[run][x][y])
elif isinstance(lf, FormulaStat):
lv = lf.value
for run in lv.keys():
result[run] = {}
for x in lv[run].keys():
result[run][x] = {}
for y in lv[run][x].keys():
result[run][x][y] = wrapop(op, lv[run][x][y], rf)
elif isinstance(rf, FormulaStat):
rv = rf.value
for run in rv.keys():
result[run] = {}
for x in rv[run].keys():
result[run][x] = {}
for y in rv[run][x].keys():
result[run][x][y] = wrapop(op, lf, rv[run][x][y])
return result
def sums(x, y):
if issequence(x):
return map(lambda x, y: x + y, x, y)
else:
return x + y
def alltrue(list):
return reduce(lambda x, y: x and y, list)
def allfalse(list):
return not reduce(lambda x, y: x or y, list)
def enumerate(list):
return map(None, range(len(list)), list)
def cmp(a, b):
if a < b:
return -1
elif a == b:
return 0
else:
return 1
class Statistic(object):
def __init__(self, data):
self.__dict__.update(data.__dict__)
if not self.__dict__.has_key('value'):
self.__dict__['value'] = None
if not self.__dict__.has_key('bins'):
self.__dict__['bins'] = None
if not self.__dict__.has_key('ticks'):
self.__dict__['ticks'] = None
def __getattribute__(self, attr):
if attr == 'value':
if self.__dict__['value'] == None:
self.__dict__['value'] = self.getValue()
return self.__dict__['value']
else:
return super(Statistic, self).__getattribute__(attr)
def __setattr__(self, attr, value):
if attr == 'bins' or attr == 'ticks':
if attr == 'bins':
if value is not None:
value = source.getBin(value)
elif attr == 'samples' and type(value) is str:
value = [ int(x) for x in value.split() ]
self.__dict__[attr] = value
self.__dict__['value'] = None
else:
super(Statistic, self).__setattr__(attr, value)
def getValue(self):
raise AttributeError, 'getValue() must be defined'
def zero(self):
return False
def __ne__(self, other):
return not (self == other)
def __str__(self):
return '%f' % (float(self))
class FormulaStat(object):
def __add__(self, other):
f = FormulaStat()
f.value = binaryop(operator.add, self, other)
return f
def __sub__(self, other):
f = FormulaStat()
f.value = binaryop(operator.sub, self, other)
return f
def __mul__(self, other):
f = FormulaStat()
f.value = binaryop(operator.mul, self, other)
return f
def __truediv__(self, other):
f = FormulaStat()
f.value = binaryop(zerodiv, self, other)
return f
def __mod__(self, other):
f = FormulaStat()
f.value = binaryop(operator.mod, self, other)
return f
def __radd__(self, other):
f = FormulaStat()
f.value = binaryop(operator.add, other, self)
return f
def __rsub__(self, other):
f = FormulaStat()
f.value = binaryop(operator.sub, other, self)
return f
def __rmul__(self, other):
f = FormulaStat()
f.value = binaryop(operator.mul, other, self)
return f
def __rtruediv__(self, other):
f = FormulaStat()
f.value = binaryop(zerodiv, other, self)
return f
def __rmod__(self, other):
f = FormulaStat()
f.value = binaryop(operator.mod, other, self)
return f
def __neg__(self):
f = FormulaStat()
f.value = unaryop(operator.neg, self)
return f
def __getitem__(self, idx):
f = FormulaStat()
f.value = {}
for key in self.value.keys():
f.value[key] = {}
f.value[key][0] = {}
f.value[key][0][0] = self.value[key][idx][0]
return f
def __float__(self):
if isinstance(self.value, FormulaStat):
return float(self.value)
if not self.value.has_key(display_run):
return (1e300*1e300)
if len(self.value[display_run]) == 1:
return self.value[display_run][0][0]
else:
#print self.value[display_run]
return self.value[display_run][4][0]
#raise ValueError
def display(self):
import display
d = display.VectorDisplay()
d.flags = 0
d.precision = 1
d.name = 'formula'
d.desc = 'formula'
val = self.value[display_run]
d.value = [ val[x][0] for x in val.keys() ]
d.display()
class Scalar(Statistic,FormulaStat):
def getValue(self):
return source.data(self, self.bins)
def display(self):
import display
p = display.Print()
p.name = self.name
p.desc = self.desc
p.value = float(self)
p.flags = self.flags
p.precision = self.precision
if display.all or (self.flags & flags.printable):
p.display()
def comparable(self, other):
return self.name == other.name
def __eq__(self, other):
return self.value == other.value
def __isub__(self, other):
self.value -= other.value
return self
def __iadd__(self, other):
self.value += other.value
return self
def __itruediv__(self, other):
if not other:
return self
self.value /= other
return self
class Vector(Statistic,FormulaStat):
def getValue(self):
return source.data(self, self.bins);
def display(self):
import display
if not display.all and not (self.flags & flags.printable):
return
d = display.VectorDisplay()
d.__dict__.update(self.__dict__)
d.display()
def comparable(self, other):
return self.name == other.name and \
len(self.value) == len(other.value)
def __eq__(self, other):
if issequence(self.value) != issequence(other.value):
return false
if issequence(self.value):
if len(self.value) != len(other.value):
return False
else:
for v1,v2 in zip(self.value, other.value):
if v1 != v2:
return False
return True
else:
return self.value == other.value
def __isub__(self, other):
self.value = binaryop(operator.sub, self.value, other.value)
return self
def __iadd__(self, other):
self.value = binaryop(operator.add, self.value, other.value)
return self
def __itruediv__(self, other):
if not other:
return self
if issequence(self.value):
for i in xrange(len(self.value)):
self.value[i] /= other
else:
self.value /= other
return self
class Formula(Vector):
def getValue(self):
formula = re.sub(':', '__', self.formula)
x = eval(formula, source.stattop)
return x.value
def comparable(self, other):
return self.name == other.name and \
compare(self.dist, other.dist)
def __eq__(self, other):
return self.value == other.value
def __isub__(self, other):
return self
def __iadd__(self, other):
return self
def __itruediv__(self, other):
if not other:
return self
return self
class SimpleDist(object):
def __init__(self, sums, squares, samples):
self.sums = sums
self.squares = squares
self.samples = samples
def getValue(self):
return 0.0
def display(self, name, desc, flags, precision):
import display
p = display.Print()
p.flags = flags
p.precision = precision
if self.samples > 0:
p.name = name + ".mean"
p.value = self.sums / self.samples
p.display()
p.name = name + ".stdev"
if self.samples > 1:
var = (self.samples * self.squares - self.sums ** 2) \
/ (self.samples * (self.samples - 1))
if var >= 0:
p.value = math.sqrt(var)
else:
p.value = 'NaN'
else:
p.value = 0.0
p.display()
p.name = name + ".samples"
p.value = self.samples
p.display()
def comparable(self, other):
return True
def __eq__(self, other):
return self.sums == other.sums and self.squares == other.squares and \
self.samples == other.samples
def __isub__(self, other):
self.sums -= other.sums
self.squares -= other.squares
self.samples -= other.samples
return self
def __iadd__(self, other):
self.sums += other.sums
self.squares += other.squares
self.samples += other.samples
return self
def __itruediv__(self, other):
if not other:
return self
self.sums /= other
self.squares /= other
self.samples /= other
return self
class FullDist(SimpleDist):
def __init__(self, sums, squares, samples, minval, maxval,
under, vec, over, min, max, bsize, size):
self.sums = sums
self.squares = squares
self.samples = samples
self.minval = minval
self.maxval = maxval
self.under = under
self.vec = vec
self.over = over
self.min = min
self.max = max
self.bsize = bsize
self.size = size
def getValue(self):
return 0.0
def display(self, name, desc, flags, precision):
import display
p = display.Print()
p.flags = flags
p.precision = precision
p.name = name + '.min_val'
p.value = self.minval
p.display()
p.name = name + '.max_val'
p.value = self.maxval
p.display()
p.name = name + '.underflow'
p.value = self.under
p.display()
i = self.min
for val in self.vec[:-1]:
p.name = name + '[%d:%d]' % (i, i + self.bsize - 1)
p.value = val
p.display()
i += self.bsize
p.name = name + '[%d:%d]' % (i, self.max)
p.value = self.vec[-1]
p.display()
p.name = name + '.overflow'
p.value = self.over
p.display()
SimpleDist.display(self, name, desc, flags, precision)
def comparable(self, other):
return self.min == other.min and self.max == other.max and \
self.bsize == other.bsize and self.size == other.size
def __eq__(self, other):
return self.sums == other.sums and self.squares == other.squares and \
self.samples == other.samples
def __isub__(self, other):
self.sums -= other.sums
self.squares -= other.squares
self.samples -= other.samples
if other.samples:
self.minval = min(self.minval, other.minval)
self.maxval = max(self.maxval, other.maxval)
self.under -= under
self.vec = map(lambda x,y: x - y, self.vec, other.vec)
self.over -= over
return self
def __iadd__(self, other):
if not self.samples and other.samples:
self = other
return self
self.sums += other.sums
self.squares += other.squares
self.samples += other.samples
if other.samples:
self.minval = min(self.minval, other.minval)
self.maxval = max(self.maxval, other.maxval)
self.under += other.under
self.vec = map(lambda x,y: x + y, self.vec, other.vec)
self.over += other.over
return self
def __itruediv__(self, other):
if not other:
return self
self.sums /= other
self.squares /= other
self.samples /= other
if self.samples:
self.under /= other
for i in xrange(len(self.vec)):
self.vec[i] /= other
self.over /= other
return self
class Dist(Statistic):
def getValue(self):
return 0.0
def display(self):
import display
if not display.all and not (self.flags & flags.printable):
return
self.dist.display(self.name, self.desc, self.flags, self.precision)
def comparable(self, other):
return self.name == other.name and \
self.dist.compareable(other.dist)
def __eq__(self, other):
return self.dist == other.dist
def __isub__(self, other):
self.dist -= other.dist
return self
def __iadd__(self, other):
self.dist += other.dist
return self
def __itruediv__(self, other):
if not other:
return self
self.dist /= other
return self
class VectorDist(Statistic):
def getValue(self):
return 0.0
def display(self):
import display
if not display.all and not (self.flags & flags.printable):
return
if isinstance(self.dist, SimpleDist):
return
for dist,sn,sd,i in map(None, self.dist, self.subnames, self.subdescs,
range(len(self.dist))):
if len(sn) > 0:
name = '%s.%s' % (self.name, sn)
else:
name = '%s[%d]' % (self.name, i)
if len(sd) > 0:
desc = sd
else:
desc = self.desc
dist.display(name, desc, self.flags, self.precision)
if (self.flags & flags.total) or 1:
if isinstance(self.dist[0], SimpleDist):
disttotal = SimpleDist( \
reduce(sums, [d.sums for d in self.dist]),
reduce(sums, [d.squares for d in self.dist]),
reduce(sums, [d.samples for d in self.dist]))
else:
disttotal = FullDist( \
reduce(sums, [d.sums for d in self.dist]),
reduce(sums, [d.squares for d in self.dist]),
reduce(sums, [d.samples for d in self.dist]),
min([d.minval for d in self.dist]),
max([d.maxval for d in self.dist]),
reduce(sums, [d.under for d in self.dist]),
reduce(sums, [d.vec for d in self.dist]),
reduce(sums, [d.over for d in self.dist]),
dist[0].min,
dist[0].max,
dist[0].bsize,
dist[0].size)
name = '%s.total' % (self.name)
desc = self.desc
disttotal.display(name, desc, self.flags, self.precision)
def comparable(self, other):
return self.name == other.name and \
alltrue(map(lambda x, y : x.comparable(y),
self.dist,
other.dist))
def __eq__(self, other):
return alltrue(map(lambda x, y : x == y, self.dist, other.dist))
def __isub__(self, other):
if issequence(self.dist) and issequence(other.dist):
for sd,od in zip(self.dist, other.dist):
sd -= od
else:
self.dist -= other.dist
return self
def __iadd__(self, other):
if issequence(self.dist) and issequence(other.dist):
for sd,od in zip(self.dist, other.dist):
sd += od
else:
self.dist += other.dist
return self
def __itruediv__(self, other):
if not other:
return self
if issequence(self.dist):
for dist in self.dist:
dist /= other
else:
self.dist /= other
return self
class Vector2d(Statistic):
def getValue(self):
return 0.0
def display(self):
import display
if not display.all and not (self.flags & flags.printable):
return
d = display.VectorDisplay()
d.__dict__.update(self.__dict__)
if self.__dict__.has_key('ysubnames'):
ysubnames = list(self.ysubnames)
slack = self.x - len(ysubnames)
if slack > 0:
ysubnames.extend(['']*slack)
else:
ysubnames = range(self.x)
for x,sname in enumerate(ysubnames):
o = x * self.y
d.value = self.value[o:o+self.y]
d.name = '%s[%s]' % (self.name, sname)
d.display()
if self.flags & flags.total:
d.value = []
for y in range(self.y):
xtot = 0.0
for x in range(self.x):
xtot += self.value[y + x * self.x]
d.value.append(xtot)
d.name = self.name + '.total'
d.display()
def comparable(self, other):
return self.name == other.name and self.x == other.x and \
self.y == other.y
def __eq__(self, other):
return True
def __isub__(self, other):
return self
def __iadd__(self, other):
return self
def __itruediv__(self, other):
if not other:
return self
return self
def NewStat(data):
stat = None
if data.type == 'SCALAR':
stat = Scalar(data)
elif data.type == 'VECTOR':
stat = Vector(data)
elif data.type == 'DIST':
stat = Dist(data)
elif data.type == 'VECTORDIST':
stat = VectorDist(data)
elif data.type == 'VECTOR2D':
stat = Vector2d(data)
elif data.type == 'FORMULA':
stat = Formula(data)
return stat