stats.py revision 1881
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 29from __future__ import division 30import re, sys, math 31 32def usage(): 33 print '''\ 34Usage: %s [-E] [-F] [ -G <get> ] [-d <db> ] [-g <graphdir> ] [-h <host>] [-p] 35 [-s <system>] [-r <runs> ] [-T <samples>] [-u <username>] 36 <command> [command args] 37 38 commands extra parameters description 39 ----------- ------------------ --------------------------------------- 40 bins [regex] List bins (only matching regex) 41 formula <formula> Evaluated formula specified 42 formulas [regex] List formulas (only matching regex) 43 runs none List all runs in database 44 samples none List samples present in database 45 stability <pairnum> <stats> Calculated statistical info about stats 46 stat <regex> Show stat data (only matching regex) 47 stats [regex] List all stats (only matching regex) 48 49 database <command> Where command is drop, init, or clean 50 51''' % sys.argv[0] 52 sys.exit(1) 53 54def getopts(list, flags): 55 import getopt 56 try: 57 opts, args = getopt.getopt(list, flags) 58 except getopt.GetoptError: 59 usage() 60 61 return opts, args 62 63class CommandException(Exception): 64 pass 65 66def commands(options, command, args): 67 if command == 'database': 68 if len(args) == 0: raise CommandException 69 70 import dbinit 71 mydb = dbinit.MyDB(options) 72 73 if args[0] == 'drop': 74 if len(args) > 2: raise CommandException 75 mydb.admin() 76 mydb.drop() 77 if len(args) == 2 and args[1] == 'init': 78 mydb.create() 79 mydb.connect() 80 mydb.populate() 81 mydb.close() 82 return 83 84 if args[0] == 'init': 85 if len(args) > 1: raise CommandException 86 mydb.admin() 87 mydb.create() 88 mydb.connect() 89 mydb.populate() 90 mydb.close() 91 return 92 93 if args[0] == 'clean': 94 if len(args) > 1: raise CommandException 95 mydb.connect() 96 mydb.clean() 97 return 98 99 raise CommandException 100 101 import db, info 102 info.source = db.Database() 103 info.source.host = options.host 104 info.source.db = options.db 105 info.source.passwd = options.passwd 106 info.source.user = options.user 107 info.source.connect() 108 #info.source.update_dict(globals()) 109 110 if type(options.get) is str: 111 info.source.get = options.get 112 113 if options.runs is None: 114 runs = info.source.allRuns 115 else: 116 rx = re.compile(options.runs) 117 runs = [] 118 for run in info.source.allRuns: 119 if rx.match(run.name): 120 runs.append(run) 121 122 info.display_run = runs[0].run 123 124 if command == 'runs': 125 user = None 126 opts, args = getopts(args, '-u') 127 if len(args): 128 raise CommandException 129 for o,a in opts: 130 if o == '-u': 131 user = a 132 info.source.listRuns(user) 133 return 134 135 if command == 'stats': 136 if len(args) == 0: 137 info.source.listStats() 138 elif len(args) == 1: 139 info.source.listStats(args[0]) 140 else: 141 raise CommandException 142 143 return 144 145 if command == 'bins': 146 if len(args) == 0: 147 info.source.listBins() 148 elif len(args) == 1: 149 info.source.listBins(args[0]) 150 else: 151 raise CommandException 152 153 return 154 155 if command == 'formulas': 156 if len(args) == 0: 157 info.source.listFormulas() 158 elif len(args) == 1: 159 info.source.listFormulas(args[0]) 160 else: 161 raise CommandException 162 163 return 164 165 if command == 'samples': 166 if len(args): 167 raise CommandException 168 169 info.source.listTicks(runs) 170 return 171 172 if command == 'stability': 173 if len(args) < 2: 174 raise CommandException 175 176 try: 177 merge = int(args[0]) 178 except ValueError: 179 usage() 180 stats = info.source.getStat(args[1]) 181 info.source.get = "sum" 182 183 def disp(*args): 184 print "%-20s %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[:20], 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 options.jobfile = None 469 options.all = False 470 471 opts, args = getopts(sys.argv[1:], '-BEFG:ad:g:h:j:pr:s:u:T:') 472 for o,a in opts: 473 if o == '-B': 474 options.binned = True 475 if o == '-E': 476 options.printmode = 'E' 477 if o == '-F': 478 options.printmode = 'F' 479 if o == '-G': 480 options.get = a 481 if o == '-a': 482 options.all = True 483 if o == '-d': 484 options.db = a 485 if o == '-g': 486 options.graph = True; 487 options.graphdir = a 488 if o == '-h': 489 options.host = a 490 if o == '-j': 491 options.jobfile = JobFile(a) 492 if o == '-p': 493 options.passwd = getpass.getpass() 494 if o == '-r': 495 options.runs = a 496 if o == '-u': 497 options.user = a 498 if o == '-s': 499 options.system = a 500 if o == '-T': 501 options.ticks = a 502 503 if options.jobfile: 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