11758Ssaidi@eecs.umich.edu# Copyright (c) 2003-2004 The Regents of The University of Michigan
21758Ssaidi@eecs.umich.edu# All rights reserved.
31758Ssaidi@eecs.umich.edu#
41758Ssaidi@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
51758Ssaidi@eecs.umich.edu# modification, are permitted provided that the following conditions are
61758Ssaidi@eecs.umich.edu# met: redistributions of source code must retain the above copyright
71758Ssaidi@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
81758Ssaidi@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
91758Ssaidi@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
101758Ssaidi@eecs.umich.edu# documentation and/or other materials provided with the distribution;
111758Ssaidi@eecs.umich.edu# neither the name of the copyright holders nor the names of its
121758Ssaidi@eecs.umich.edu# contributors may be used to endorse or promote products derived from
131758Ssaidi@eecs.umich.edu# this software without specific prior written permission.
141758Ssaidi@eecs.umich.edu#
151758Ssaidi@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161758Ssaidi@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171758Ssaidi@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
181758Ssaidi@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
191758Ssaidi@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
201758Ssaidi@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
211758Ssaidi@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
221758Ssaidi@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
231758Ssaidi@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
241758Ssaidi@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
251758Ssaidi@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262665Ssaidi@eecs.umich.edu#
272665Ssaidi@eecs.umich.edu# Authors: Nathan Binkert
281758Ssaidi@eecs.umich.edu
291049Sbinkertn@umich.eduimport MySQLdb, re, string
301049Sbinkertn@umich.edu
311049Sbinkertn@umich.edudef statcmp(a, b):
321049Sbinkertn@umich.edu    v1 = a.split('.')
331049Sbinkertn@umich.edu    v2 = b.split('.')
341049Sbinkertn@umich.edu
351049Sbinkertn@umich.edu    last = min(len(v1), len(v2)) - 1
361049Sbinkertn@umich.edu    for i,j in zip(v1[0:last], v2[0:last]):
371049Sbinkertn@umich.edu        if i != j:
381049Sbinkertn@umich.edu            return cmp(i, j)
391049Sbinkertn@umich.edu
401049Sbinkertn@umich.edu    # Special compare for last element.
411049Sbinkertn@umich.edu    if len(v1) == len(v2):
421049Sbinkertn@umich.edu        return cmp(v1[last], v2[last])
431049Sbinkertn@umich.edu    else:
441049Sbinkertn@umich.edu        return cmp(len(v1), len(v2))
451049Sbinkertn@umich.edu
461049Sbinkertn@umich.educlass RunData:
471049Sbinkertn@umich.edu    def __init__(self, row):
481049Sbinkertn@umich.edu        self.run = int(row[0])
491049Sbinkertn@umich.edu        self.name = row[1]
501049Sbinkertn@umich.edu        self.user = row[2]
511049Sbinkertn@umich.edu        self.project = row[3]
521049Sbinkertn@umich.edu
531049Sbinkertn@umich.educlass SubData:
541049Sbinkertn@umich.edu    def __init__(self, row):
551049Sbinkertn@umich.edu        self.stat = int(row[0])
561049Sbinkertn@umich.edu        self.x = int(row[1])
571049Sbinkertn@umich.edu        self.y = int(row[2])
581049Sbinkertn@umich.edu        self.name = row[3]
591049Sbinkertn@umich.edu        self.descr = row[4]
601049Sbinkertn@umich.edu
611049Sbinkertn@umich.educlass Data:
621049Sbinkertn@umich.edu    def __init__(self, row):
631049Sbinkertn@umich.edu        if len(row) != 5:
641049Sbinkertn@umich.edu            raise 'stat db error'
651049Sbinkertn@umich.edu        self.stat = int(row[0])
661049Sbinkertn@umich.edu        self.run = int(row[1])
671049Sbinkertn@umich.edu        self.x = int(row[2])
681049Sbinkertn@umich.edu        self.y = int(row[3])
691049Sbinkertn@umich.edu        self.data = float(row[4])
701049Sbinkertn@umich.edu
711049Sbinkertn@umich.edu    def __repr__(self):
721049Sbinkertn@umich.edu        return '''Data(['%d', '%d', '%d', '%d', '%f'])''' % ( self.stat,
731049Sbinkertn@umich.edu            self.run, self.x, self.y, self.data)
741049Sbinkertn@umich.edu
751049Sbinkertn@umich.educlass StatData(object):
761049Sbinkertn@umich.edu    def __init__(self, row):
771049Sbinkertn@umich.edu        self.stat = int(row[0])
781049Sbinkertn@umich.edu        self.name = row[1]
791049Sbinkertn@umich.edu        self.desc = row[2]
801049Sbinkertn@umich.edu        self.type = row[3]
811049Sbinkertn@umich.edu        self.prereq = int(row[5])
821049Sbinkertn@umich.edu        self.precision = int(row[6])
831049Sbinkertn@umich.edu
841049Sbinkertn@umich.edu        import flags
851049Sbinkertn@umich.edu        self.flags = 0
861049Sbinkertn@umich.edu        if int(row[4]): self.flags |= flags.printable
871049Sbinkertn@umich.edu        if int(row[7]): self.flags |= flags.nozero
881049Sbinkertn@umich.edu        if int(row[8]): self.flags |= flags.nonan
891049Sbinkertn@umich.edu        if int(row[9]): self.flags |= flags.total
901049Sbinkertn@umich.edu        if int(row[10]): self.flags |= flags.pdf
911049Sbinkertn@umich.edu        if int(row[11]): self.flags |= flags.cdf
921049Sbinkertn@umich.edu
931049Sbinkertn@umich.edu        if self.type == 'DIST' or self.type == 'VECTORDIST':
941049Sbinkertn@umich.edu            self.min = float(row[12])
951049Sbinkertn@umich.edu            self.max = float(row[13])
961049Sbinkertn@umich.edu            self.bktsize = float(row[14])
971049Sbinkertn@umich.edu            self.size = int(row[15])
981049Sbinkertn@umich.edu
991049Sbinkertn@umich.edu        if self.type == 'FORMULA':
1001049Sbinkertn@umich.edu            self.formula = self.db.allFormulas[self.stat]
1011049Sbinkertn@umich.edu
1021049Sbinkertn@umich.educlass Node(object):
1031049Sbinkertn@umich.edu    def __init__(self, name):
1041049Sbinkertn@umich.edu        self.name = name
1051049Sbinkertn@umich.edu    def __str__(self):
1061881Sbinkertn@umich.edu        return self.name
1071049Sbinkertn@umich.edu
1081929Sbinkertn@umich.educlass Result(object):
1091929Sbinkertn@umich.edu    def __init__(self, x, y):
1101929Sbinkertn@umich.edu        self.data = {}
1111929Sbinkertn@umich.edu        self.x = x
1121929Sbinkertn@umich.edu        self.y = y
1131929Sbinkertn@umich.edu
1141929Sbinkertn@umich.edu    def __contains__(self, run):
1151929Sbinkertn@umich.edu        return run in self.data
1161929Sbinkertn@umich.edu
1171929Sbinkertn@umich.edu    def __getitem__(self, run):
1181929Sbinkertn@umich.edu        if run not in self.data:
1191929Sbinkertn@umich.edu            self.data[run] = [ [ 0.0 ] * self.y for i in xrange(self.x) ]
1201929Sbinkertn@umich.edu        return self.data[run]
1211929Sbinkertn@umich.edu
1221049Sbinkertn@umich.educlass Database(object):
1231049Sbinkertn@umich.edu    def __init__(self):
1241049Sbinkertn@umich.edu        self.host = 'zizzer.pool'
1251049Sbinkertn@umich.edu        self.user = ''
1261049Sbinkertn@umich.edu        self.passwd = ''
1271049Sbinkertn@umich.edu        self.db = 'm5stats'
1281049Sbinkertn@umich.edu        self.cursor = None
1291049Sbinkertn@umich.edu
1301049Sbinkertn@umich.edu        self.allStats = []
1311049Sbinkertn@umich.edu        self.allStatIds = {}
1321049Sbinkertn@umich.edu        self.allStatNames = {}
1331049Sbinkertn@umich.edu
1341049Sbinkertn@umich.edu        self.allSubData = {}
1351049Sbinkertn@umich.edu
1361049Sbinkertn@umich.edu        self.allRuns = []
1371049Sbinkertn@umich.edu        self.allRunIds = {}
1381049Sbinkertn@umich.edu        self.allRunNames = {}
1391049Sbinkertn@umich.edu
1401049Sbinkertn@umich.edu        self.allFormulas = {}
1411049Sbinkertn@umich.edu
1421049Sbinkertn@umich.edu        self.stattop = {}
1431049Sbinkertn@umich.edu        self.statdict = {}
1441049Sbinkertn@umich.edu        self.statlist = []
1451049Sbinkertn@umich.edu
1461049Sbinkertn@umich.edu        self.mode = 'sum';
1471049Sbinkertn@umich.edu        self.runs = None
1481049Sbinkertn@umich.edu        self.ticks = None
1491929Sbinkertn@umich.edu        self.method = 'sum'
1501929Sbinkertn@umich.edu        self._method = type(self).sum
1511929Sbinkertn@umich.edu
1522014Sbinkertn@umich.edu    def get(self, job, stat, system=None):
1532014Sbinkertn@umich.edu        run = self.allRunNames.get(str(job), None)
1541929Sbinkertn@umich.edu        if run is None:
1551929Sbinkertn@umich.edu            return None
1561929Sbinkertn@umich.edu
1572014Sbinkertn@umich.edu        from info import ProxyError, scalar, vector, value, values, total, len
1582183Sbinkertn@umich.edu        if system is None and hasattr(job, 'system'):
1592014Sbinkertn@umich.edu            system = job.system
1602014Sbinkertn@umich.edu
1612014Sbinkertn@umich.edu        if system is not None:
1622014Sbinkertn@umich.edu            stat.system = self[system]
1632014Sbinkertn@umich.edu        try:
1642014Sbinkertn@umich.edu            if scalar(stat):
1652014Sbinkertn@umich.edu                return value(stat, run.run)
1662014Sbinkertn@umich.edu            if vector(stat):
1672014Sbinkertn@umich.edu                return values(stat, run.run)
1682014Sbinkertn@umich.edu        except ProxyError:
1692014Sbinkertn@umich.edu            return None
1701929Sbinkertn@umich.edu
1711929Sbinkertn@umich.edu        return None
1721049Sbinkertn@umich.edu
1731049Sbinkertn@umich.edu    def query(self, sql):
1741049Sbinkertn@umich.edu        self.cursor.execute(sql)
1751049Sbinkertn@umich.edu
1761049Sbinkertn@umich.edu    def update_dict(self, dict):
1771049Sbinkertn@umich.edu        dict.update(self.stattop)
1781049Sbinkertn@umich.edu
1791049Sbinkertn@umich.edu    def append(self, stat):
1801049Sbinkertn@umich.edu        statname = re.sub(':', '__', stat.name)
1811049Sbinkertn@umich.edu        path = string.split(statname, '.')
1821049Sbinkertn@umich.edu        pathtop = path[0]
1831049Sbinkertn@umich.edu        fullname = ''
1841049Sbinkertn@umich.edu
1851049Sbinkertn@umich.edu        x = self
1861049Sbinkertn@umich.edu        while len(path) > 1:
1871049Sbinkertn@umich.edu            name = path.pop(0)
1881049Sbinkertn@umich.edu            if not x.__dict__.has_key(name):
1891049Sbinkertn@umich.edu                x.__dict__[name] = Node(fullname + name)
1901049Sbinkertn@umich.edu            x = x.__dict__[name]
1911049Sbinkertn@umich.edu            fullname = '%s%s.' % (fullname, name)
1921049Sbinkertn@umich.edu
1931049Sbinkertn@umich.edu        name = path.pop(0)
1941049Sbinkertn@umich.edu        x.__dict__[name] = stat
1951049Sbinkertn@umich.edu
1961049Sbinkertn@umich.edu        self.stattop[pathtop] = self.__dict__[pathtop]
1971049Sbinkertn@umich.edu        self.statdict[statname] = stat
1981049Sbinkertn@umich.edu        self.statlist.append(statname)
1991049Sbinkertn@umich.edu
2001049Sbinkertn@umich.edu    def connect(self):
2011049Sbinkertn@umich.edu        # connect
2021049Sbinkertn@umich.edu        self.thedb = MySQLdb.connect(db=self.db,
2031049Sbinkertn@umich.edu                                     host=self.host,
2041049Sbinkertn@umich.edu                                     user=self.user,
2051049Sbinkertn@umich.edu                                     passwd=self.passwd)
2061049Sbinkertn@umich.edu
2071049Sbinkertn@umich.edu        # create a cursor
2081049Sbinkertn@umich.edu        self.cursor = self.thedb.cursor()
2091049Sbinkertn@umich.edu
2101049Sbinkertn@umich.edu        self.query('''select rn_id,rn_name,rn_sample,rn_user,rn_project
2111049Sbinkertn@umich.edu                   from runs''')
2121049Sbinkertn@umich.edu        for result in self.cursor.fetchall():
2131049Sbinkertn@umich.edu            run = RunData(result);
2141049Sbinkertn@umich.edu            self.allRuns.append(run)
2151049Sbinkertn@umich.edu            self.allRunIds[run.run] = run
2161049Sbinkertn@umich.edu            self.allRunNames[run.name] = run
2171049Sbinkertn@umich.edu
2181049Sbinkertn@umich.edu        self.query('select sd_stat,sd_x,sd_y,sd_name,sd_descr from subdata')
2191049Sbinkertn@umich.edu        for result in self.cursor.fetchall():
2201049Sbinkertn@umich.edu            subdata = SubData(result)
2211049Sbinkertn@umich.edu            if self.allSubData.has_key(subdata.stat):
2221049Sbinkertn@umich.edu                self.allSubData[subdata.stat].append(subdata)
2231049Sbinkertn@umich.edu            else:
2241049Sbinkertn@umich.edu                self.allSubData[subdata.stat] = [ subdata ]
2251049Sbinkertn@umich.edu
2261049Sbinkertn@umich.edu        self.query('select * from formulas')
2271049Sbinkertn@umich.edu        for id,formula in self.cursor.fetchall():
2281306Sbinkertn@umich.edu            self.allFormulas[int(id)] = formula.tostring()
2291049Sbinkertn@umich.edu
2301049Sbinkertn@umich.edu        StatData.db = self
2311049Sbinkertn@umich.edu        self.query('select * from stats')
2321049Sbinkertn@umich.edu        import info
2331049Sbinkertn@umich.edu        for result in self.cursor.fetchall():
2341929Sbinkertn@umich.edu            stat = info.NewStat(self, StatData(result))
2351049Sbinkertn@umich.edu            self.append(stat)
2361049Sbinkertn@umich.edu            self.allStats.append(stat)
2371049Sbinkertn@umich.edu            self.allStatIds[stat.stat] = stat
2381049Sbinkertn@umich.edu            self.allStatNames[stat.name] = stat
2391049Sbinkertn@umich.edu
2401049Sbinkertn@umich.edu    # Name: listruns
2411049Sbinkertn@umich.edu    # Desc: Prints all runs matching a given user, if no argument
2421049Sbinkertn@umich.edu    #       is given all runs are returned
2431049Sbinkertn@umich.edu    def listRuns(self, user=None):
2441049Sbinkertn@umich.edu        print '%-40s %-10s %-5s' % ('run name', 'user', 'id')
2451049Sbinkertn@umich.edu        print '-' * 62
2461049Sbinkertn@umich.edu        for run in self.allRuns:
2471049Sbinkertn@umich.edu            if user == None or user == run.user:
2481049Sbinkertn@umich.edu                print '%-40s %-10s %-10d' % (run.name, run.user, run.run)
2491049Sbinkertn@umich.edu
2501049Sbinkertn@umich.edu    # Name: listTicks
2511049Sbinkertn@umich.edu    # Desc: Prints all samples for a given run
2521309Ssaidi@eecs.umich.edu    def listTicks(self, runs=None):
2531049Sbinkertn@umich.edu        print "tick"
2541049Sbinkertn@umich.edu        print "----------------------------------------"
2551309Ssaidi@eecs.umich.edu        sql = 'select distinct dt_tick from data where dt_stat=1180 and ('
2561309Ssaidi@eecs.umich.edu        if runs != None:
2571309Ssaidi@eecs.umich.edu            first = True
2581309Ssaidi@eecs.umich.edu            for run in runs:
2591309Ssaidi@eecs.umich.edu               if first:
2601309Ssaidi@eecs.umich.edu            #       sql += ' where'
2611309Ssaidi@eecs.umich.edu                   first = False
2621309Ssaidi@eecs.umich.edu               else:
2631309Ssaidi@eecs.umich.edu                   sql += ' or'
2641309Ssaidi@eecs.umich.edu               sql += ' dt_run=%s' % run.run
2651309Ssaidi@eecs.umich.edu            sql += ')'
2661049Sbinkertn@umich.edu        self.query(sql)
2671049Sbinkertn@umich.edu        for r in self.cursor.fetchall():
2681049Sbinkertn@umich.edu            print r[0]
2691049Sbinkertn@umich.edu
2701309Ssaidi@eecs.umich.edu    # Name: retTicks
2711309Ssaidi@eecs.umich.edu    # Desc: Prints all samples for a given run
2721309Ssaidi@eecs.umich.edu    def retTicks(self, runs=None):
2731309Ssaidi@eecs.umich.edu        sql = 'select distinct dt_tick from data where dt_stat=1180 and ('
2741309Ssaidi@eecs.umich.edu        if runs != None:
2751309Ssaidi@eecs.umich.edu            first = True
2761309Ssaidi@eecs.umich.edu            for run in runs:
2771309Ssaidi@eecs.umich.edu               if first:
2781309Ssaidi@eecs.umich.edu                   first = False
2791309Ssaidi@eecs.umich.edu               else:
2801309Ssaidi@eecs.umich.edu                   sql += ' or'
2811309Ssaidi@eecs.umich.edu               sql += ' dt_run=%s' % run.run
2821309Ssaidi@eecs.umich.edu            sql += ')'
2831309Ssaidi@eecs.umich.edu        self.query(sql)
2841309Ssaidi@eecs.umich.edu        ret = []
2851309Ssaidi@eecs.umich.edu        for r in self.cursor.fetchall():
2861309Ssaidi@eecs.umich.edu            ret.append(r[0])
2871309Ssaidi@eecs.umich.edu        return ret
2881309Ssaidi@eecs.umich.edu
2891049Sbinkertn@umich.edu    # Name: liststats
2901049Sbinkertn@umich.edu    # Desc: Prints all statistics that appear in the database,
2911049Sbinkertn@umich.edu    #         the optional argument is a regular expression that can
2921049Sbinkertn@umich.edu    #         be used to prune the result set
2931049Sbinkertn@umich.edu    def listStats(self, regex=None):
2941049Sbinkertn@umich.edu        print '%-60s %-8s %-10s' % ('stat name', 'id', 'type')
2951049Sbinkertn@umich.edu        print '-' * 80
2961049Sbinkertn@umich.edu
2971049Sbinkertn@umich.edu        rx = None
2981049Sbinkertn@umich.edu        if regex != None:
2991049Sbinkertn@umich.edu            rx = re.compile(regex)
3001049Sbinkertn@umich.edu
3011049Sbinkertn@umich.edu        stats = [ stat.name for stat in self.allStats ]
3021049Sbinkertn@umich.edu        stats.sort(statcmp)
3031049Sbinkertn@umich.edu        for stat in stats:
3041049Sbinkertn@umich.edu            stat = self.allStatNames[stat]
3051049Sbinkertn@umich.edu            if rx == None or rx.match(stat.name):
3061049Sbinkertn@umich.edu                print '%-60s %-8s %-10s' % (stat.name, stat.stat, stat.type)
3071049Sbinkertn@umich.edu
3081049Sbinkertn@umich.edu    # Name: liststats
3091049Sbinkertn@umich.edu    # Desc: Prints all statistics that appear in the database,
3101049Sbinkertn@umich.edu    #         the optional argument is a regular expression that can
3111049Sbinkertn@umich.edu    #         be used to prune the result set
3121049Sbinkertn@umich.edu    def listFormulas(self, regex=None):
3131049Sbinkertn@umich.edu        print '%-60s %s' % ('formula name', 'formula')
3141049Sbinkertn@umich.edu        print '-' * 80
3151049Sbinkertn@umich.edu
3161049Sbinkertn@umich.edu        rx = None
3171049Sbinkertn@umich.edu        if regex != None:
3181049Sbinkertn@umich.edu            rx = re.compile(regex)
3191049Sbinkertn@umich.edu
3201049Sbinkertn@umich.edu        stats = [ stat.name for stat in self.allStats ]
3211049Sbinkertn@umich.edu        stats.sort(statcmp)
3221049Sbinkertn@umich.edu        for stat in stats:
3231049Sbinkertn@umich.edu            stat = self.allStatNames[stat]
3241049Sbinkertn@umich.edu            if stat.type == 'FORMULA' and (rx == None or rx.match(stat.name)):
3251049Sbinkertn@umich.edu                print '%-60s %s' % (stat.name, self.allFormulas[stat.stat])
3261049Sbinkertn@umich.edu
3271049Sbinkertn@umich.edu    def getStat(self, stats):
3281049Sbinkertn@umich.edu        if type(stats) is not list:
3291049Sbinkertn@umich.edu            stats = [ stats ]
3301049Sbinkertn@umich.edu
3311049Sbinkertn@umich.edu        ret = []
3321049Sbinkertn@umich.edu        for stat in stats:
3331049Sbinkertn@umich.edu            if type(stat) is int:
3341049Sbinkertn@umich.edu                ret.append(self.allStatIds[stat])
3351049Sbinkertn@umich.edu
3361049Sbinkertn@umich.edu            if type(stat) is str:
3371049Sbinkertn@umich.edu                rx = re.compile(stat)
3381049Sbinkertn@umich.edu                for stat in self.allStats:
3391049Sbinkertn@umich.edu                    if rx.match(stat.name):
3401049Sbinkertn@umich.edu                        ret.append(stat)
3411049Sbinkertn@umich.edu        return ret
3421049Sbinkertn@umich.edu
3431049Sbinkertn@umich.edu    #########################################
3441049Sbinkertn@umich.edu    # get the data
3451049Sbinkertn@umich.edu    #
3462343Sbinkertn@umich.edu    def query(self, op, stat, ticks, group=False):
3471049Sbinkertn@umich.edu        sql = 'select '
3481049Sbinkertn@umich.edu        sql += 'dt_stat as stat, '
3491049Sbinkertn@umich.edu        sql += 'dt_run as run, '
3501049Sbinkertn@umich.edu        sql += 'dt_x as x, '
3511049Sbinkertn@umich.edu        sql += 'dt_y as y, '
3521049Sbinkertn@umich.edu        if group:
3531049Sbinkertn@umich.edu            sql += 'dt_tick as tick, '
3541049Sbinkertn@umich.edu        sql += '%s(dt_data) as data ' % op
3551049Sbinkertn@umich.edu        sql += 'from data '
3561049Sbinkertn@umich.edu        sql += 'where '
3571049Sbinkertn@umich.edu
3581049Sbinkertn@umich.edu        if isinstance(stat, list):
3591049Sbinkertn@umich.edu            val = ' or '.join([ 'dt_stat=%d' % s.stat for s in stat ])
3601049Sbinkertn@umich.edu            sql += ' (%s)' % val
3611049Sbinkertn@umich.edu        else:
3621049Sbinkertn@umich.edu            sql += ' dt_stat=%d' % stat.stat
3631049Sbinkertn@umich.edu
3641049Sbinkertn@umich.edu        if self.runs != None and len(self.runs):
3651049Sbinkertn@umich.edu            val = ' or '.join([ 'dt_run=%d' % r for r in self.runs ])
3661049Sbinkertn@umich.edu            sql += ' and (%s)' % val
3671049Sbinkertn@umich.edu
3681049Sbinkertn@umich.edu        if ticks != None and len(ticks):
3691049Sbinkertn@umich.edu            val = ' or '.join([ 'dt_tick=%d' % s for s in ticks ])
3701049Sbinkertn@umich.edu            sql += ' and (%s)' % val
3711049Sbinkertn@umich.edu
3721049Sbinkertn@umich.edu        sql += ' group by dt_stat,dt_run,dt_x,dt_y'
3731049Sbinkertn@umich.edu        if group:
3741049Sbinkertn@umich.edu            sql += ',dt_tick'
3751049Sbinkertn@umich.edu        return sql
3761049Sbinkertn@umich.edu
3771049Sbinkertn@umich.edu    # Name: sum
3782343Sbinkertn@umich.edu    # Desc: given a run, a stat and an array of samples, total the samples
3792343Sbinkertn@umich.edu    def sum(self, *args, **kwargs):
3802343Sbinkertn@umich.edu        return self.query('sum', *args, **kwargs)
3811049Sbinkertn@umich.edu
3821049Sbinkertn@umich.edu    # Name: avg
3832343Sbinkertn@umich.edu    # Desc: given a run, a stat and an array of samples, average the samples
3842343Sbinkertn@umich.edu    def avg(self, stat, ticks):
3852343Sbinkertn@umich.edu        return self.query('avg', *args, **kwargs)
3861049Sbinkertn@umich.edu
3871049Sbinkertn@umich.edu    # Name: stdev
3882343Sbinkertn@umich.edu    # Desc: given a run, a stat and an array of samples, get the standard
3892343Sbinkertn@umich.edu    #       deviation
3902343Sbinkertn@umich.edu    def stdev(self, stat, ticks):
3912343Sbinkertn@umich.edu        return self.query('stddev', *args, **kwargs)
3921049Sbinkertn@umich.edu
3931049Sbinkertn@umich.edu    def __setattr__(self, attr, value):
3941929Sbinkertn@umich.edu        super(Database, self).__setattr__(attr, value)
3951929Sbinkertn@umich.edu        if attr != 'method':
3961049Sbinkertn@umich.edu            return
3971049Sbinkertn@umich.edu
3981049Sbinkertn@umich.edu        if value == 'sum':
3991929Sbinkertn@umich.edu            self._method = self.sum
4001049Sbinkertn@umich.edu        elif value == 'avg':
4011929Sbinkertn@umich.edu            self._method = self.avg
4021049Sbinkertn@umich.edu        elif value == 'stdev':
4031929Sbinkertn@umich.edu            self._method = self.stdev
4041049Sbinkertn@umich.edu        else:
4051049Sbinkertn@umich.edu            raise AttributeError, "can only set get to: sum | avg | stdev"
4061049Sbinkertn@umich.edu
4072343Sbinkertn@umich.edu    def data(self, stat, ticks=None):
4081049Sbinkertn@umich.edu        if ticks is None:
4091049Sbinkertn@umich.edu            ticks = self.ticks
4102343Sbinkertn@umich.edu        sql = self._method(self, stat, ticks)
4111049Sbinkertn@umich.edu        self.query(sql)
4121049Sbinkertn@umich.edu
4131049Sbinkertn@umich.edu        runs = {}
4141929Sbinkertn@umich.edu        xmax = 0
4151929Sbinkertn@umich.edu        ymax = 0
4161049Sbinkertn@umich.edu        for x in self.cursor.fetchall():
4171049Sbinkertn@umich.edu            data = Data(x)
4181049Sbinkertn@umich.edu            if not runs.has_key(data.run):
4191049Sbinkertn@umich.edu                runs[data.run] = {}
4201049Sbinkertn@umich.edu            if not runs[data.run].has_key(data.x):
4211049Sbinkertn@umich.edu                runs[data.run][data.x] = {}
4221049Sbinkertn@umich.edu
4231929Sbinkertn@umich.edu            xmax = max(xmax, data.x)
4241929Sbinkertn@umich.edu            ymax = max(ymax, data.y)
4251049Sbinkertn@umich.edu            runs[data.run][data.x][data.y] = data.data
4261929Sbinkertn@umich.edu
4271929Sbinkertn@umich.edu        results = Result(xmax + 1, ymax + 1)
4281929Sbinkertn@umich.edu        for run,data in runs.iteritems():
4291929Sbinkertn@umich.edu            result = results[run]
4301929Sbinkertn@umich.edu            for x,ydata in data.iteritems():
4311929Sbinkertn@umich.edu                for y,data in ydata.iteritems():
4321929Sbinkertn@umich.edu                    result[x][y] = data
4331929Sbinkertn@umich.edu        return results
4341881Sbinkertn@umich.edu
4351881Sbinkertn@umich.edu    def __getitem__(self, key):
4361881Sbinkertn@umich.edu        return self.stattop[key]
437