stats.py revision 1957
1451SN/A#!/usr/bin/env python
25795Ssaidi@eecs.umich.edu
3451SN/A# Copyright (c) 2003-2004 The Regents of The University of Michigan
4451SN/A# All rights reserved.
5451SN/A#
6451SN/A# Redistribution and use in source and binary forms, with or without
7451SN/A# modification, are permitted provided that the following conditions are
8451SN/A# met: redistributions of source code must retain the above copyright
9451SN/A# notice, this list of conditions and the following disclaimer;
10451SN/A# redistributions in binary form must reproduce the above copyright
11451SN/A# notice, this list of conditions and the following disclaimer in the
12451SN/A# documentation and/or other materials provided with the distribution;
13451SN/A# neither the name of the copyright holders nor the names of its
14451SN/A# contributors may be used to endorse or promote products derived from
15451SN/A# this software without specific prior written permission.
16451SN/A#
17451SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18451SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19451SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20451SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21451SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22451SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23451SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24451SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25451SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26451SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272665Ssaidi@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu
29451SN/Afrom __future__ import division
30451SN/Aimport re, sys, math
31451SN/A
32451SN/Adef usage():
336215Snate@binkert.org    print '''\
346215Snate@binkert.orgUsage: %s [-E] [-F] [ -G <get> ] [-d <db> ] [-g <graphdir> ] [-h <host>] [-p]
352093SN/A       [-s <system>] [-r <runs> ] [-T <samples>] [-u <username>]
365795Ssaidi@eecs.umich.edu       <command> [command args]
372093SN/A
383113Sgblack@eecs.umich.edu       commands    extra parameters   description
392423SN/A       ----------- ------------------ ---------------------------------------
405795Ssaidi@eecs.umich.edu       bins        [regex]            List bins (only matching regex)
415795Ssaidi@eecs.umich.edu       formula     <formula>          Evaluated formula specified
425795Ssaidi@eecs.umich.edu       formulas    [regex]            List formulas (only matching regex)
432093SN/A       runs        none               List all runs in database
442093SN/A       samples     none               List samples present in database
452093SN/A       stability   <pairnum> <stats>  Calculated statistical info about stats
462093SN/A       stat        <regex>            Show stat data (only matching regex)
472093SN/A       stats       [regex]            List all stats (only matching regex)
483113Sgblack@eecs.umich.edu
493113Sgblack@eecs.umich.edu       database    <command>          Where command is drop, init, or clean
502093SN/A
512093SN/A''' % sys.argv[0]
522093SN/A    sys.exit(1)
532093SN/A
542093SN/Adef getopts(list, flags):
553122Sgblack@eecs.umich.edu    import getopt
562093SN/A    try:
572093SN/A        opts, args = getopt.getopt(list, flags)
586684Stjones1@inf.ed.ac.uk    except getopt.GetoptError:
592093SN/A        usage()
603122Sgblack@eecs.umich.edu
612093SN/A    return opts, args
622093SN/A
632093SN/Aclass CommandException(Exception):
643113Sgblack@eecs.umich.edu    pass
653113Sgblack@eecs.umich.edu
663113Sgblack@eecs.umich.edudef commands(options, command, args):
675543Ssaidi@eecs.umich.edu    if command == 'database':
685543Ssaidi@eecs.umich.edu        if len(args) == 0: raise CommandException
695543Ssaidi@eecs.umich.edu
705543Ssaidi@eecs.umich.edu        import dbinit
715543Ssaidi@eecs.umich.edu        mydb = dbinit.MyDB(options)
725543Ssaidi@eecs.umich.edu
735543Ssaidi@eecs.umich.edu        if args[0] == 'drop':
745543Ssaidi@eecs.umich.edu            if len(args) > 2: raise CommandException
755543Ssaidi@eecs.umich.edu            mydb.admin()
765543Ssaidi@eecs.umich.edu            mydb.drop()
775543Ssaidi@eecs.umich.edu            if len(args) == 2 and args[1] == 'init':
785543Ssaidi@eecs.umich.edu                mydb.create()
795543Ssaidi@eecs.umich.edu                mydb.connect()
805543Ssaidi@eecs.umich.edu                mydb.populate()
815543Ssaidi@eecs.umich.edu            mydb.close()
825543Ssaidi@eecs.umich.edu            return
833113Sgblack@eecs.umich.edu
842093SN/A        if args[0] == 'init':
852093SN/A            if len(args) > 1: raise CommandException
863113Sgblack@eecs.umich.edu            mydb.admin()
875543Ssaidi@eecs.umich.edu            mydb.create()
885543Ssaidi@eecs.umich.edu            mydb.connect()
895543Ssaidi@eecs.umich.edu            mydb.populate()
905543Ssaidi@eecs.umich.edu            mydb.close()
915543Ssaidi@eecs.umich.edu            return
922093SN/A
935543Ssaidi@eecs.umich.edu        if args[0] == 'clean':
945543Ssaidi@eecs.umich.edu            if len(args) > 1: raise CommandException
955543Ssaidi@eecs.umich.edu            mydb.connect()
965543Ssaidi@eecs.umich.edu            mydb.clean()
975543Ssaidi@eecs.umich.edu            return
985543Ssaidi@eecs.umich.edu
992093SN/A        raise CommandException
1005543Ssaidi@eecs.umich.edu
1015543Ssaidi@eecs.umich.edu    import db, info
1025543Ssaidi@eecs.umich.edu    info.source = db.Database()
1035543Ssaidi@eecs.umich.edu    info.source.host = options.host
1045543Ssaidi@eecs.umich.edu    info.source.db = options.db
1055543Ssaidi@eecs.umich.edu    info.source.passwd = options.passwd
1065543Ssaidi@eecs.umich.edu    info.source.user = options.user
1073113Sgblack@eecs.umich.edu    info.source.connect()
1082093SN/A    #info.source.update_dict(globals())
1092093SN/A
1102093SN/A    if type(options.get) is str:
1112093SN/A        info.source.get = options.get
1122093SN/A
1132093SN/A    if options.runs is None:
1145543Ssaidi@eecs.umich.edu        runs = info.source.allRuns
1155543Ssaidi@eecs.umich.edu    else:
1165543Ssaidi@eecs.umich.edu        rx = re.compile(options.runs)
1175543Ssaidi@eecs.umich.edu        runs = []
1185543Ssaidi@eecs.umich.edu        for run in info.source.allRuns:
1192093SN/A            if rx.match(run.name):
1202093SN/A                runs.append(run)
1212093SN/A
1222093SN/A    info.display_run = runs[0].run
1235543Ssaidi@eecs.umich.edu
1245543Ssaidi@eecs.umich.edu    if command == 'runs':
1252093SN/A        user = None
1262093SN/A        opts, args = getopts(args, '-u')
1272093SN/A        if len(args):
1282093SN/A            raise CommandException
1295543Ssaidi@eecs.umich.edu        for o,a in opts:
1305543Ssaidi@eecs.umich.edu            if o == '-u':
1312093SN/A                user = a
1322093SN/A        info.source.listRuns(user)
1336683Stjones1@inf.ed.ac.uk        return
1346744SAli.Saidi@arm.com
1356683Stjones1@inf.ed.ac.uk    if command == 'stats':
1366683Stjones1@inf.ed.ac.uk        if len(args) == 0:
1376683Stjones1@inf.ed.ac.uk            info.source.listStats()
1386683Stjones1@inf.ed.ac.uk        elif len(args) == 1:
1396683Stjones1@inf.ed.ac.uk            info.source.listStats(args[0])
1406683Stjones1@inf.ed.ac.uk        else:
1416683Stjones1@inf.ed.ac.uk            raise CommandException
1426683Stjones1@inf.ed.ac.uk
1436683Stjones1@inf.ed.ac.uk        return
1442093SN/A
1452093SN/A    if command == 'bins':
1462093SN/A        if len(args) == 0:
1472093SN/A            info.source.listBins()
1482093SN/A        elif len(args) == 1:
1492093SN/A            info.source.listBins(args[0])
1502093SN/A        else:
1512093SN/A            raise CommandException
1522093SN/A
1535543Ssaidi@eecs.umich.edu        return
1545543Ssaidi@eecs.umich.edu
1555543Ssaidi@eecs.umich.edu    if command == 'formulas':
1565543Ssaidi@eecs.umich.edu        if len(args) == 0:
1575543Ssaidi@eecs.umich.edu            info.source.listFormulas()
1585543Ssaidi@eecs.umich.edu        elif len(args) == 1:
1595543Ssaidi@eecs.umich.edu            info.source.listFormulas(args[0])
1605543Ssaidi@eecs.umich.edu        else:
1615543Ssaidi@eecs.umich.edu            raise CommandException
1625543Ssaidi@eecs.umich.edu
1635543Ssaidi@eecs.umich.edu        return
1645543Ssaidi@eecs.umich.edu
1655543Ssaidi@eecs.umich.edu    if command == 'samples':
1665543Ssaidi@eecs.umich.edu        if len(args):
1675543Ssaidi@eecs.umich.edu            raise CommandException
1685543Ssaidi@eecs.umich.edu
1692093SN/A        info.source.listTicks(runs)
1702093SN/A        return
1715795Ssaidi@eecs.umich.edu
1725795Ssaidi@eecs.umich.edu    if command == 'stability':
1735795Ssaidi@eecs.umich.edu        if len(args) < 2:
1749112Smarc.orr@gmail.com            raise CommandException
1759112Smarc.orr@gmail.com
1769112Smarc.orr@gmail.com        try:
1779112Smarc.orr@gmail.com            merge = int(args[0])
1789112Smarc.orr@gmail.com        except ValueError:
1799112Smarc.orr@gmail.com            usage()
1802093SN/A        stats = info.source.getStat(args[1])
1812093SN/A        info.source.get = "sum"
182451SN/A
183        def disp(*args):
184            print "%-35s %12s %12s %4s %5s %5s %5s %10s" % args
185
186        # temporary variable containing a bunch of dashes
187        d = '-' * 100
188
189        #loop through all the stats selected
190        for stat in stats:
191            print "%s:" % stat.name
192            disp("run name", "average", "stdev", ">10%", ">1SDV", ">2SDV",
193                 "SAMP", "CV")
194            disp(d[:35], d[:12], d[:12], d[:4], d[:5], d[:5], d[:5], d[:10])
195
196            #loop through all the selected runs
197            for run in runs:
198                info.display_run = run.run;
199                runTicks = info.source.retTicks([ run ])
200                #throw away the first one, it's 0
201                runTicks.pop(0)
202                info.globalTicks = runTicks
203                avg = 0
204                stdev = 0
205                numoutsideavg  = 0
206                numoutside1std = 0
207                numoutside2std = 0
208                pairRunTicks = []
209                if float(stat) == 1e300*1e300:
210                    continue
211                for t in range(0, len(runTicks)-(merge-1), merge):
212                    tempPair = []
213                    for p in range(0,merge):
214                        tempPair.append(runTicks[t+p])
215                    pairRunTicks.append(tempPair)
216                #loop through all the various ticks for each run
217                for tick in pairRunTicks:
218                    info.globalTicks = tick
219                    avg += float(stat)
220                avg /= len(pairRunTicks)
221                for tick in pairRunTicks:
222                    info.globalTicks = tick
223                    val = float(stat)
224                    stdev += pow((val-avg),2)
225                stdev = math.sqrt(stdev / len(pairRunTicks))
226                for tick in pairRunTicks:
227                    info.globalTicks = tick
228                    val = float(stat)
229                    if (val < (avg * .9)) or (val > (avg * 1.1)):
230                        numoutsideavg += 1
231                    if (val < (avg - stdev)) or (val > (avg + stdev)):
232                        numoutside1std += 1
233                    if (val < (avg - (2*stdev))) or (val > (avg + (2*stdev))):
234                        numoutside2std += 1
235                if avg > 1000:
236                    disp(run.name, "%.1f" % avg, "%.1f" % stdev,
237                         "%d" % numoutsideavg, "%d" % numoutside1std,
238                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
239                         "%.3f" % (stdev/avg*100))
240                elif avg > 100:
241                    disp(run.name, "%.1f" % avg, "%.1f" % stdev,
242                         "%d" % numoutsideavg, "%d" % numoutside1std,
243                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
244                         "%.5f" % (stdev/avg*100))
245                else:
246                    disp(run.name, "%.5f" % avg, "%.5f" % stdev,
247                         "%d" % numoutsideavg, "%d" % numoutside1std,
248                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
249                         "%.7f" % (stdev/avg*100))
250        return
251
252    if command == 'all':
253        if len(args):
254            raise CommandException
255
256        all = [ 'bps', 'rxbps', 'txbps', 'bpt',
257                'misses', 'mpkb',
258                'ipkb',
259                'pps', 'bpp', 'txbpp', 'rxbpp',
260                'rtp', 'rtb' ]
261        for command in all:
262            commands(options, command, args)
263
264    if options.ticks:
265        if not options.graph:
266            print 'only displaying sample %s' % options.ticks
267        info.globalTicks = [ int(x) for x in options.ticks.split() ]
268
269    from output import StatOutput
270
271    def display():
272        if options.graph:
273            output.graph(options.graphdir)
274        else:
275            output.display(options.binned, options.printmode)
276
277
278    if command == 'stat' or command == 'formula':
279        if len(args) != 1:
280            raise CommandException
281
282        if command == 'stat':
283            stats = info.source.getStat(args[0])
284        if command == 'formula':
285            stats = eval(args[0])
286
287        for stat in stats:
288            output = StatOutput(stat.name, options.jobfile)
289            output.stat = stat
290            output.label = stat.name
291            display()
292
293        return
294
295    if len(args):
296        raise CommandException
297
298    system = info.source.__dict__[options.system]
299
300    from proxy import ProxyGroup
301    sim_ticks = info.source['sim_ticks']
302    sim_seconds = info.source['sim_seconds']
303    proxy = ProxyGroup(system = info.source[options.system])
304    system = proxy.system
305
306    etherdev = system.tsunami.etherdev0
307    bytes = etherdev.rxBytes + etherdev.txBytes
308    kbytes = bytes / 1024
309    packets = etherdev.rxPackets + etherdev.txPackets
310    bps = etherdev.rxBandwidth + etherdev.txBandwidth
311
312    output = StatOutput(command, options.jobfile)
313
314    if command == 'usertime':
315        import copy
316        user = copy.copy(system.full0.numCycles)
317        user.bins = 'user'
318
319        output.stat = user / system.full0.numCycles
320        output.label = 'User Fraction'
321
322        display()
323        return
324
325    if command == 'ticks':
326        output.stat = system.full0.numCycles
327        output.binstats = [ system.full0.numCycles ]
328
329        display()
330        return
331
332    if command == 'bytes':
333        output.stat = bytes
334        display()
335        return
336
337    if command == 'packets':
338        output.stat = packets
339        display()
340        return
341
342    if command == 'ppt' or command == 'tpp':
343        output.stat = packets / sim_ticks
344        output.invert = command == 'tpp'
345        display()
346        return
347
348    if command == 'pps':
349        output.stat = packets / sim_seconds
350        output.label = 'Packets/s'
351        display()
352        return
353
354    if command == 'bpt' or command == 'tpb':
355        output.stat = bytes / sim_ticks * 8
356        output.label = 'bps / Hz'
357        output.invert = command == 'tpb'
358        display()
359        return
360
361    if command == 'rxbps':
362        output.stat = etherdev.rxBandwidth / 1e9
363        output.label = 'Bandwidth (Gbps)'
364        display()
365        return
366
367    if command == 'txbps':
368        output.stat = etherdev.txBandwidth / 1e9
369        output.label = 'Bandwidth (Gbps)'
370        display()
371        return
372
373    if command == 'bps':
374        output.stat = bps / 1e9
375        output.label = 'Bandwidth (Gbps)'
376        display()
377        return
378
379    if command == 'bpp':
380        output.stat = bytes / packets
381        output.label = 'Bytes / Packet'
382        display()
383        return
384
385    if command == 'rxbpp':
386        output.stat = etherdev.rxBytes / etherdev.rxPackets
387        output.label = 'Receive Bytes / Packet'
388        display()
389        return
390
391    if command == 'txbpp':
392        output.stat = etherdev.txBytes / etherdev.txPackets
393        output.label = 'Transmit Bytes / Packet'
394        display()
395        return
396
397    if command == 'rtp':
398        output.stat = etherdev.rxPackets / etherdev.txPackets
399        output.label = 'rxPackets / txPackets'
400        display()
401        return
402
403    if command == 'rtb':
404        output.stat = etherdev.rxBytes / etherdev.txBytes
405        output.label = 'rxBytes / txBytes'
406        display()
407        return
408
409    misses = system.l2.overall_mshr_misses
410
411    if command == 'misses':
412        output.stat = misses
413        output.label = 'Overall MSHR Misses'
414        display()
415        return
416
417    if command == 'mpkb':
418        output.stat = misses / (bytes / 1024)
419        output.binstats = [ misses ]
420        output.label = 'Misses / KB'
421        display()
422        return
423
424    if command == 'ipkb':
425        interrupts = system.full0.kern.faults[4]
426        output.stat = interrupts / kbytes
427        output.binstats = [ interrupts ]
428        output.label = 'Interrupts / KB'
429        display()
430        return
431
432    if command == 'execute':
433        output.stat = system.full0.ISSUE__count
434        display()
435        return
436
437    if command == 'commit':
438        output.stat = system.full0.COM__count
439        display()
440        return
441
442    if command == 'fetch':
443        output.stat = system.full0.FETCH__count
444        display()
445        return
446
447    raise CommandException
448
449
450class Options: pass
451
452if __name__ == '__main__':
453    import getpass
454    from jobfile import JobFile
455
456    options = Options()
457    options.host = None
458    options.db = None
459    options.passwd = ''
460    options.user = getpass.getuser()
461    options.runs = None
462    options.system = 'client'
463    options.get = None
464    options.binned = False
465    options.graph = False
466    options.ticks = False
467    options.printmode = 'G'
468    jobfilename = 'Test.py'
469    options.jobfile = None
470    options.all = False
471
472    opts, args = getopts(sys.argv[1:], '-BEFG:Jad:g:h:j:pr:s:u:T:')
473    for o,a in opts:
474        if o == '-B':
475            options.binned = True
476        if o == '-E':
477            options.printmode = 'E'
478        if o == '-F':
479            options.printmode = 'F'
480        if o == '-G':
481            options.get = a
482        if o == '-a':
483            options.all = True
484        if o == '-d':
485            options.db = a
486        if o == '-g':
487            options.graph = True;
488            options.graphdir = a
489        if o == '-h':
490            options.host = a
491        if o == '-J':
492            jobfilename = None
493        if o == '-j':
494            jobfilename = a
495        if o == '-p':
496            options.passwd = getpass.getpass()
497        if o == '-r':
498            options.runs = a
499        if o == '-u':
500            options.user = a
501        if o == '-s':
502            options.system = a
503        if o == '-T':
504            options.ticks = a
505
506    if jobfilename:
507        options.jobfile = JobFile(jobfilename)
508        if not options.host:
509            options.host = options.jobfile.dbhost
510        if not options.db:
511            options.db = options.jobfile.statdb
512
513    if not options.host:
514        sys.exit('Database server must be provided from a jobfile or -h')
515
516    if not options.db:
517        sys.exit('Database name must be provided from a jobfile or -d')
518
519    if len(args) == 0:
520        usage()
521
522    command = args[0]
523    args = args[1:]
524
525    try:
526        commands(options, command, args)
527    except CommandException:
528        usage()
529