stats.py revision 1929:fb189519cb06
19020Sgblack@eecs.umich.edu#!/usr/bin/env python
29020Sgblack@eecs.umich.edu
39020Sgblack@eecs.umich.edu# Copyright (c) 2003-2004 The Regents of The University of Michigan
49020Sgblack@eecs.umich.edu# All rights reserved.
59020Sgblack@eecs.umich.edu#
69020Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
79020Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
89020Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
99020Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
109020Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
119020Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
129020Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
139020Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
149020Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
159020Sgblack@eecs.umich.edu# this software without specific prior written permission.
169020Sgblack@eecs.umich.edu#
179020Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
189020Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
199020Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
209020Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
219020Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
229020Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
239020Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
249020Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
259020Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
269020Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
279020Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289020Sgblack@eecs.umich.edu
299020Sgblack@eecs.umich.edufrom __future__ import division
309020Sgblack@eecs.umich.eduimport re, sys, math
319020Sgblack@eecs.umich.edu
329020Sgblack@eecs.umich.edudef usage():
339020Sgblack@eecs.umich.edu    print '''\
349024Sgblack@eecs.umich.eduUsage: %s [-E] [-F] [ -G <get> ] [-d <db> ] [-g <graphdir> ] [-h <host>] [-p]
359023Sgblack@eecs.umich.edu       [-s <system>] [-r <runs> ] [-T <samples>] [-u <username>]
369022Sgblack@eecs.umich.edu       <command> [command args]
379024Sgblack@eecs.umich.edu
389023Sgblack@eecs.umich.edu       commands    extra parameters   description
399023Sgblack@eecs.umich.edu       ----------- ------------------ ---------------------------------------
409023Sgblack@eecs.umich.edu       bins        [regex]            List bins (only matching regex)
419020Sgblack@eecs.umich.edu       formula     <formula>          Evaluated formula specified
429020Sgblack@eecs.umich.edu       formulas    [regex]            List formulas (only matching regex)
439020Sgblack@eecs.umich.edu       runs        none               List all runs in database
449020Sgblack@eecs.umich.edu       samples     none               List samples present in database
459022Sgblack@eecs.umich.edu       stability   <pairnum> <stats>  Calculated statistical info about stats
469022Sgblack@eecs.umich.edu       stat        <regex>            Show stat data (only matching regex)
479022Sgblack@eecs.umich.edu       stats       [regex]            List all stats (only matching regex)
489023Sgblack@eecs.umich.edu
499023Sgblack@eecs.umich.edu       database    <command>          Where command is drop, init, or clean
509023Sgblack@eecs.umich.edu
519023Sgblack@eecs.umich.edu''' % sys.argv[0]
529375Sgblack@eecs.umich.edu    sys.exit(1)
539023Sgblack@eecs.umich.edu
549023Sgblack@eecs.umich.edudef getopts(list, flags):
559375Sgblack@eecs.umich.edu    import getopt
569023Sgblack@eecs.umich.edu    try:
579023Sgblack@eecs.umich.edu        opts, args = getopt.getopt(list, flags)
589023Sgblack@eecs.umich.edu    except getopt.GetoptError:
599023Sgblack@eecs.umich.edu        usage()
609023Sgblack@eecs.umich.edu
619023Sgblack@eecs.umich.edu    return opts, args
629023Sgblack@eecs.umich.edu
639023Sgblack@eecs.umich.educlass CommandException(Exception):
649023Sgblack@eecs.umich.edu    pass
659023Sgblack@eecs.umich.edu
669023Sgblack@eecs.umich.edudef commands(options, command, args):
679023Sgblack@eecs.umich.edu    if command == 'database':
689023Sgblack@eecs.umich.edu        if len(args) == 0: raise CommandException
699023Sgblack@eecs.umich.edu
709023Sgblack@eecs.umich.edu        import dbinit
719023Sgblack@eecs.umich.edu        mydb = dbinit.MyDB(options)
729023Sgblack@eecs.umich.edu
739023Sgblack@eecs.umich.edu        if args[0] == 'drop':
749023Sgblack@eecs.umich.edu            if len(args) > 2: raise CommandException
759023Sgblack@eecs.umich.edu            mydb.admin()
769023Sgblack@eecs.umich.edu            mydb.drop()
779023Sgblack@eecs.umich.edu            if len(args) == 2 and args[1] == 'init':
789023Sgblack@eecs.umich.edu                mydb.create()
799023Sgblack@eecs.umich.edu                mydb.connect()
809023Sgblack@eecs.umich.edu                mydb.populate()
819023Sgblack@eecs.umich.edu            mydb.close()
829023Sgblack@eecs.umich.edu            return
839023Sgblack@eecs.umich.edu
849023Sgblack@eecs.umich.edu        if args[0] == 'init':
859023Sgblack@eecs.umich.edu            if len(args) > 1: raise CommandException
869023Sgblack@eecs.umich.edu            mydb.admin()
879023Sgblack@eecs.umich.edu            mydb.create()
889023Sgblack@eecs.umich.edu            mydb.connect()
899023Sgblack@eecs.umich.edu            mydb.populate()
909375Sgblack@eecs.umich.edu            mydb.close()
919023Sgblack@eecs.umich.edu            return
929023Sgblack@eecs.umich.edu
939023Sgblack@eecs.umich.edu        if args[0] == 'clean':
949023Sgblack@eecs.umich.edu            if len(args) > 1: raise CommandException
959023Sgblack@eecs.umich.edu            mydb.connect()
969023Sgblack@eecs.umich.edu            mydb.clean()
979023Sgblack@eecs.umich.edu            return
989023Sgblack@eecs.umich.edu
999023Sgblack@eecs.umich.edu        raise CommandException
1009023Sgblack@eecs.umich.edu
1019023Sgblack@eecs.umich.edu    import db
1029023Sgblack@eecs.umich.edu    source = db.Database()
1039023Sgblack@eecs.umich.edu    source.host = options.host
1049023Sgblack@eecs.umich.edu    source.db = options.db
1059023Sgblack@eecs.umich.edu    source.passwd = options.passwd
1069023Sgblack@eecs.umich.edu    source.user = options.user
1079023Sgblack@eecs.umich.edu    source.connect()
1089023Sgblack@eecs.umich.edu    #source.update_dict(globals())
1099023Sgblack@eecs.umich.edu
1109375Sgblack@eecs.umich.edu    if type(options.method) is str:
1119375Sgblack@eecs.umich.edu        source.method = options.method
1129375Sgblack@eecs.umich.edu
1139375Sgblack@eecs.umich.edu    if options.runs is None:
1149375Sgblack@eecs.umich.edu        runs = source.allRuns
1159375Sgblack@eecs.umich.edu    else:
1169023Sgblack@eecs.umich.edu        rx = re.compile(options.runs)
1179022Sgblack@eecs.umich.edu        runs = []
1189024Sgblack@eecs.umich.edu        for run in source.allRuns:
1199022Sgblack@eecs.umich.edu            if rx.match(run.name):
1209022Sgblack@eecs.umich.edu                runs.append(run)
1219022Sgblack@eecs.umich.edu
1229022Sgblack@eecs.umich.edu    if command == 'runs':
1239022Sgblack@eecs.umich.edu        user = None
1249022Sgblack@eecs.umich.edu        opts, args = getopts(args, '-u')
1259022Sgblack@eecs.umich.edu        if len(args):
1269022Sgblack@eecs.umich.edu            raise CommandException
1279022Sgblack@eecs.umich.edu        for o,a in opts:
1289022Sgblack@eecs.umich.edu            if o == '-u':
1299022Sgblack@eecs.umich.edu                user = a
1309022Sgblack@eecs.umich.edu        source.listRuns(user)
1319023Sgblack@eecs.umich.edu        return
1329023Sgblack@eecs.umich.edu
1339023Sgblack@eecs.umich.edu    if command == 'stats':
1349023Sgblack@eecs.umich.edu        if len(args) == 0:
1359023Sgblack@eecs.umich.edu            source.listStats()
1369023Sgblack@eecs.umich.edu        elif len(args) == 1:
1379023Sgblack@eecs.umich.edu            source.listStats(args[0])
1389023Sgblack@eecs.umich.edu        else:
1399023Sgblack@eecs.umich.edu            raise CommandException
1409022Sgblack@eecs.umich.edu
1419020Sgblack@eecs.umich.edu        return
1429020Sgblack@eecs.umich.edu
1439020Sgblack@eecs.umich.edu    if command == 'bins':
1449020Sgblack@eecs.umich.edu        if len(args) == 0:
145            source.listBins()
146        elif len(args) == 1:
147            source.listBins(args[0])
148        else:
149            raise CommandException
150
151        return
152
153    if command == 'formulas':
154        if len(args) == 0:
155            source.listFormulas()
156        elif len(args) == 1:
157            source.listFormulas(args[0])
158        else:
159            raise CommandException
160
161        return
162
163    if command == 'samples':
164        if len(args):
165            raise CommandException
166
167        source.listTicks(runs)
168        return
169
170    if command == 'stability':
171        if len(args) < 2:
172            raise CommandException
173
174        try:
175            merge = int(args[0])
176        except ValueError:
177            usage()
178        stats = source.getStat(args[1])
179        source.method = 'sum'
180
181        def disp(*args):
182            print "%-20s %12s %12s %4s %5s %5s %5s %10s" % args
183
184        # temporary variable containing a bunch of dashes
185        d = '-' * 100
186
187        #loop through all the stats selected
188        for stat in stats:
189            print "%s:" % stat.name
190            disp("run name", "average", "stdev", ">10%", ">1SDV", ">2SDV",
191                 "SAMP", "CV")
192            disp(d[:20], d[:12], d[:12], d[:4], d[:5], d[:5], d[:5], d[:10])
193
194            #loop through all the selected runs
195            for run in runs:
196                runTicks = source.retTicks([ run ])
197                #throw away the first one, it's 0
198                runTicks.pop(0)
199                source.ticks = runTicks
200                avg = 0
201                stdev = 0
202                numoutsideavg  = 0
203                numoutside1std = 0
204                numoutside2std = 0
205                pairRunTicks = []
206                if value(stat, run.run) == 1e300*1e300:
207                    continue
208                for t in range(0, len(runTicks)-(merge-1), merge):
209                    tempPair = []
210                    for p in range(0,merge):
211                        tempPair.append(runTicks[t+p])
212                    pairRunTicks.append(tempPair)
213                #loop through all the various ticks for each run
214                for tick in pairRunTicks:
215                    source.ticks = tick
216                    avg += value(stat, run.run)
217                avg /= len(pairRunTicks)
218                for tick in pairRunTicks:
219                    source.ticks = tick
220                    val = value(stat, run.run)
221                    stdev += pow((val-avg),2)
222                stdev = math.sqrt(stdev / len(pairRunTicks))
223                for tick in pairRunTicks:
224                    source.ticks = tick
225                    val = value(stat, run.run)
226                    if (val < (avg * .9)) or (val > (avg * 1.1)):
227                        numoutsideavg += 1
228                    if (val < (avg - stdev)) or (val > (avg + stdev)):
229                        numoutside1std += 1
230                    if (val < (avg - (2*stdev))) or (val > (avg + (2*stdev))):
231                        numoutside2std += 1
232                if avg > 1000:
233                    disp(run.name, "%.1f" % avg, "%.1f" % stdev,
234                         "%d" % numoutsideavg, "%d" % numoutside1std,
235                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
236                         "%.3f" % (stdev/avg*100))
237                elif avg > 100:
238                    disp(run.name, "%.1f" % avg, "%.1f" % stdev,
239                         "%d" % numoutsideavg, "%d" % numoutside1std,
240                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
241                         "%.5f" % (stdev/avg*100))
242                else:
243                    disp(run.name, "%.5f" % avg, "%.5f" % stdev,
244                         "%d" % numoutsideavg, "%d" % numoutside1std,
245                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
246                         "%.7f" % (stdev/avg*100))
247        return
248
249    if command == 'all':
250        if len(args):
251            raise CommandException
252
253        all = [ 'bps', 'rxbps', 'txbps', 'bpt',
254                'misses', 'mpkb',
255                'ipkb',
256                'pps', 'bpp', 'txbpp', 'rxbpp',
257                'rtp', 'rtb' ]
258        for command in all:
259            commands(options, command, args)
260
261    if options.ticks:
262        if not options.graph:
263            print 'only displaying sample %s' % options.ticks
264        source.ticks = [ int(x) for x in options.ticks.split() ]
265
266    import output
267
268    def display():
269        if options.graph:
270            output.graph(options.graphdir)
271        else:
272            output.display(options.binned, options.printmode)
273
274
275    if command == 'stat' or command == 'formula':
276        if len(args) != 1:
277            raise CommandException
278
279        if command == 'stat':
280            stats = source.getStat(args[0])
281        if command == 'formula':
282            stats = eval(args[0])
283
284        for stat in stats:
285            output = output.StatOutput(stat.name, options.jobfile, source)
286            output.stat = stat
287            output.label = stat.name
288            display()
289
290        return
291
292    if len(args):
293        raise CommandException
294
295    system = source.__dict__[options.system]
296    from info import ProxyGroup
297    sim_ticks = source['sim_ticks']
298    sim_seconds = source['sim_seconds']
299    proxy = ProxyGroup(system = source[options.system])
300    system = proxy.system
301
302    etherdev = system.tsunami.etherdev0
303    bytes = etherdev.rxBytes + etherdev.txBytes
304    kbytes = bytes / 1024
305    packets = etherdev.rxPackets + etherdev.txPackets
306    bps = etherdev.rxBandwidth + etherdev.txBandwidth
307
308    output = output.StatOutput(command, options.jobfile, source)
309
310    if command == 'usertime':
311        import copy
312        user = copy.copy(system.full0.numCycles)
313        user.bins = 'user'
314
315        output.stat = user / system.full0.numCycles
316        output.label = 'User Fraction'
317
318        display()
319        return
320
321    if command == 'ticks':
322        output.stat = system.full0.numCycles
323        output.binstats = [ system.full0.numCycles ]
324
325        display()
326        return
327
328    if command == 'bytes':
329        output.stat = bytes
330        display()
331        return
332
333    if command == 'packets':
334        output.stat = packets
335        display()
336        return
337
338    if command == 'ppt' or command == 'tpp':
339        output.stat = packets / sim_ticks
340        output.invert = command == 'tpp'
341        display()
342        return
343
344    if command == 'pps':
345        output.stat = packets / sim_seconds
346        output.label = 'Packets/s'
347        display()
348        return
349
350    if command == 'bpt' or command == 'tpb':
351        output.stat = bytes / sim_ticks * 8
352        output.label = 'bps / Hz'
353        output.invert = command == 'tpb'
354        display()
355        return
356
357    if command == 'rxbps':
358        output.stat = etherdev.rxBandwidth / 1e9
359        output.label = 'Bandwidth (Gbps)'
360        display()
361        return
362
363    if command == 'txbps':
364        output.stat = etherdev.txBandwidth / 1e9
365        output.label = 'Bandwidth (Gbps)'
366        display()
367        return
368
369    if command == 'bps':
370        output.stat = bps / 1e9
371        output.label = 'Bandwidth (Gbps)'
372        display()
373        return
374
375    if command == 'bpp':
376        output.stat = bytes / packets
377        output.label = 'Bytes / Packet'
378        display()
379        return
380
381    if command == 'rxbpp':
382        output.stat = etherdev.rxBytes / etherdev.rxPackets
383        output.label = 'Receive Bytes / Packet'
384        display()
385        return
386
387    if command == 'txbpp':
388        output.stat = etherdev.txBytes / etherdev.txPackets
389        output.label = 'Transmit Bytes / Packet'
390        display()
391        return
392
393    if command == 'rtp':
394        output.stat = etherdev.rxPackets / etherdev.txPackets
395        output.label = 'rxPackets / txPackets'
396        display()
397        return
398
399    if command == 'rtb':
400        output.stat = etherdev.rxBytes / etherdev.txBytes
401        output.label = 'rxBytes / txBytes'
402        display()
403        return
404
405    misses = system.l2.overall_mshr_misses
406
407    if command == 'misses':
408        output.stat = misses
409        output.label = 'Overall MSHR Misses'
410        display()
411        return
412
413    if command == 'mpkb':
414        output.stat = misses / (bytes / 1024)
415        output.binstats = [ misses ]
416        output.label = 'Misses / KB'
417        display()
418        return
419
420    if command == 'ipkb':
421        interrupts = system.full0.kern.faults[4]
422        output.stat = interrupts / kbytes
423        output.binstats = [ interrupts ]
424        output.label = 'Interrupts / KB'
425        display()
426        return
427
428    if command == 'execute':
429        output.stat = system.full0.ISSUE__count
430        display()
431        return
432
433    if command == 'commit':
434        output.stat = system.full0.COM__count
435        display()
436        return
437
438    if command == 'fetch':
439        output.stat = system.full0.FETCH__count
440        display()
441        return
442
443    raise CommandException
444
445
446class Options: pass
447
448if __name__ == '__main__':
449    import getpass
450    from jobfile import JobFile
451
452    options = Options()
453    options.host = None
454    options.db = None
455    options.passwd = ''
456    options.user = getpass.getuser()
457    options.runs = None
458    options.system = 'client'
459    options.method = None
460    options.binned = False
461    options.graph = False
462    options.ticks = False
463    options.printmode = 'G'
464    jobfilename = 'Test.py'
465    options.jobfile = None
466    options.all = False
467
468    opts, args = getopts(sys.argv[1:], '-BEFJad:g:h:j:m:pr:s:u:T:')
469    for o,a in opts:
470        if o == '-B':
471            options.binned = True
472        if o == '-E':
473            options.printmode = 'E'
474        if o == '-F':
475            options.printmode = 'F'
476        if o == '-a':
477            options.all = True
478        if o == '-d':
479            options.db = a
480        if o == '-g':
481            options.graph = True;
482            options.graphdir = a
483        if o == '-h':
484            options.host = a
485        if o == '-J':
486            jobfilename = None
487        if o == '-j':
488            jobfilename = a
489        if o == '-m':
490            options.method = a
491        if o == '-p':
492            options.passwd = getpass.getpass()
493        if o == '-r':
494            options.runs = a
495        if o == '-u':
496            options.user = a
497        if o == '-s':
498            options.system = a
499        if o == '-T':
500            options.ticks = a
501
502    if jobfilename:
503        options.jobfile = JobFile(jobfilename)
504        if not options.host:
505            options.host = options.jobfile.dbhost
506        if not options.db:
507            options.db = options.jobfile.statdb
508
509    if not options.host:
510        sys.exit('Database server must be provided from a jobfile or -h')
511
512    if not options.db:
513        sys.exit('Database name must be provided from a jobfile or -d')
514
515    if len(args) == 0:
516        usage()
517
518    command = args[0]
519    args = args[1:]
520
521    try:
522        commands(options, command, args)
523    except CommandException:
524        usage()
525