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 bins [regex] List bins (only matching regex)
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
145 if command == 'bins':
146 if len(args) == 0:
147 source.listBins()
148 elif len(args) == 1:
149 source.listBins(args[0])
150 else:
151 raise CommandException
152
153 return
154
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:
284 output.display(stat.name, options.binned, options.printmode)
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:
304 output.display(command, options.binned, options.printmode)
293 output.display(command, options.printmode)
294
306 if command == 'usertime':
307 import copy
308 user = copy.copy(system.run0.numCycles)
309 user.bins = 'user'
310
311 output.stat = user / system.run0.numCycles
312 output.ylabel = 'User Fraction'
313
314 display()
315 return
316
295 if command == 'ticks':
296 output.stat = system.run0.numCycles
319 output.binstats = [ 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)
406 output.binstats = [ misses ]
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
414 output.binstats = [ interrupts ]
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
451 options.binned = False
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
459 opts, args = getopts(sys.argv[1:], '-BEFJad:g:h:j:m:pr:s:u:T:')
433 opts, args = getopts(sys.argv[1:], '-EFJad:g:h:j:m:pr:s:u:T:')
434 for o,a in opts:
461 if o == '-B':
462 options.binned = True
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()