stats.py revision 2665
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) 43 formula <formula> Evaluated formula specified 44 formulas [regex] List formulas (only matching regex) 45 runs none List all runs in database 46 samples none List samples present in database 47 stability <pairnum> <stats> Calculated statistical info about stats 48 stat <regex> Show stat data (only matching regex) 49 stats [regex] List all stats (only matching regex) 50 51 database <command> Where command is drop, init, or clean 52 53''' % sys.argv[0] 54 sys.exit(1) 55 56def getopts(list, flags): 57 import getopt 58 try: 59 opts, args = getopt.getopt(list, flags) 60 except getopt.GetoptError: 61 usage() 62 63 return opts, args 64 65class CommandException(Exception): 66 pass 67 68def commands(options, command, args): 69 if command == 'database': 70 if len(args) == 0: raise CommandException 71 72 import dbinit 73 mydb = dbinit.MyDB(options) 74 75 if args[0] == 'drop': 76 if len(args) > 2: raise CommandException 77 mydb.admin() 78 mydb.drop() 79 if len(args) == 2 and args[1] == 'init': 80 mydb.create() 81 mydb.connect() 82 mydb.populate() 83 mydb.close() 84 return 85 86 if args[0] == 'init': 87 if len(args) > 1: raise CommandException 88 mydb.admin() 89 mydb.create() 90 mydb.connect() 91 mydb.populate() 92 mydb.close() 93 return 94 95 if args[0] == 'clean': 96 if len(args) > 1: raise CommandException 97 mydb.connect() 98 mydb.clean() 99 return 100 101 raise CommandException 102 103 import db 104 source = db.Database() 105 source.host = options.host 106 source.db = options.db 107 source.passwd = options.passwd 108 source.user = options.user 109 source.connect() 110 #source.update_dict(globals()) 111 112 if type(options.method) is str: 113 source.method = options.method 114 115 if options.runs is None: 116 runs = source.allRuns 117 else: 118 rx = re.compile(options.runs) 119 runs = [] 120 for run in source.allRuns: 121 if rx.match(run.name): 122 runs.append(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 source.listRuns(user) 133 return 134 135 if command == 'stats': 136 if len(args) == 0: 137 source.listStats() 138 elif len(args) == 1: 139 source.listStats(args[0]) 140 else: 141 raise CommandException 142 143 return 144 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 155 if command == 'formulas': 156 if len(args) == 0: 157 source.listFormulas() 158 elif len(args) == 1: 159 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 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 = source.getStat(args[1]) 181 source.method = 'sum' 182 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 runTicks = source.retTicks([ run ]) 199 #throw away the first one, it's 0 200 runTicks.pop(0) 201 source.ticks = runTicks 202 avg = 0 203 stdev = 0 204 numoutsideavg = 0 205 numoutside1std = 0 206 numoutside2std = 0 207 pairRunTicks = [] 208 if value(stat, run.run) == 1e300*1e300: 209 continue 210 for t in range(0, len(runTicks)-(merge-1), merge): 211 tempPair = [] 212 for p in range(0,merge): 213 tempPair.append(runTicks[t+p]) 214 pairRunTicks.append(tempPair) 215 #loop through all the various ticks for each run 216 for tick in pairRunTicks: 217 source.ticks = tick 218 avg += value(stat, run.run) 219 avg /= len(pairRunTicks) 220 for tick in pairRunTicks: 221 source.ticks = tick 222 val = value(stat, run.run) 223 stdev += pow((val-avg),2) 224 stdev = math.sqrt(stdev / len(pairRunTicks)) 225 for tick in pairRunTicks: 226 source.ticks = tick 227 val = value(stat, run.run) 228 if (val < (avg * .9)) or (val > (avg * 1.1)): 229 numoutsideavg += 1 230 if (val < (avg - stdev)) or (val > (avg + stdev)): 231 numoutside1std += 1 232 if (val < (avg - (2*stdev))) or (val > (avg + (2*stdev))): 233 numoutside2std += 1 234 if avg > 1000: 235 disp(run.name, "%.1f" % avg, "%.1f" % stdev, 236 "%d" % numoutsideavg, "%d" % numoutside1std, 237 "%d" % numoutside2std, "%d" % len(pairRunTicks), 238 "%.3f" % (stdev/avg*100)) 239 elif avg > 100: 240 disp(run.name, "%.1f" % avg, "%.1f" % stdev, 241 "%d" % numoutsideavg, "%d" % numoutside1std, 242 "%d" % numoutside2std, "%d" % len(pairRunTicks), 243 "%.5f" % (stdev/avg*100)) 244 else: 245 disp(run.name, "%.5f" % avg, "%.5f" % stdev, 246 "%d" % numoutsideavg, "%d" % numoutside1std, 247 "%d" % numoutside2std, "%d" % len(pairRunTicks), 248 "%.7f" % (stdev/avg*100)) 249 return 250 251 if command == 'all': 252 if len(args): 253 raise CommandException 254 255 all = [ 'bps', 'misses', 'mpkb', 'ipkb', 'pps', 'bpt' ] 256 for command in all: 257 commands(options, command, args) 258 259 if options.ticks: 260 if not options.graph: 261 print 'only displaying sample %s' % options.ticks 262 source.ticks = [ int(x) for x in options.ticks.split() ] 263 264 from output import StatOutput 265 output = StatOutput(options.jobfile, source) 266 output.xlabel = 'System Configuration' 267 output.colormap = 'RdYlGn' 268 269 if command == 'stat' or command == 'formula': 270 if len(args) != 1: 271 raise CommandException 272 273 if command == 'stat': 274 stats = source.getStat(args[0]) 275 if command == 'formula': 276 stats = eval(args[0]) 277 278 for stat in stats: 279 output.stat = stat 280 output.ylabel = stat.name 281 if options.graph: 282 output.graph(stat.name, options.graphdir) 283 else: 284 output.display(stat.name, options.binned, options.printmode) 285 286 return 287 288 if len(args): 289 raise CommandException 290 291 from info import ProxyGroup 292 proxy = ProxyGroup(system = source[options.system]) 293 system = proxy.system 294 295 etherdev = system.tsunami.etherdev0 296 bytes = etherdev.rxBytes + etherdev.txBytes 297 kbytes = bytes / 1024 298 packets = etherdev.rxPackets + etherdev.txPackets 299 300 def display(): 301 if options.graph: 302 output.graph(command, options.graphdir, proxy) 303 else: 304 output.display(command, options.binned, options.printmode) 305 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 317 if command == 'ticks': 318 output.stat = system.run0.numCycles 319 output.binstats = [ system.run0.numCycles ] 320 321 display() 322 return 323 324 if command == 'bytes': 325 output.stat = bytes 326 display() 327 return 328 329 if command == 'packets': 330 output.stat = packets 331 display() 332 return 333 334 if command == 'ppt' or command == 'tpp': 335 output.stat = packets / system.run0.numCycles 336 output.invert = command == 'tpp' 337 display() 338 return 339 340 if command == 'pps': 341 output.stat = packets / source['sim_seconds'] 342 output.ylabel = 'Packets/s' 343 display() 344 return 345 346 if command == 'bpt' or command == 'tpb': 347 output.stat = bytes / system.run0.numCycles * 8 348 output.ylabel = 'bps / Hz' 349 output.invert = command == 'tpb' 350 display() 351 return 352 353 if command in ('rxbps', 'txbps', 'bps'): 354 if command == 'rxbps': 355 output.stat = etherdev.rxBandwidth / 1e9 356 if command == 'txbps': 357 output.stat = etherdev.txBandwidth / 1e9 358 if command == 'bps': 359 output.stat = (etherdev.rxBandwidth + etherdev.txBandwidth) / 1e9 360 361 output.ylabel = 'Bandwidth (Gbps)' 362 output.ylim = [ 0.0, 10.0 ] 363 display() 364 return 365 366 if command == 'bpp': 367 output.stat = bytes / packets 368 output.ylabel = 'Bytes / Packet' 369 display() 370 return 371 372 if command == 'rxbpp': 373 output.stat = etherdev.rxBytes / etherdev.rxPackets 374 output.ylabel = 'Receive Bytes / Packet' 375 display() 376 return 377 378 if command == 'txbpp': 379 output.stat = etherdev.txBytes / etherdev.txPackets 380 output.ylabel = 'Transmit Bytes / Packet' 381 display() 382 return 383 384 if command == 'rtp': 385 output.stat = etherdev.rxPackets / etherdev.txPackets 386 output.ylabel = 'rxPackets / txPackets' 387 display() 388 return 389 390 if command == 'rtb': 391 output.stat = etherdev.rxBytes / etherdev.txBytes 392 output.ylabel = 'rxBytes / txBytes' 393 display() 394 return 395 396 misses = system.l2.overall_mshr_misses 397 398 if command == 'misses': 399 output.stat = misses 400 output.ylabel = 'Overall MSHR Misses' 401 display() 402 return 403 404 if command == 'mpkb': 405 output.stat = misses / (bytes / 1024) 406 output.binstats = [ misses ] 407 output.ylabel = 'Misses / KB' 408 display() 409 return 410 411 if command == 'ipkb': 412 interrupts = system.run0.kern.faults[4] 413 output.stat = interrupts / kbytes 414 output.binstats = [ interrupts ] 415 output.ylabel = 'Interrupts / KB' 416 display() 417 return 418 419 if command == 'execute': 420 output.stat = system.run0.ISSUE__count 421 display() 422 return 423 424 if command == 'commit': 425 output.stat = system.run0.COM__count 426 display() 427 return 428 429 if command == 'fetch': 430 output.stat = system.run0.FETCH__count 431 display() 432 return 433 434 raise CommandException 435 436 437class Options: pass 438 439if __name__ == '__main__': 440 import getpass 441 from jobfile import JobFile 442 443 options = Options() 444 options.host = None 445 options.db = None 446 options.passwd = '' 447 options.user = getpass.getuser() 448 options.runs = None 449 options.system = 'client' 450 options.method = None 451 options.binned = False 452 options.graph = False 453 options.ticks = False 454 options.printmode = 'G' 455 jobfilename = 'Test.py' 456 options.jobfile = None 457 options.all = False 458 459 opts, args = getopts(sys.argv[1:], '-BEFJad:g:h:j:m:pr:s:u:T:') 460 for o,a in opts: 461 if o == '-B': 462 options.binned = True 463 if o == '-E': 464 options.printmode = 'E' 465 if o == '-F': 466 options.printmode = 'F' 467 if o == '-a': 468 options.all = True 469 if o == '-d': 470 options.db = a 471 if o == '-g': 472 options.graph = True; 473 options.graphdir = a 474 if o == '-h': 475 options.host = a 476 if o == '-J': 477 jobfilename = None 478 if o == '-j': 479 jobfilename = a 480 if o == '-m': 481 options.method = a 482 if o == '-p': 483 options.passwd = getpass.getpass() 484 if o == '-r': 485 options.runs = a 486 if o == '-u': 487 options.user = a 488 if o == '-s': 489 options.system = a 490 if o == '-T': 491 options.ticks = a 492 493 if jobfilename: 494 options.jobfile = JobFile(jobfilename) 495 if not options.host: 496 options.host = options.jobfile.dbhost 497 if not options.db: 498 options.db = options.jobfile.statdb 499 500 if not options.host: 501 sys.exit('Database server must be provided from a jobfile or -h') 502 503 if not options.db: 504 sys.exit('Database name must be provided from a jobfile or -d') 505 506 if len(args) == 0: 507 usage() 508 509 command = args[0] 510 args = args[1:] 511 512 try: 513 commands(options, command, args) 514 except CommandException: 515 usage() 516