Home | History | Annotate | Download | only in misc
      1 #!/usr/bin/env python
      2 
      3 import sys, re, os.path, cgi, stat, math
      4 from optparse import OptionParser
      5 from color import getColorizer
      6 
      7 class tblCell(object):
      8     def __init__(self, text, value = None, props = None):
      9         self.text = text
     10         self.value = value
     11         self.props = props
     12 
     13 class tblColumn(object):
     14     def __init__(self, caption, title = None, props = None):
     15         self.text = caption
     16         self.title = title
     17         self.props = props
     18 
     19 class tblRow(object):
     20     def __init__(self, colsNum, props = None):
     21         self.cells = [None] * colsNum
     22         self.props = props
     23 
     24 def htmlEncode(str):
     25     return '<br/>'.join([cgi.escape(s) for s in str])
     26 
     27 class 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 
    437 def 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">
    447 html, 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">
    460 function 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 (&quot;resize.*640x480&quot; - 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 
    573 def htmlPrintFooter(out):
    574     out.write("</body>\n</html>")
    575 
    576 def 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 
    590 def 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 
    608 def 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 
    619 def 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 
    630 def 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 
    646 metrix_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 
    677 def 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 
    698 if __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