stats.py revision 2716:b9114064d77a
1#!/usr/bin/env python
2
3# Copyright (c) 2003-2004 The Regents of The University of Michigan
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met: redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer;
10# redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution;
13# neither the name of the copyright holders nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29# Authors: Nathan Binkert
30
31from __future__ import division
32import re, sys, math
33
34def usage():
35    print '''\
36Usage: %s [-E] [-F] [ -G <get> ] [-d <db> ] [-g <graphdir> ] [-h <host>] [-p]
37       [-s <system>] [-r <runs> ] [-T <samples>] [-u <username>]
38       <command> [command args]
39
40       commands    extra parameters   description
41       ----------- ------------------ ---------------------------------------
42       formula     <formula>          Evaluated formula specified
43       formulas    [regex]            List formulas (only matching regex)
44       runs        none               List all runs in database
45       samples     none               List samples present in database
46       stability   <pairnum> <stats>  Calculated statistical info about stats
47       stat        <regex>            Show stat data (only matching regex)
48       stats       [regex]            List all stats (only matching regex)
49
50       database    <command>          Where command is drop, init, or clean
51
52''' % sys.argv[0]
53    sys.exit(1)
54
55def getopts(list, flags):
56    import getopt
57    try:
58        opts, args = getopt.getopt(list, flags)
59    except getopt.GetoptError:
60        usage()
61
62    return opts, args
63
64class CommandException(Exception):
65    pass
66
67def commands(options, command, args):
68    if command == 'database':
69        if len(args) == 0: raise CommandException
70
71        import dbinit
72        mydb = dbinit.MyDB(options)
73
74        if args[0] == 'drop':
75            if len(args) > 2: raise CommandException
76            mydb.admin()
77            mydb.drop()
78            if len(args) == 2 and args[1] == 'init':
79                mydb.create()
80                mydb.connect()
81                mydb.populate()
82            mydb.close()
83            return
84
85        if args[0] == 'init':
86            if len(args) > 1: raise CommandException
87            mydb.admin()
88            mydb.create()
89            mydb.connect()
90            mydb.populate()
91            mydb.close()
92            return
93
94        if args[0] == 'clean':
95            if len(args) > 1: raise CommandException
96            mydb.connect()
97            mydb.clean()
98            return
99
100        raise CommandException
101
102    import db
103    source = db.Database()
104    source.host = options.host
105    source.db = options.db
106    source.passwd = options.passwd
107    source.user = options.user
108    source.connect()
109    #source.update_dict(globals())
110
111    if type(options.method) is str:
112        source.method = options.method
113
114    if options.runs is None:
115        runs = source.allRuns
116    else:
117        rx = re.compile(options.runs)
118        runs = []
119        for run in source.allRuns:
120            if rx.match(run.name):
121                runs.append(run)
122
123    if command == 'runs':
124        user = None
125        opts, args = getopts(args, '-u')
126        if len(args):
127            raise CommandException
128        for o,a in opts:
129            if o == '-u':
130                user = a
131        source.listRuns(user)
132        return
133
134    if command == 'stats':
135        if len(args) == 0:
136            source.listStats()
137        elif len(args) == 1:
138            source.listStats(args[0])
139        else:
140            raise CommandException
141
142        return
143
144    if command == 'formulas':
145        if len(args) == 0:
146            source.listFormulas()
147        elif len(args) == 1:
148            source.listFormulas(args[0])
149        else:
150            raise CommandException
151
152        return
153
154    if command == 'samples':
155        if len(args):
156            raise CommandException
157
158        source.listTicks(runs)
159        return
160
161    if command == 'stability':
162        if len(args) < 2:
163            raise CommandException
164
165        try:
166            merge = int(args[0])
167        except ValueError:
168            usage()
169        stats = source.getStat(args[1])
170        source.method = 'sum'
171
172        def disp(*args):
173            print "%-35s %12s %12s %4s %5s %5s %5s %10s" % args
174
175        # temporary variable containing a bunch of dashes
176        d = '-' * 100
177
178        #loop through all the stats selected
179        for stat in stats:
180            print "%s:" % stat.name
181            disp("run name", "average", "stdev", ">10%", ">1SDV", ">2SDV",
182                 "SAMP", "CV")
183            disp(d[:35], d[:12], d[:12], d[:4], d[:5], d[:5], d[:5], d[:10])
184
185            #loop through all the selected runs
186            for run in runs:
187                runTicks = source.retTicks([ run ])
188                #throw away the first one, it's 0
189                runTicks.pop(0)
190                source.ticks = runTicks
191                avg = 0
192                stdev = 0
193                numoutsideavg  = 0
194                numoutside1std = 0
195                numoutside2std = 0
196                pairRunTicks = []
197                if value(stat, run.run) == 1e300*1e300:
198                    continue
199                for t in range(0, len(runTicks)-(merge-1), merge):
200                    tempPair = []
201                    for p in range(0,merge):
202                        tempPair.append(runTicks[t+p])
203                    pairRunTicks.append(tempPair)
204                #loop through all the various ticks for each run
205                for tick in pairRunTicks:
206                    source.ticks = tick
207                    avg += value(stat, run.run)
208                avg /= len(pairRunTicks)
209                for tick in pairRunTicks:
210                    source.ticks = tick
211                    val = value(stat, run.run)
212                    stdev += pow((val-avg),2)
213                stdev = math.sqrt(stdev / len(pairRunTicks))
214                for tick in pairRunTicks:
215                    source.ticks = tick
216                    val = value(stat, run.run)
217                    if (val < (avg * .9)) or (val > (avg * 1.1)):
218                        numoutsideavg += 1
219                    if (val < (avg - stdev)) or (val > (avg + stdev)):
220                        numoutside1std += 1
221                    if (val < (avg - (2*stdev))) or (val > (avg + (2*stdev))):
222                        numoutside2std += 1
223                if avg > 1000:
224                    disp(run.name, "%.1f" % avg, "%.1f" % stdev,
225                         "%d" % numoutsideavg, "%d" % numoutside1std,
226                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
227                         "%.3f" % (stdev/avg*100))
228                elif avg > 100:
229                    disp(run.name, "%.1f" % avg, "%.1f" % stdev,
230                         "%d" % numoutsideavg, "%d" % numoutside1std,
231                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
232                         "%.5f" % (stdev/avg*100))
233                else:
234                    disp(run.name, "%.5f" % avg, "%.5f" % stdev,
235                         "%d" % numoutsideavg, "%d" % numoutside1std,
236                         "%d" % numoutside2std, "%d" % len(pairRunTicks),
237                         "%.7f" % (stdev/avg*100))
238        return
239
240    if command == 'all':
241        if len(args):
242            raise CommandException
243
244        all = [ 'bps', 'misses', 'mpkb', 'ipkb', 'pps', 'bpt' ]
245        for command in all:
246            commands(options, command, args)
247
248    if options.ticks:
249        if not options.graph:
250            print 'only displaying sample %s' % options.ticks
251        source.ticks = [ int(x) for x in options.ticks.split() ]
252
253    from output import StatOutput
254    output = StatOutput(options.jobfile, source)
255    output.xlabel = 'System Configuration'
256    output.colormap = 'RdYlGn'
257
258    if command == 'stat' or command == 'formula':
259        if len(args) != 1:
260            raise CommandException
261
262        if command == 'stat':
263            stats = source.getStat(args[0])
264        if command == 'formula':
265            stats = eval(args[0])
266
267        for stat in stats:
268            output.stat = stat
269            output.ylabel = stat.name
270            if options.graph:
271                output.graph(stat.name, options.graphdir)
272            else:
273                output.display(stat.name, options.printmode)
274
275        return
276
277    if len(args):
278        raise CommandException
279
280    from info import ProxyGroup
281    proxy = ProxyGroup(system = source[options.system])
282    system = proxy.system
283
284    etherdev = system.tsunami.etherdev0
285    bytes = etherdev.rxBytes + etherdev.txBytes
286    kbytes = bytes / 1024
287    packets = etherdev.rxPackets + etherdev.txPackets
288
289    def display():
290        if options.graph:
291            output.graph(command, options.graphdir, proxy)
292        else:
293            output.display(command, options.printmode)
294
295    if command == 'ticks':
296        output.stat = system.run0.numCycles
297
298        display()
299        return
300
301    if command == 'bytes':
302        output.stat = bytes
303        display()
304        return
305
306    if command == 'packets':
307        output.stat = packets
308        display()
309        return
310
311    if command == 'ppt' or command == 'tpp':
312        output.stat = packets / system.run0.numCycles
313        output.invert = command == 'tpp'
314        display()
315        return
316
317    if command == 'pps':
318        output.stat = packets / source['sim_seconds']
319        output.ylabel = 'Packets/s'
320        display()
321        return
322
323    if command == 'bpt' or command == 'tpb':
324        output.stat = bytes / system.run0.numCycles * 8
325        output.ylabel = 'bps / Hz'
326        output.invert = command == 'tpb'
327        display()
328        return
329
330    if command in ('rxbps', 'txbps', 'bps'):
331        if command == 'rxbps':
332            output.stat = etherdev.rxBandwidth / 1e9
333        if command == 'txbps':
334            output.stat = etherdev.txBandwidth / 1e9
335        if command == 'bps':
336            output.stat = (etherdev.rxBandwidth + etherdev.txBandwidth) / 1e9
337
338        output.ylabel = 'Bandwidth (Gbps)'
339        output.ylim = [ 0.0, 10.0 ]
340        display()
341        return
342
343    if command == 'bpp':
344        output.stat = bytes / packets
345        output.ylabel = 'Bytes / Packet'
346        display()
347        return
348
349    if command == 'rxbpp':
350        output.stat = etherdev.rxBytes / etherdev.rxPackets
351        output.ylabel = 'Receive Bytes / Packet'
352        display()
353        return
354
355    if command == 'txbpp':
356        output.stat = etherdev.txBytes / etherdev.txPackets
357        output.ylabel = 'Transmit Bytes / Packet'
358        display()
359        return
360
361    if command == 'rtp':
362        output.stat = etherdev.rxPackets / etherdev.txPackets
363        output.ylabel = 'rxPackets / txPackets'
364        display()
365        return
366
367    if command == 'rtb':
368        output.stat = etherdev.rxBytes / etherdev.txBytes
369        output.ylabel = 'rxBytes / txBytes'
370        display()
371        return
372
373    misses = system.l2.overall_mshr_misses
374
375    if command == 'misses':
376        output.stat = misses
377        output.ylabel = 'Overall MSHR Misses'
378        display()
379        return
380
381    if command == 'mpkb':
382        output.stat = misses / (bytes / 1024)
383        output.ylabel = 'Misses / KB'
384        display()
385        return
386
387    if command == 'ipkb':
388        interrupts = system.run0.kern.faults[4]
389        output.stat = interrupts / kbytes
390        output.ylabel = 'Interrupts / KB'
391        display()
392        return
393
394    if command == 'execute':
395        output.stat = system.run0.ISSUE__count
396        display()
397        return
398
399    if command == 'commit':
400        output.stat = system.run0.COM__count
401        display()
402        return
403
404    if command == 'fetch':
405        output.stat = system.run0.FETCH__count
406        display()
407        return
408
409    raise CommandException
410
411
412class Options: pass
413
414if __name__ == '__main__':
415    import getpass
416    from jobfile import JobFile
417
418    options = Options()
419    options.host = None
420    options.db = None
421    options.passwd = ''
422    options.user = getpass.getuser()
423    options.runs = None
424    options.system = 'client'
425    options.method = None
426    options.graph = False
427    options.ticks = False
428    options.printmode = 'G'
429    jobfilename = 'Test.py'
430    options.jobfile = None
431    options.all = False
432
433    opts, args = getopts(sys.argv[1:], '-EFJad:g:h:j:m:pr:s:u:T:')
434    for o,a in opts:
435        if o == '-E':
436            options.printmode = 'E'
437        if o == '-F':
438            options.printmode = 'F'
439        if o == '-a':
440            options.all = True
441        if o == '-d':
442            options.db = a
443        if o == '-g':
444            options.graph = True;
445            options.graphdir = a
446        if o == '-h':
447            options.host = a
448        if o == '-J':
449            jobfilename = None
450        if o == '-j':
451            jobfilename = a
452        if o == '-m':
453            options.method = a
454        if o == '-p':
455            options.passwd = getpass.getpass()
456        if o == '-r':
457            options.runs = a
458        if o == '-u':
459            options.user = a
460        if o == '-s':
461            options.system = a
462        if o == '-T':
463            options.ticks = a
464
465    if jobfilename:
466        options.jobfile = JobFile(jobfilename)
467        if not options.host:
468            options.host = options.jobfile.dbhost
469        if not options.db:
470            options.db = options.jobfile.statdb
471
472    if not options.host:
473        sys.exit('Database server must be provided from a jobfile or -h')
474
475    if not options.db:
476        sys.exit('Database name must be provided from a jobfile or -d')
477
478    if len(args) == 0:
479        usage()
480
481    command = args[0]
482    args = args[1:]
483
484    try:
485        commands(options, command, args)
486    except CommandException:
487        usage()
488