1#!/usr/bin/env python 2 3import sys, re, os.path, cgi, stat, math 4from optparse import OptionParser 5from color import getColorizer 6 7class tblCell(object): 8 def __init__(self, text, value = None, props = None): 9 self.text = text 10 self.value = value 11 self.props = props 12 13class tblColumn(object): 14 def __init__(self, caption, title = None, props = None): 15 self.text = caption 16 self.title = title 17 self.props = props 18 19class tblRow(object): 20 def __init__(self, colsNum, props = None): 21 self.cells = [None] * colsNum 22 self.props = props 23 24def htmlEncode(str): 25 return '<br/>'.join([cgi.escape(s) for s in str]) 26 27class table(object): 28 def_align = "left" 29 def_valign = "middle" 30 def_color = None 31 def_colspan = 1 32 def_rowspan = 1 33 def_bold = False 34 def_italic = False 35 def_text="-" 36 37 def __init__(self, caption = None): 38 self.columns = {} 39 self.rows = [] 40 self.ridx = -1; 41 self.caption = caption 42 pass 43 44 def newRow(self, **properties): 45 if len(self.rows) - 1 == self.ridx: 46 self.rows.append(tblRow(len(self.columns), properties)) 47 else: 48 self.rows[ridx + 1].props = properties 49 self.ridx += 1 50 return self.rows[self.ridx] 51 52 def trimLastRow(self): 53 if self.rows: 54 self.rows.pop() 55 if self.ridx >= len(self.rows): 56 self.ridx = len(self.rows) - 1 57 58 def newColumn(self, name, caption, title = None, **properties): 59 if name in self.columns: 60 index = self.columns[name].index 61 else: 62 index = len(self.columns) 63 if isinstance(caption, tblColumn): 64 caption.index = index 65 self.columns[name] = caption 66 return caption 67 else: 68 col = tblColumn(caption, title, properties) 69 col.index = index 70 self.columns[name] = col 71 return col 72 73 def getColumn(self, name): 74 if isinstance(name, str): 75 return self.columns.get(name, None) 76 else: 77 vals = [v for v in self.columns.values() if v.index == name] 78 if vals: 79 return vals[0] 80 return None 81 82 def newCell(self, col_name, text, value = None, **properties): 83 if self.ridx < 0: 84 self.newRow() 85 col = self.getColumn(col_name) 86 row = self.rows[self.ridx] 87 if not col: 88 return None 89 if isinstance(text, tblCell): 90 cl = text 91 else: 92 cl = tblCell(text, value, properties) 93 row.cells[col.index] = cl 94 return cl 95 96 def layoutTable(self): 97 columns = self.columns.values() 98 columns.sort(key=lambda c: c.index) 99 100 colspanned = [] 101 rowspanned = [] 102 103 self.headerHeight = 1 104 rowsToAppend = 0 105 106 for col in columns: 107 self.measureCell(col) 108 if col.height > self.headerHeight: 109 self.headerHeight = col.height 110 col.minwidth = col.width 111 col.line = None 112 113 for r in range(len(self.rows)): 114 row = self.rows[r] 115 row.minheight = 1 116 for i in range(len(row.cells)): 117 cell = row.cells[i] 118 if row.cells[i] is None: 119 continue 120 cell.line = None 121 self.measureCell(cell) 122 colspan = int(self.getValue("colspan", cell)) 123 rowspan = int(self.getValue("rowspan", cell)) 124 if colspan > 1: 125 colspanned.append((r,i)) 126 if i + colspan > len(columns): 127 colspan = len(columns) - i 128 cell.colspan = colspan 129 #clear spanned cells 130 for j in range(i+1, min(len(row.cells), i + colspan)): 131 row.cells[j] = None 132 elif columns[i].minwidth < cell.width: 133 columns[i].minwidth = cell.width 134 if rowspan > 1: 135 rowspanned.append((r,i)) 136 rowsToAppend2 = r + colspan - len(self.rows) 137 if rowsToAppend2 > rowsToAppend: 138 rowsToAppend = rowsToAppend2 139 cell.rowspan = rowspan 140 #clear spanned cells 141 for j in range(r+1, min(len(self.rows), r + rowspan)): 142 if len(self.rows[j].cells) > i: 143 self.rows[j].cells[i] = None 144 elif row.minheight < cell.height: 145 row.minheight = cell.height 146 147 self.ridx = len(self.rows) - 1 148 for r in range(rowsToAppend): 149 self.newRow() 150 self.rows[len(self.rows) - 1].minheight = 1 151 152 while colspanned: 153 colspanned_new = [] 154 for r, c in colspanned: 155 cell = self.rows[r].cells[c] 156 sum([col.minwidth for col in columns[c:c + cell.colspan]]) 157 cell.awailable = sum([col.minwidth for col in columns[c:c + cell.colspan]]) + cell.colspan - 1 158 if cell.awailable < cell.width: 159 colspanned_new.append((r,c)) 160 colspanned = colspanned_new 161 if colspanned: 162 r,c = colspanned[0] 163 cell = self.rows[r].cells[c] 164 cols = columns[c:c + cell.colspan] 165 total = cell.awailable - cell.colspan + 1 166 budget = cell.width - cell.awailable 167 spent = 0 168 s = 0 169 for col in cols: 170 s += col.minwidth 171 addition = s * budget / total - spent 172 spent += addition 173 col.minwidth += addition 174 175 while rowspanned: 176 rowspanned_new = [] 177 for r, c in rowspanned: 178 cell = self.rows[r].cells[c] 179 cell.awailable = sum([row.minheight for row in self.rows[r:r + cell.rowspan]]) 180 if cell.awailable < cell.height: 181 rowspanned_new.append((r,c)) 182 rowspanned = rowspanned_new 183 if rowspanned: 184 r,c = rowspanned[0] 185 cell = self.rows[r].cells[c] 186 rows = self.rows[r:r + cell.rowspan] 187 total = cell.awailable 188 budget = cell.height - cell.awailable 189 spent = 0 190 s = 0 191 for row in rows: 192 s += row.minheight 193 addition = s * budget / total - spent 194 spent += addition 195 row.minheight += addition 196 197 return columns 198 199 def measureCell(self, cell): 200 text = self.getValue("text", cell) 201 cell.text = self.reformatTextValue(text) 202 cell.height = len(cell.text) 203 cell.width = len(max(cell.text, key = lambda line: len(line))) 204 205 def reformatTextValue(self, value): 206 if isinstance(value, str): 207 vstr = value 208 elif isinstance(value, unicode): 209 vstr = str(value) 210 else: 211 try: 212 vstr = '\n'.join([str(v) for v in value]) 213 except TypeError: 214 vstr = str(value) 215 return vstr.splitlines() 216 217 def adjustColWidth(self, cols, width): 218 total = sum([c.minWidth for c in cols]) 219 if total + len(cols) - 1 >= width: 220 return 221 budget = width - len(cols) + 1 - total 222 spent = 0 223 s = 0 224 for col in cols: 225 s += col.minWidth 226 addition = s * budget / total - spent 227 spent += addition 228 col.minWidth += addition 229 230 def getValue(self, name, *elements): 231 for el in elements: 232 try: 233 return getattr(el, name) 234 except AttributeError: 235 pass 236 try: 237 val = el.props[name] 238 if val: 239 return val 240 except AttributeError: 241 pass 242 except KeyError: 243 pass 244 try: 245 return getattr(self.__class__, "def_" + name) 246 except AttributeError: 247 return None 248 249 def consolePrintTable(self, out): 250 columns = self.layoutTable() 251 colrizer = getColorizer(out) 252 253 if self.caption: 254 out.write("%s%s%s" % ( os.linesep, os.linesep.join(self.reformatTextValue(self.caption)), os.linesep * 2)) 255 256 headerRow = tblRow(len(columns), {"align": "center", "valign": "top", "bold": True, "header": True}) 257 headerRow.cells = columns 258 headerRow.minheight = self.headerHeight 259 260 self.consolePrintRow2(colrizer, headerRow, columns) 261 262 for i in range(0, len(self.rows)): 263 self.consolePrintRow2(colrizer, i, columns) 264 265 def consolePrintRow2(self, out, r, columns): 266 if isinstance(r, tblRow): 267 row = r 268 r = -1 269 else: 270 row = self.rows[r] 271 272 #evaluate initial values for line numbers 273 i = 0 274 while i < len(row.cells): 275 cell = row.cells[i] 276 colspan = self.getValue("colspan", cell) 277 if cell is not None: 278 cell.wspace = sum([col.minwidth for col in columns[i:i + colspan]]) + colspan - 1 279 if cell.line is None: 280 if r < 0: 281 rows = [row] 282 else: 283 rows = self.rows[r:r + self.getValue("rowspan", cell)] 284 cell.line = self.evalLine(cell, rows, columns[i]) 285 if len(rows) > 1: 286 for rw in rows: 287 rw.cells[i] = cell 288 i += colspan 289 290 #print content 291 for ln in range(row.minheight): 292 i = 0 293 while i < len(row.cells): 294 if i > 0: 295 out.write(" ") 296 cell = row.cells[i] 297 column = columns[i] 298 if cell is None: 299 out.write(" " * column.minwidth) 300 i += 1 301 else: 302 self.consolePrintLine(cell, row, column, out) 303 i += self.getValue("colspan", cell) 304 out.write(os.linesep) 305 306 def consolePrintLine(self, cell, row, column, out): 307 if cell.line < 0 or cell.line >= cell.height: 308 line = "" 309 else: 310 line = cell.text[cell.line] 311 width = cell.wspace 312 align = self.getValue("align", ((None, cell)[isinstance(cell, tblCell)]), row, column) 313 314 if align == "right": 315 pattern = "%" + str(width) + "s" 316 elif align == "center": 317 pattern = "%" + str((width - len(line)) / 2 + len(line)) + "s" + " " * (width - len(line) - (width - len(line)) / 2) 318 else: 319 pattern = "%-" + str(width) + "s" 320 321 out.write(pattern % line, color = self.getValue("color", cell, row, column)) 322 cell.line += 1 323 324 def evalLine(self, cell, rows, column): 325 height = cell.height 326 valign = self.getValue("valign", cell, rows[0], column) 327 space = sum([row.minheight for row in rows]) 328 if valign == "bottom": 329 return height - space 330 if valign == "middle": 331 return (height - space + 1) / 2 332 return 0 333 334 def htmlPrintTable(self, out, embeedcss = False): 335 columns = self.layoutTable() 336 337 if embeedcss: 338 out.write("<div style=\"font-family: Lucida Console, Courier New, Courier;font-size: 16px;color:#3e4758;\">\n<table style=\"background:none repeat scroll 0 0 #FFFFFF;border-collapse:collapse;font-family:'Lucida Sans Unicode','Lucida Grande',Sans-Serif;font-size:14px;margin:20px;text-align:left;width:480px;margin-left: auto;margin-right: auto;white-space:nowrap;\">\n") 339 else: 340 out.write("<div class=\"tableFormatter\">\n<table class=\"tbl\">\n") 341 if self.caption: 342 if embeedcss: 343 out.write(" <caption style=\"font:italic 16px 'Trebuchet MS',Verdana,Arial,Helvetica,sans-serif;padding:0 0 5px;text-align:right;white-space:normal;\">%s</caption>\n" % htmlEncode(self.reformatTextValue(self.caption))) 344 else: 345 out.write(" <caption>%s</caption>\n" % htmlEncode(self.reformatTextValue(self.caption))) 346 out.write(" <thead>\n") 347 348 headerRow = tblRow(len(columns), {"align": "center", "valign": "top", "bold": True, "header": True}) 349 headerRow.cells = columns 350 351 header_rows = [headerRow] 352 header_rows.extend([row for row in self.rows if self.getValue("header")]) 353 last_row = header_rows[len(header_rows) - 1] 354 355 for row in header_rows: 356 out.write(" <tr>\n") 357 for th in row.cells: 358 align = self.getValue("align", ((None, th)[isinstance(th, tblCell)]), row, row) 359 valign = self.getValue("valign", th, row) 360 cssclass = self.getValue("cssclass", th) 361 attr = "" 362 if align: 363 attr += " align=\"%s\"" % align 364 if valign: 365 attr += " valign=\"%s\"" % valign 366 if cssclass: 367 attr += " class=\"%s\"" % cssclass 368 css = "" 369 if embeedcss: 370 css = " style=\"border:none;color:#003399;font-size:16px;font-weight:normal;white-space:nowrap;padding:3px 10px;\"" 371 if row == last_row: 372 css = css[:-1] + "padding-bottom:5px;\"" 373 out.write(" <th%s%s>\n" % (attr, css)) 374 if th is not None: 375 out.write(" %s\n" % htmlEncode(th.text)) 376 out.write(" </th>\n") 377 out.write(" </tr>\n") 378 379 out.write(" </thead>\n <tbody>\n") 380 381 rows = [row for row in self.rows if not self.getValue("header")] 382 for r in range(len(rows)): 383 row = rows[r] 384 rowattr = "" 385 cssclass = self.getValue("cssclass", row) 386 if cssclass: 387 rowattr += " class=\"%s\"" % cssclass 388 out.write(" <tr%s>\n" % (rowattr)) 389 i = 0 390 while i < len(row.cells): 391 column = columns[i] 392 td = row.cells[i] 393 if isinstance(td, int): 394 i += td 395 continue 396 colspan = self.getValue("colspan", td) 397 rowspan = self.getValue("rowspan", td) 398 align = self.getValue("align", td, row, column) 399 valign = self.getValue("valign", td, row, column) 400 color = self.getValue("color", td, row, column) 401 bold = self.getValue("bold", td, row, column) 402 italic = self.getValue("italic", td, row, column) 403 style = "" 404 attr = "" 405 if color: 406 style += "color:%s;" % color 407 if bold: 408 style += "font-weight: bold;" 409 if italic: 410 style += "font-style: italic;" 411 if align and align != "left": 412 attr += " align=\"%s\"" % align 413 if valign and valign != "middle": 414 attr += " valign=\"%s\"" % valign 415 if colspan > 1: 416 attr += " colspan=\"%s\"" % colspan 417 if rowspan > 1: 418 attr += " rowspan=\"%s\"" % rowspan 419 for q in range(r+1, min(r+rowspan, len(rows))): 420 rows[q].cells[i] = colspan 421 if style: 422 attr += " style=\"%s\"" % style 423 css = "" 424 if embeedcss: 425 css = " style=\"border:none;border-bottom:1px solid #CCCCCC;color:#666699;padding:6px 8px;white-space:nowrap;\"" 426 if r == 0: 427 css = css[:-1] + "border-top:2px solid #6678B1;\"" 428 out.write(" <td%s%s>\n" % (attr, css)) 429 if td is not None: 430 out.write(" %s\n" % htmlEncode(td.text)) 431 out.write(" </td>\n") 432 i += colspan 433 out.write(" </tr>\n") 434 435 out.write(" </tbody>\n</table>\n</div>\n") 436 437def htmlPrintHeader(out, title = None): 438 if title: 439 titletag = "<title>%s</title>\n" % htmlEncode([str(title)]) 440 else: 441 titletag = "" 442 out.write("""<!DOCTYPE HTML> 443<html> 444<head> 445<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> 446%s<style type="text/css"> 447html, body {font-family: Lucida Console, Courier New, Courier;font-size: 16px;color:#3e4758;} 448.tbl{background:none repeat scroll 0 0 #FFFFFF;border-collapse:collapse;font-family:"Lucida Sans Unicode","Lucida Grande",Sans-Serif;font-size:14px;margin:20px;text-align:left;width:480px;margin-left: auto;margin-right: auto;white-space:nowrap;} 449.tbl span{display:block;white-space:nowrap;} 450.tbl thead tr:last-child th {padding-bottom:5px;} 451.tbl tbody tr:first-child td {border-top:3px solid #6678B1;} 452.tbl th{border:none;color:#003399;font-size:16px;font-weight:normal;white-space:nowrap;padding:3px 10px;} 453.tbl td{border:none;border-bottom:1px solid #CCCCCC;color:#666699;padding:6px 8px;white-space:nowrap;} 454.tbl tbody tr:hover td{color:#000099;} 455.tbl caption{font:italic 16px "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;padding:0 0 5px;text-align:right;white-space:normal;} 456.firstingroup {border-top:2px solid #6678B1;} 457</style> 458<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script> 459<script type="text/javascript"> 460function abs(val) { return val < 0 ? -val : val } 461$(function(){ 462 //generate filter rows 463 $("div.tableFormatter table.tbl").each(function(tblIdx, tbl) { 464 var head = $("thead", tbl) 465 var filters = $("<tr></tr>") 466 var hasAny = false 467 $("tr:first th", head).each(function(colIdx, col) { 468 col = $(col) 469 var cell 470 var id = "t" + tblIdx + "r" + colIdx 471 if (col.hasClass("col_name")){ 472 cell = $("<th><input id='" + id + "' name='" + id + "' type='text' style='width:100%%' class='filter_col_name' title='Regular expression for name filtering ("resize.*640x480" - resize tests on VGA resolution)'></input></th>") 473 hasAny = true 474 } 475 else if (col.hasClass("col_rel")){ 476 cell = $("<th><input id='" + id + "' name='" + id + "' type='text' style='width:100%%' class='filter_col_rel' title='Filter out lines with a x-factor of acceleration less than Nx'></input></th>") 477 hasAny = true 478 } 479 else if (col.hasClass("col_cr")){ 480 cell = $("<th><input id='" + id + "' name='" + id + "' type='text' style='width:100%%' class='filter_col_cr' title='Filter out lines with a percentage of acceleration less than N%%'></input></th>") 481 hasAny = true 482 } 483 else 484 cell = $("<th></th>") 485 cell.appendTo(filters) 486 }) 487 488 if (hasAny){ 489 $(tbl).wrap("<form id='form_t" + tblIdx + "' method='get' action=''></form>") 490 $("<input it='test' type='submit' value='Apply Filters' style='margin-left:10px;'></input>") 491 .appendTo($("th:last", filters.appendTo(head))) 492 } 493 }) 494 495 //get filter values 496 var vars = [] 497 var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&') 498 for(var i = 0; i < hashes.length; ++i) 499 { 500 hash = hashes[i].split('=') 501 vars.push(decodeURIComponent(hash[0])) 502 vars[decodeURIComponent(hash[0])] = decodeURIComponent(hash[1]); 503 } 504 505 //set filter values 506 for(var i = 0; i < vars.length; ++i) 507 $("#" + vars[i]).val(vars[vars[i]]) 508 509 //apply filters 510 $("div.tableFormatter table.tbl").each(function(tblIdx, tbl) { 511 filters = $("input:text", tbl) 512 var predicate = function(row) {return true;} 513 var empty = true 514 $.each($("input:text", tbl), function(i, flt) { 515 flt = $(flt) 516 var val = flt.val() 517 var pred = predicate; 518 if(val) { 519 empty = false 520 var colIdx = parseInt(flt.attr("id").slice(flt.attr("id").indexOf('r') + 1)) 521 if(flt.hasClass("filter_col_name")) { 522 var re = new RegExp(val); 523 predicate = function(row) { 524 if (re.exec($(row.get(colIdx)).text()) == null) 525 return false 526 return pred(row) 527 } 528 } else if(flt.hasClass("filter_col_rel")) { 529 var percent = parseFloat(val) 530 if (percent < 0) { 531 predicate = function(row) { 532 var val = parseFloat($(row.get(colIdx)).text()) 533 if (!val || val >= 1 || val > 1+percent) 534 return false 535 return pred(row) 536 } 537 } else { 538 predicate = function(row) { 539 var val = parseFloat($(row.get(colIdx)).text()) 540 if (!val || val < percent) 541 return false 542 return pred(row) 543 } 544 } 545 } else if(flt.hasClass("filter_col_cr")) { 546 var percent = parseFloat(val) 547 predicate = function(row) { 548 var val = parseFloat($(row.get(colIdx)).text()) 549 if (!val || val < percent) 550 return false 551 return pred(row) 552 } 553 } 554 } 555 }); 556 if (!empty){ 557 $("tbody tr", tbl).each(function (i, tbl_row) { 558 if(!predicate($("td", tbl_row))) 559 $(tbl_row).remove() 560 }) 561 if($("tbody tr", tbl).length == 0) { 562 $("<tr><td colspan='"+$("thead tr:first th", tbl).length+"'>No results mathing your search criteria</td></tr>") 563 .appendTo($("tbody", tbl)) 564 } 565 } 566 }) 567}) 568</script> 569</head> 570<body> 571""" % titletag) 572 573def htmlPrintFooter(out): 574 out.write("</body>\n</html>") 575 576def getStdoutFilename(): 577 try: 578 if os.name == "nt": 579 import msvcrt, ctypes 580 handle = msvcrt.get_osfhandle(sys.stdout.fileno()) 581 size = ctypes.c_ulong(1024) 582 nameBuffer = ctypes.create_string_buffer(size.value) 583 ctypes.windll.kernel32.GetFinalPathNameByHandleA(handle, nameBuffer, size, 4) 584 return nameBuffer.value 585 else: 586 return os.readlink('/proc/self/fd/1') 587 except: 588 return "" 589 590def detectHtmlOutputType(requestedType): 591 if requestedType == "txt": 592 return False 593 elif requestedType in ["html", "moinwiki"]: 594 return True 595 else: 596 if sys.stdout.isatty(): 597 return False 598 else: 599 outname = getStdoutFilename() 600 if outname: 601 if outname.endswith(".htm") or outname.endswith(".html"): 602 return True 603 else: 604 return False 605 else: 606 return False 607 608def getRelativeVal(test, test0, metric): 609 if not test or not test0: 610 return None 611 val0 = test0.get(metric, "s") 612 if not val0: 613 return None 614 val = test.get(metric, "s") 615 if not val or val == 0: 616 return None 617 return float(val0)/val 618 619def getCycleReduction(test, test0, metric): 620 if not test or not test0: 621 return None 622 val0 = test0.get(metric, "s") 623 if not val0 or val0 == 0: 624 return None 625 val = test.get(metric, "s") 626 if not val: 627 return None 628 return (1.0-float(val)/val0)*100 629 630def getScore(test, test0, metric): 631 if not test or not test0: 632 return None 633 m0 = float(test.get("gmean", None)) 634 m1 = float(test0.get("gmean", None)) 635 if m0 == 0 or m1 == 0: 636 return None 637 s0 = float(test.get("gstddev", None)) 638 s1 = float(test0.get("gstddev", None)) 639 s = math.sqrt(s0*s0 + s1*s1) 640 m0 = math.log(m0) 641 m1 = math.log(m1) 642 if s == 0: 643 return None 644 return (m0-m1)/s 645 646metrix_table = \ 647{ 648 "name": ("Name of Test", lambda test,test0,units: str(test)), 649 650 "samples": ("Number of\ncollected samples", lambda test,test0,units: test.get("samples", units)), 651 "outliers": ("Number of\noutliers", lambda test,test0,units: test.get("outliers", units)), 652 653 "gmean": ("Geometric mean", lambda test,test0,units: test.get("gmean", units)), 654 "mean": ("Mean", lambda test,test0,units: test.get("mean", units)), 655 "min": ("Min", lambda test,test0,units: test.get("min", units)), 656 "median": ("Median", lambda test,test0,units: test.get("median", units)), 657 "stddev": ("Standard deviation", lambda test,test0,units: test.get("stddev", units)), 658 "gstddev": ("Standard deviation of Ln(time)", lambda test,test0,units: test.get("gstddev")), 659 660 "gmean%": ("Geometric mean (relative)", lambda test,test0,units: getRelativeVal(test, test0, "gmean")), 661 "mean%": ("Mean (relative)", lambda test,test0,units: getRelativeVal(test, test0, "mean")), 662 "min%": ("Min (relative)", lambda test,test0,units: getRelativeVal(test, test0, "min")), 663 "median%": ("Median (relative)", lambda test,test0,units: getRelativeVal(test, test0, "median")), 664 "stddev%": ("Standard deviation (relative)", lambda test,test0,units: getRelativeVal(test, test0, "stddev")), 665 "gstddev%": ("Standard deviation of Ln(time) (relative)", lambda test,test0,units: getRelativeVal(test, test0, "gstddev")), 666 667 "gmean$": ("Geometric mean (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "gmean")), 668 "mean$": ("Mean (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "mean")), 669 "min$": ("Min (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "min")), 670 "median$": ("Median (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "median")), 671 "stddev$": ("Standard deviation (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "stddev")), 672 "gstddev$": ("Standard deviation of Ln(time) (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "gstddev")), 673 674 "score": ("SCORE", lambda test,test0,units: getScore(test, test0, "gstddev")), 675} 676 677def formatValue(val, metric, units = None): 678 if val is None: 679 return "-" 680 if metric.endswith("%"): 681 return "%.2f" % val 682 if metric.endswith("$"): 683 return "%.2f%%" % val 684 if metric.endswith("S"): 685 if val > 3.5: 686 return "SLOWER" 687 if val < -3.5: 688 return "FASTER" 689 if val > -1.5 and val < 1.5: 690 return " " 691 if val < 0: 692 return "faster" 693 if val > 0: 694 return "slower" 695 #return "%.4f" % val 696 return "%.3f %s" % (val, units) 697 698if __name__ == "__main__": 699 if len(sys.argv) < 2: 700 print "Usage:\n", os.path.basename(sys.argv[0]), "<log_name>.xml" 701 exit(0) 702 703 parser = OptionParser() 704 parser.add_option("-o", "--output", dest="format", help="output results in text format (can be 'txt', 'html' or 'auto' - default)", metavar="FMT", default="auto") 705 parser.add_option("-m", "--metric", dest="metric", help="output metric", metavar="NAME", default="gmean") 706 parser.add_option("-u", "--units", dest="units", help="units for output values (s, ms (default), mks, ns or ticks)", metavar="UNITS", default="ms") 707 (options, args) = parser.parse_args() 708 709 options.generateHtml = detectHtmlOutputType(options.format) 710 if options.metric not in metrix_table: 711 options.metric = "gmean" 712 713 #print options 714 #print args 715 716# tbl = table() 717# tbl.newColumn("first", "qqqq", align = "left") 718# tbl.newColumn("second", "wwww\nz\nx\n") 719# tbl.newColumn("third", "wwasdas") 720# 721# tbl.newCell(0, "ccc111", align = "right") 722# tbl.newCell(1, "dddd1") 723# tbl.newCell(2, "8768756754") 724# tbl.newRow() 725# tbl.newCell(0, "1\n2\n3\n4\n5\n6\n7", align = "center", colspan = 2, rowspan = 2) 726# tbl.newCell(2, "xxx\nqqq", align = "center", colspan = 1, valign = "middle") 727# tbl.newRow() 728# tbl.newCell(2, "+", align = "center", colspan = 1, valign = "middle") 729# tbl.newRow() 730# tbl.newCell(0, "vcvvbasdsadassdasdasv", align = "right", colspan = 2) 731# tbl.newCell(2, "dddd1") 732# tbl.newRow() 733# tbl.newCell(0, "vcvvbv") 734# tbl.newCell(1, "3445324", align = "right") 735# tbl.newCell(2, None) 736# tbl.newCell(1, "0000") 737# if sys.stdout.isatty(): 738# tbl.consolePrintTable(sys.stdout) 739# else: 740# htmlPrintHeader(sys.stdout) 741# tbl.htmlPrintTable(sys.stdout) 742# htmlPrintFooter(sys.stdout) 743 744 import testlog_parser 745 746 if options.generateHtml: 747 htmlPrintHeader(sys.stdout, "Tables demo") 748 749 getter = metrix_table[options.metric][1] 750 751 for arg in args: 752 tests = testlog_parser.parseLogFile(arg) 753 tbl = table(arg) 754 tbl.newColumn("name", "Name of Test", align = "left") 755 tbl.newColumn("value", metrix_table[options.metric][0], align = "center", bold = "true") 756 757 for t in sorted(tests): 758 tbl.newRow() 759 tbl.newCell("name", str(t)) 760 761 status = t.get("status") 762 if status != "run": 763 tbl.newCell("value", status) 764 else: 765 val = getter(t, None, options.units) 766 if val: 767 if options.metric.endswith("%"): 768 tbl.newCell("value", "%.2f" % val, val) 769 else: 770 tbl.newCell("value", "%.3f %s" % (val, options.units), val) 771 else: 772 tbl.newCell("value", "-") 773 774 if options.generateHtml: 775 tbl.htmlPrintTable(sys.stdout) 776 else: 777 tbl.consolePrintTable(sys.stdout) 778 779 if options.generateHtml: 780 htmlPrintFooter(sys.stdout) 781