3c95f5958f
into iceaxe.:/Volumes/work/research/m5/merge src/cpu/simple/base.cc: src/kern/kernel_stats.cc: src/kern/kernel_stats.hh: src/kern/system_events.cc: src/kern/system_events.hh: src/python/m5/objects/System.py: src/sim/system.cc: src/sim/system.hh: hand merge --HG-- rename : build/SConstruct => SConstruct rename : SConscript => src/SConscript rename : arch/alpha/freebsd/system.cc => src/arch/alpha/freebsd/system.cc rename : arch/alpha/linux/system.cc => src/arch/alpha/linux/system.cc rename : arch/alpha/linux/system.hh => src/arch/alpha/linux/system.hh rename : arch/alpha/system.cc => src/arch/alpha/system.cc rename : arch/alpha/tru64/system.cc => src/arch/alpha/tru64/system.cc rename : base/statistics.cc => src/base/statistics.cc rename : base/statistics.hh => src/base/statistics.hh rename : base/stats/mysql.cc => src/base/stats/mysql.cc rename : base/stats/mysql.hh => src/base/stats/mysql.hh rename : base/stats/statdb.cc => src/base/stats/statdb.cc rename : base/stats/statdb.hh => src/base/stats/statdb.hh rename : base/stats/text.cc => src/base/stats/text.cc rename : base/stats/text.hh => src/base/stats/text.hh rename : cpu/simple/cpu.cc => src/cpu/simple/base.cc rename : kern/kernel_stats.cc => src/kern/kernel_stats.cc rename : kern/kernel_stats.hh => src/kern/kernel_stats.hh rename : kern/system_events.cc => src/kern/system_events.cc rename : kern/system_events.hh => src/kern/system_events.hh rename : python/m5/objects/System.py => src/python/m5/objects/System.py rename : sim/system.cc => src/sim/system.cc rename : sim/system.hh => src/sim/system.hh rename : test/stattest.cc => src/unittest/stattest.cc extra : convert_revision : 4bb576a2bf5e32784efc48030bd776c6c7c29a7c
436 lines
14 KiB
Python
436 lines
14 KiB
Python
# Copyright (c) 2003-2004 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
|
|
|
|
import MySQLdb, re, string
|
|
|
|
def statcmp(a, b):
|
|
v1 = a.split('.')
|
|
v2 = b.split('.')
|
|
|
|
last = min(len(v1), len(v2)) - 1
|
|
for i,j in zip(v1[0:last], v2[0:last]):
|
|
if i != j:
|
|
return cmp(i, j)
|
|
|
|
# Special compare for last element.
|
|
if len(v1) == len(v2):
|
|
return cmp(v1[last], v2[last])
|
|
else:
|
|
return cmp(len(v1), len(v2))
|
|
|
|
class RunData:
|
|
def __init__(self, row):
|
|
self.run = int(row[0])
|
|
self.name = row[1]
|
|
self.user = row[2]
|
|
self.project = row[3]
|
|
|
|
class SubData:
|
|
def __init__(self, row):
|
|
self.stat = int(row[0])
|
|
self.x = int(row[1])
|
|
self.y = int(row[2])
|
|
self.name = row[3]
|
|
self.descr = row[4]
|
|
|
|
class Data:
|
|
def __init__(self, row):
|
|
if len(row) != 5:
|
|
raise 'stat db error'
|
|
self.stat = int(row[0])
|
|
self.run = int(row[1])
|
|
self.x = int(row[2])
|
|
self.y = int(row[3])
|
|
self.data = float(row[4])
|
|
|
|
def __repr__(self):
|
|
return '''Data(['%d', '%d', '%d', '%d', '%f'])''' % ( self.stat,
|
|
self.run, self.x, self.y, self.data)
|
|
|
|
class StatData(object):
|
|
def __init__(self, row):
|
|
self.stat = int(row[0])
|
|
self.name = row[1]
|
|
self.desc = row[2]
|
|
self.type = row[3]
|
|
self.prereq = int(row[5])
|
|
self.precision = int(row[6])
|
|
|
|
import flags
|
|
self.flags = 0
|
|
if int(row[4]): self.flags |= flags.printable
|
|
if int(row[7]): self.flags |= flags.nozero
|
|
if int(row[8]): self.flags |= flags.nonan
|
|
if int(row[9]): self.flags |= flags.total
|
|
if int(row[10]): self.flags |= flags.pdf
|
|
if int(row[11]): self.flags |= flags.cdf
|
|
|
|
if self.type == 'DIST' or self.type == 'VECTORDIST':
|
|
self.min = float(row[12])
|
|
self.max = float(row[13])
|
|
self.bktsize = float(row[14])
|
|
self.size = int(row[15])
|
|
|
|
if self.type == 'FORMULA':
|
|
self.formula = self.db.allFormulas[self.stat]
|
|
|
|
class Node(object):
|
|
def __init__(self, name):
|
|
self.name = name
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
class Result(object):
|
|
def __init__(self, x, y):
|
|
self.data = {}
|
|
self.x = x
|
|
self.y = y
|
|
|
|
def __contains__(self, run):
|
|
return run in self.data
|
|
|
|
def __getitem__(self, run):
|
|
if run not in self.data:
|
|
self.data[run] = [ [ 0.0 ] * self.y for i in xrange(self.x) ]
|
|
return self.data[run]
|
|
|
|
class Database(object):
|
|
def __init__(self):
|
|
self.host = 'zizzer.pool'
|
|
self.user = ''
|
|
self.passwd = ''
|
|
self.db = 'm5stats'
|
|
self.cursor = None
|
|
|
|
self.allStats = []
|
|
self.allStatIds = {}
|
|
self.allStatNames = {}
|
|
|
|
self.allSubData = {}
|
|
|
|
self.allRuns = []
|
|
self.allRunIds = {}
|
|
self.allRunNames = {}
|
|
|
|
self.allFormulas = {}
|
|
|
|
self.stattop = {}
|
|
self.statdict = {}
|
|
self.statlist = []
|
|
|
|
self.mode = 'sum';
|
|
self.runs = None
|
|
self.ticks = None
|
|
self.method = 'sum'
|
|
self._method = type(self).sum
|
|
|
|
def get(self, job, stat, system=None):
|
|
run = self.allRunNames.get(str(job), None)
|
|
if run is None:
|
|
return None
|
|
|
|
from info import ProxyError, scalar, vector, value, values, total, len
|
|
if system is None and hasattr(job, 'system'):
|
|
system = job.system
|
|
|
|
if system is not None:
|
|
stat.system = self[system]
|
|
try:
|
|
if scalar(stat):
|
|
return value(stat, run.run)
|
|
if vector(stat):
|
|
return values(stat, run.run)
|
|
except ProxyError:
|
|
return None
|
|
|
|
return None
|
|
|
|
def query(self, sql):
|
|
self.cursor.execute(sql)
|
|
|
|
def update_dict(self, dict):
|
|
dict.update(self.stattop)
|
|
|
|
def append(self, stat):
|
|
statname = re.sub(':', '__', stat.name)
|
|
path = string.split(statname, '.')
|
|
pathtop = path[0]
|
|
fullname = ''
|
|
|
|
x = self
|
|
while len(path) > 1:
|
|
name = path.pop(0)
|
|
if not x.__dict__.has_key(name):
|
|
x.__dict__[name] = Node(fullname + name)
|
|
x = x.__dict__[name]
|
|
fullname = '%s%s.' % (fullname, name)
|
|
|
|
name = path.pop(0)
|
|
x.__dict__[name] = stat
|
|
|
|
self.stattop[pathtop] = self.__dict__[pathtop]
|
|
self.statdict[statname] = stat
|
|
self.statlist.append(statname)
|
|
|
|
def connect(self):
|
|
# connect
|
|
self.thedb = MySQLdb.connect(db=self.db,
|
|
host=self.host,
|
|
user=self.user,
|
|
passwd=self.passwd)
|
|
|
|
# create a cursor
|
|
self.cursor = self.thedb.cursor()
|
|
|
|
self.query('''select rn_id,rn_name,rn_sample,rn_user,rn_project
|
|
from runs''')
|
|
for result in self.cursor.fetchall():
|
|
run = RunData(result);
|
|
self.allRuns.append(run)
|
|
self.allRunIds[run.run] = run
|
|
self.allRunNames[run.name] = run
|
|
|
|
self.query('select sd_stat,sd_x,sd_y,sd_name,sd_descr from subdata')
|
|
for result in self.cursor.fetchall():
|
|
subdata = SubData(result)
|
|
if self.allSubData.has_key(subdata.stat):
|
|
self.allSubData[subdata.stat].append(subdata)
|
|
else:
|
|
self.allSubData[subdata.stat] = [ subdata ]
|
|
|
|
self.query('select * from formulas')
|
|
for id,formula in self.cursor.fetchall():
|
|
self.allFormulas[int(id)] = formula.tostring()
|
|
|
|
StatData.db = self
|
|
self.query('select * from stats')
|
|
import info
|
|
for result in self.cursor.fetchall():
|
|
stat = info.NewStat(self, StatData(result))
|
|
self.append(stat)
|
|
self.allStats.append(stat)
|
|
self.allStatIds[stat.stat] = stat
|
|
self.allStatNames[stat.name] = stat
|
|
|
|
# Name: listruns
|
|
# Desc: Prints all runs matching a given user, if no argument
|
|
# is given all runs are returned
|
|
def listRuns(self, user=None):
|
|
print '%-40s %-10s %-5s' % ('run name', 'user', 'id')
|
|
print '-' * 62
|
|
for run in self.allRuns:
|
|
if user == None or user == run.user:
|
|
print '%-40s %-10s %-10d' % (run.name, run.user, run.run)
|
|
|
|
# Name: listTicks
|
|
# Desc: Prints all samples for a given run
|
|
def listTicks(self, runs=None):
|
|
print "tick"
|
|
print "----------------------------------------"
|
|
sql = 'select distinct dt_tick from data where dt_stat=1180 and ('
|
|
if runs != None:
|
|
first = True
|
|
for run in runs:
|
|
if first:
|
|
# sql += ' where'
|
|
first = False
|
|
else:
|
|
sql += ' or'
|
|
sql += ' dt_run=%s' % run.run
|
|
sql += ')'
|
|
self.query(sql)
|
|
for r in self.cursor.fetchall():
|
|
print r[0]
|
|
|
|
# Name: retTicks
|
|
# Desc: Prints all samples for a given run
|
|
def retTicks(self, runs=None):
|
|
sql = 'select distinct dt_tick from data where dt_stat=1180 and ('
|
|
if runs != None:
|
|
first = True
|
|
for run in runs:
|
|
if first:
|
|
first = False
|
|
else:
|
|
sql += ' or'
|
|
sql += ' dt_run=%s' % run.run
|
|
sql += ')'
|
|
self.query(sql)
|
|
ret = []
|
|
for r in self.cursor.fetchall():
|
|
ret.append(r[0])
|
|
return ret
|
|
|
|
# Name: liststats
|
|
# Desc: Prints all statistics that appear in the database,
|
|
# the optional argument is a regular expression that can
|
|
# be used to prune the result set
|
|
def listStats(self, regex=None):
|
|
print '%-60s %-8s %-10s' % ('stat name', 'id', 'type')
|
|
print '-' * 80
|
|
|
|
rx = None
|
|
if regex != None:
|
|
rx = re.compile(regex)
|
|
|
|
stats = [ stat.name for stat in self.allStats ]
|
|
stats.sort(statcmp)
|
|
for stat in stats:
|
|
stat = self.allStatNames[stat]
|
|
if rx == None or rx.match(stat.name):
|
|
print '%-60s %-8s %-10s' % (stat.name, stat.stat, stat.type)
|
|
|
|
# Name: liststats
|
|
# Desc: Prints all statistics that appear in the database,
|
|
# the optional argument is a regular expression that can
|
|
# be used to prune the result set
|
|
def listFormulas(self, regex=None):
|
|
print '%-60s %s' % ('formula name', 'formula')
|
|
print '-' * 80
|
|
|
|
rx = None
|
|
if regex != None:
|
|
rx = re.compile(regex)
|
|
|
|
stats = [ stat.name for stat in self.allStats ]
|
|
stats.sort(statcmp)
|
|
for stat in stats:
|
|
stat = self.allStatNames[stat]
|
|
if stat.type == 'FORMULA' and (rx == None or rx.match(stat.name)):
|
|
print '%-60s %s' % (stat.name, self.allFormulas[stat.stat])
|
|
|
|
def getStat(self, stats):
|
|
if type(stats) is not list:
|
|
stats = [ stats ]
|
|
|
|
ret = []
|
|
for stat in stats:
|
|
if type(stat) is int:
|
|
ret.append(self.allStatIds[stat])
|
|
|
|
if type(stat) is str:
|
|
rx = re.compile(stat)
|
|
for stat in self.allStats:
|
|
if rx.match(stat.name):
|
|
ret.append(stat)
|
|
return ret
|
|
|
|
#########################################
|
|
# get the data
|
|
#
|
|
def query(self, op, stat, ticks, group=False):
|
|
sql = 'select '
|
|
sql += 'dt_stat as stat, '
|
|
sql += 'dt_run as run, '
|
|
sql += 'dt_x as x, '
|
|
sql += 'dt_y as y, '
|
|
if group:
|
|
sql += 'dt_tick as tick, '
|
|
sql += '%s(dt_data) as data ' % op
|
|
sql += 'from data '
|
|
sql += 'where '
|
|
|
|
if isinstance(stat, list):
|
|
val = ' or '.join([ 'dt_stat=%d' % s.stat for s in stat ])
|
|
sql += ' (%s)' % val
|
|
else:
|
|
sql += ' dt_stat=%d' % stat.stat
|
|
|
|
if self.runs != None and len(self.runs):
|
|
val = ' or '.join([ 'dt_run=%d' % r for r in self.runs ])
|
|
sql += ' and (%s)' % val
|
|
|
|
if ticks != None and len(ticks):
|
|
val = ' or '.join([ 'dt_tick=%d' % s for s in ticks ])
|
|
sql += ' and (%s)' % val
|
|
|
|
sql += ' group by dt_stat,dt_run,dt_x,dt_y'
|
|
if group:
|
|
sql += ',dt_tick'
|
|
return sql
|
|
|
|
# Name: sum
|
|
# Desc: given a run, a stat and an array of samples, total the samples
|
|
def sum(self, *args, **kwargs):
|
|
return self.query('sum', *args, **kwargs)
|
|
|
|
# Name: avg
|
|
# Desc: given a run, a stat and an array of samples, average the samples
|
|
def avg(self, stat, ticks):
|
|
return self.query('avg', *args, **kwargs)
|
|
|
|
# Name: stdev
|
|
# Desc: given a run, a stat and an array of samples, get the standard
|
|
# deviation
|
|
def stdev(self, stat, ticks):
|
|
return self.query('stddev', *args, **kwargs)
|
|
|
|
def __setattr__(self, attr, value):
|
|
super(Database, self).__setattr__(attr, value)
|
|
if attr != 'method':
|
|
return
|
|
|
|
if value == 'sum':
|
|
self._method = self.sum
|
|
elif value == 'avg':
|
|
self._method = self.avg
|
|
elif value == 'stdev':
|
|
self._method = self.stdev
|
|
else:
|
|
raise AttributeError, "can only set get to: sum | avg | stdev"
|
|
|
|
def data(self, stat, ticks=None):
|
|
if ticks is None:
|
|
ticks = self.ticks
|
|
sql = self._method(self, stat, ticks)
|
|
self.query(sql)
|
|
|
|
runs = {}
|
|
xmax = 0
|
|
ymax = 0
|
|
for x in self.cursor.fetchall():
|
|
data = Data(x)
|
|
if not runs.has_key(data.run):
|
|
runs[data.run] = {}
|
|
if not runs[data.run].has_key(data.x):
|
|
runs[data.run][data.x] = {}
|
|
|
|
xmax = max(xmax, data.x)
|
|
ymax = max(ymax, data.y)
|
|
runs[data.run][data.x][data.y] = data.data
|
|
|
|
results = Result(xmax + 1, ymax + 1)
|
|
for run,data in runs.iteritems():
|
|
result = results[run]
|
|
for x,ydata in data.iteritems():
|
|
for y,data in ydata.iteritems():
|
|
result[x][y] = data
|
|
return results
|
|
|
|
def __getitem__(self, key):
|
|
return self.stattop[key]
|