stats.py revision 2002
112855Sgabeblack@google.com#!/usr/bin/env python 212855Sgabeblack@google.com 312855Sgabeblack@google.com# Copyright (c) 2003-2004 The Regents of The University of Michigan 412855Sgabeblack@google.com# All rights reserved. 512855Sgabeblack@google.com# 612855Sgabeblack@google.com# Redistribution and use in source and binary forms, with or without 712855Sgabeblack@google.com# modification, are permitted provided that the following conditions are 812855Sgabeblack@google.com# met: redistributions of source code must retain the above copyright 912855Sgabeblack@google.com# notice, this list of conditions and the following disclaimer; 1012855Sgabeblack@google.com# redistributions in binary form must reproduce the above copyright 1112855Sgabeblack@google.com# notice, this list of conditions and the following disclaimer in the 1212855Sgabeblack@google.com# documentation and/or other materials provided with the distribution; 1312855Sgabeblack@google.com# neither the name of the copyright holders nor the names of its 1412855Sgabeblack@google.com# contributors may be used to endorse or promote products derived from 1512855Sgabeblack@google.com# this software without specific prior written permission. 1612855Sgabeblack@google.com# 1712855Sgabeblack@google.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1812855Sgabeblack@google.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1912855Sgabeblack@google.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2012855Sgabeblack@google.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2112855Sgabeblack@google.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2212855Sgabeblack@google.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2312855Sgabeblack@google.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2412855Sgabeblack@google.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2512855Sgabeblack@google.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2612855Sgabeblack@google.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2712855Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2812855Sgabeblack@google.com 2912855Sgabeblack@google.comfrom __future__ import division 3012855Sgabeblack@google.comimport re, sys, math 3112855Sgabeblack@google.com 3212855Sgabeblack@google.comdef usage(): 3312855Sgabeblack@google.com print '''\ 3412855Sgabeblack@google.comUsage: %s [-E] [-F] [ -G <get> ] [-d <db> ] [-g <graphdir> ] [-h <host>] [-p] 3512855Sgabeblack@google.com [-s <system>] [-r <runs> ] [-T <samples>] [-u <username>] 3612855Sgabeblack@google.com <command> [command args] 3712855Sgabeblack@google.com 3812855Sgabeblack@google.com commands extra parameters description 3912855Sgabeblack@google.com ----------- ------------------ --------------------------------------- 4012855Sgabeblack@google.com bins [regex] List bins (only matching regex) 4112855Sgabeblack@google.com formula <formula> Evaluated formula specified 4212855Sgabeblack@google.com formulas [regex] List formulas (only matching regex) 4312855Sgabeblack@google.com runs none List all runs in database 4412855Sgabeblack@google.com samples none List samples present in database 4512855Sgabeblack@google.com stability <pairnum> <stats> Calculated statistical info about stats 4612855Sgabeblack@google.com stat <regex> Show stat data (only matching regex) 4712855Sgabeblack@google.com stats [regex] List all stats (only matching regex) 4812855Sgabeblack@google.com 4912855Sgabeblack@google.com database <command> Where command is drop, init, or clean 5012855Sgabeblack@google.com 5112855Sgabeblack@google.com''' % sys.argv[0] 5212855Sgabeblack@google.com sys.exit(1) 5312855Sgabeblack@google.com 5412855Sgabeblack@google.comdef getopts(list, flags): 5512855Sgabeblack@google.com import getopt 5612855Sgabeblack@google.com try: 5712855Sgabeblack@google.com opts, args = getopt.getopt(list, flags) 5812855Sgabeblack@google.com except getopt.GetoptError: 5912855Sgabeblack@google.com usage() 6012855Sgabeblack@google.com 6112855Sgabeblack@google.com return opts, args 6212855Sgabeblack@google.com 6312855Sgabeblack@google.comclass CommandException(Exception): 6412855Sgabeblack@google.com pass 6512855Sgabeblack@google.com 6612855Sgabeblack@google.comdef commands(options, command, args): 6712855Sgabeblack@google.com if command == 'database': 6812855Sgabeblack@google.com if len(args) == 0: raise CommandException 6912855Sgabeblack@google.com 7012855Sgabeblack@google.com import dbinit 7112855Sgabeblack@google.com mydb = dbinit.MyDB(options) 7212855Sgabeblack@google.com 7312855Sgabeblack@google.com if args[0] == 'drop': 7412855Sgabeblack@google.com if len(args) > 2: raise CommandException 7512855Sgabeblack@google.com mydb.admin() 7612855Sgabeblack@google.com mydb.drop() 7712855Sgabeblack@google.com if len(args) == 2 and args[1] == 'init': 7812855Sgabeblack@google.com mydb.create() 7912855Sgabeblack@google.com mydb.connect() 8012855Sgabeblack@google.com mydb.populate() 8112855Sgabeblack@google.com mydb.close() 8212855Sgabeblack@google.com return 8312855Sgabeblack@google.com 8412855Sgabeblack@google.com if args[0] == 'init': 8512855Sgabeblack@google.com if len(args) > 1: raise CommandException 8612855Sgabeblack@google.com mydb.admin() 8712855Sgabeblack@google.com mydb.create() 8812855Sgabeblack@google.com mydb.connect() 8912855Sgabeblack@google.com mydb.populate() 9012855Sgabeblack@google.com mydb.close() 9112855Sgabeblack@google.com return 9212855Sgabeblack@google.com 9312855Sgabeblack@google.com if args[0] == 'clean': 9412855Sgabeblack@google.com if len(args) > 1: raise CommandException 9512855Sgabeblack@google.com mydb.connect() 9612855Sgabeblack@google.com mydb.clean() 9712855Sgabeblack@google.com return 9812855Sgabeblack@google.com 9912855Sgabeblack@google.com raise CommandException 10012855Sgabeblack@google.com 10112855Sgabeblack@google.com import db 10212855Sgabeblack@google.com source = db.Database() 10312855Sgabeblack@google.com source.host = options.host 10412855Sgabeblack@google.com source.db = options.db 10512855Sgabeblack@google.com source.passwd = options.passwd 10612855Sgabeblack@google.com source.user = options.user 10712855Sgabeblack@google.com source.connect() 10812855Sgabeblack@google.com #source.update_dict(globals()) 10912855Sgabeblack@google.com 11012855Sgabeblack@google.com if type(options.method) is str: 11112855Sgabeblack@google.com source.method = options.method 11212855Sgabeblack@google.com 11312855Sgabeblack@google.com if options.runs is None: 11412855Sgabeblack@google.com runs = source.allRuns 11512855Sgabeblack@google.com else: 11612855Sgabeblack@google.com rx = re.compile(options.runs) 11712855Sgabeblack@google.com runs = [] 11812855Sgabeblack@google.com for run in source.allRuns: 11912855Sgabeblack@google.com if rx.match(run.name): 12012855Sgabeblack@google.com runs.append(run) 12112855Sgabeblack@google.com 12212855Sgabeblack@google.com if command == 'runs': 12312855Sgabeblack@google.com user = None 12412855Sgabeblack@google.com opts, args = getopts(args, '-u') 12512855Sgabeblack@google.com if len(args): 12612855Sgabeblack@google.com raise CommandException 12712855Sgabeblack@google.com for o,a in opts: 12812855Sgabeblack@google.com if o == '-u': 12912855Sgabeblack@google.com user = a 13012855Sgabeblack@google.com source.listRuns(user) 13112855Sgabeblack@google.com return 13212855Sgabeblack@google.com 13312855Sgabeblack@google.com if command == 'stats': 13412855Sgabeblack@google.com if len(args) == 0: 13512855Sgabeblack@google.com source.listStats() 13612855Sgabeblack@google.com elif len(args) == 1: 13712855Sgabeblack@google.com source.listStats(args[0]) 13812855Sgabeblack@google.com else: 13912855Sgabeblack@google.com 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 "%-35s %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[:35], 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_seconds = source['sim_seconds'] 298 proxy = ProxyGroup(system = source[options.system]) 299 system = proxy.system 300 301 etherdev = system.tsunami.etherdev0 302 bytes = etherdev.rxBytes + etherdev.txBytes 303 kbytes = bytes / 1024 304 packets = etherdev.rxPackets + etherdev.txPackets 305 bps = etherdev.rxBandwidth + etherdev.txBandwidth 306 307 output = output.StatOutput(command, options.jobfile, source) 308 309 if command == 'usertime': 310 import copy 311 user = copy.copy(system.run0.numCycles) 312 user.bins = 'user' 313 314 output.stat = user / system.run0.numCycles 315 output.label = 'User Fraction' 316 317 display() 318 return 319 320 if command == 'ticks': 321 output.stat = system.run0.numCycles 322 output.binstats = [ system.run0.numCycles ] 323 324 display() 325 return 326 327 if command == 'bytes': 328 output.stat = bytes 329 display() 330 return 331 332 if command == 'packets': 333 output.stat = packets 334 display() 335 return 336 337 if command == 'ppt' or command == 'tpp': 338 output.stat = packets / system.run0.numCycles 339 output.invert = command == 'tpp' 340 display() 341 return 342 343 if command == 'pps': 344 output.stat = packets / sim_seconds 345 output.label = 'Packets/s' 346 display() 347 return 348 349 if command == 'bpt' or command == 'tpb': 350 output.stat = bytes / system.run0.numCycles * 8 351 output.label = 'bps / Hz' 352 output.invert = command == 'tpb' 353 display() 354 return 355 356 if command in ('rxbps', 'txbps', 'bps'): 357 if command == 'rxbps': 358 output.stat = etherdev.rxBandwidth / 1e9 359 if command == 'txbps': 360 output.stat = etherdev.txBandwidth / 1e9 361 if command == 'bps': 362 output.stat = bps / 1e9 363 364 output.label = 'Bandwidth (Gbps)' 365 display() 366 return 367 368 if command == 'bpp': 369 output.stat = bytes / packets 370 output.label = 'Bytes / Packet' 371 display() 372 return 373 374 if command == 'rxbpp': 375 output.stat = etherdev.rxBytes / etherdev.rxPackets 376 output.label = 'Receive Bytes / Packet' 377 display() 378 return 379 380 if command == 'txbpp': 381 output.stat = etherdev.txBytes / etherdev.txPackets 382 output.label = 'Transmit Bytes / Packet' 383 display() 384 return 385 386 if command == 'rtp': 387 output.stat = etherdev.rxPackets / etherdev.txPackets 388 output.label = 'rxPackets / txPackets' 389 display() 390 return 391 392 if command == 'rtb': 393 output.stat = etherdev.rxBytes / etherdev.txBytes 394 output.label = 'rxBytes / txBytes' 395 display() 396 return 397 398 misses = system.l2.overall_mshr_misses 399 400 if command == 'misses': 401 output.stat = misses 402 output.label = 'Overall MSHR Misses' 403 display() 404 return 405 406 if command == 'mpkb': 407 output.stat = misses / (bytes / 1024) 408 output.binstats = [ misses ] 409 output.label = 'Misses / KB' 410 display() 411 return 412 413 if command == 'ipkb': 414 interrupts = system.run0.kern.faults[4] 415 output.stat = interrupts / kbytes 416 output.binstats = [ interrupts ] 417 output.label = 'Interrupts / KB' 418 display() 419 return 420 421 if command == 'execute': 422 output.stat = system.run0.ISSUE__count 423 display() 424 return 425 426 if command == 'commit': 427 output.stat = system.run0.COM__count 428 display() 429 return 430 431 if command == 'fetch': 432 output.stat = system.run0.FETCH__count 433 display() 434 return 435 436 raise CommandException 437 438 439class Options: pass 440 441if __name__ == '__main__': 442 import getpass 443 from jobfile import JobFile 444 445 options = Options() 446 options.host = None 447 options.db = None 448 options.passwd = '' 449 options.user = getpass.getuser() 450 options.runs = None 451 options.system = 'client' 452 options.method = None 453 options.binned = False 454 options.graph = False 455 options.ticks = False 456 options.printmode = 'G' 457 jobfilename = 'Test.py' 458 options.jobfile = None 459 options.all = False 460 461 opts, args = getopts(sys.argv[1:], '-BEFJad:g:h:j:m:pr:s:u:T:') 462 for o,a in opts: 463 if o == '-B': 464 options.binned = True 465 if o == '-E': 466 options.printmode = 'E' 467 if o == '-F': 468 options.printmode = 'F' 469 if o == '-a': 470 options.all = True 471 if o == '-d': 472 options.db = a 473 if o == '-g': 474 options.graph = True; 475 options.graphdir = a 476 if o == '-h': 477 options.host = a 478 if o == '-J': 479 jobfilename = None 480 if o == '-j': 481 jobfilename = a 482 if o == '-m': 483 options.method = a 484 if o == '-p': 485 options.passwd = getpass.getpass() 486 if o == '-r': 487 options.runs = a 488 if o == '-u': 489 options.user = a 490 if o == '-s': 491 options.system = a 492 if o == '-T': 493 options.ticks = a 494 495 if jobfilename: 496 options.jobfile = JobFile(jobfilename) 497 if not options.host: 498 options.host = options.jobfile.dbhost 499 if not options.db: 500 options.db = options.jobfile.statdb 501 502 if not options.host: 503 sys.exit('Database server must be provided from a jobfile or -h') 504 505 if not options.db: 506 sys.exit('Database name must be provided from a jobfile or -d') 507 508 if len(args) == 0: 509 usage() 510 511 command = args[0] 512 args = args[1:] 513 514 try: 515 commands(options, command, args) 516 except CommandException: 517 usage() 518