stats.py revision 1929
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 102 source = db.Database() 103 source.host = options.host 104 source.db = options.db 105 source.passwd = options.passwd 106 source.user = options.user 107 source.connect() 108 #source.update_dict(globals()) 109 110 if type(options.method) is str: 111 source.method = options.method 112 113 if options.runs is None: 114 runs = source.allRuns 115 else: 116 rx = re.compile(options.runs) 117 runs = [] 118 for run in source.allRuns: 119 if rx.match(run.name): 120 runs.append(run) 121 122 if command == 'runs': 123 user = None 124 opts, args = getopts(args, '-u') 125 if len(args): 126 raise CommandException 127 for o,a in opts: 128 if o == '-u': 129 user = a 130 source.listRuns(user) 131 return 132 133 if command == 'stats': 134 if len(args) == 0: 135 source.listStats() 136 elif len(args) == 1: 137 source.listStats(args[0]) 138 else: 139 raise CommandException 140 141 return 142 143 if command == 'bins': 144 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