mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
814 lines
30 KiB
814 lines
30 KiB
#!/usr/bin/env python |
|
""" Prints data in a table format. |
|
|
|
This module serves as utility for other scripts. |
|
""" |
|
|
|
import sys, re, os.path, stat, math |
|
from html import escape |
|
from optparse import OptionParser |
|
from color import getColorizer, dummyColorizer |
|
|
|
class tblCell(object): |
|
def __init__(self, text, value = None, props = None): |
|
self.text = text |
|
self.value = value |
|
self.props = props |
|
|
|
class tblColumn(object): |
|
def __init__(self, caption, title = None, props = None): |
|
self.text = caption |
|
self.title = title |
|
self.props = props |
|
|
|
class tblRow(object): |
|
def __init__(self, colsNum, props = None): |
|
self.cells = [None] * colsNum |
|
self.props = props |
|
|
|
def htmlEncode(str): |
|
return '<br/>'.join([escape(s) for s in str]) |
|
|
|
class table(object): |
|
def_align = "left" |
|
def_valign = "middle" |
|
def_color = None |
|
def_colspan = 1 |
|
def_rowspan = 1 |
|
def_bold = False |
|
def_italic = False |
|
def_text="-" |
|
|
|
def __init__(self, caption = None, format=None): |
|
self.format = format |
|
self.is_markdown = self.format == 'markdown' |
|
self.is_tabs = self.format == 'tabs' |
|
self.columns = {} |
|
self.rows = [] |
|
self.ridx = -1; |
|
self.caption = caption |
|
pass |
|
|
|
def newRow(self, **properties): |
|
if len(self.rows) - 1 == self.ridx: |
|
self.rows.append(tblRow(len(self.columns), properties)) |
|
else: |
|
self.rows[self.ridx + 1].props = properties |
|
self.ridx += 1 |
|
return self.rows[self.ridx] |
|
|
|
def trimLastRow(self): |
|
if self.rows: |
|
self.rows.pop() |
|
if self.ridx >= len(self.rows): |
|
self.ridx = len(self.rows) - 1 |
|
|
|
def newColumn(self, name, caption, title = None, **properties): |
|
if name in self.columns: |
|
index = self.columns[name].index |
|
else: |
|
index = len(self.columns) |
|
if isinstance(caption, tblColumn): |
|
caption.index = index |
|
self.columns[name] = caption |
|
return caption |
|
else: |
|
col = tblColumn(caption, title, properties) |
|
col.index = index |
|
self.columns[name] = col |
|
return col |
|
|
|
def getColumn(self, name): |
|
if isinstance(name, str): |
|
return self.columns.get(name, None) |
|
else: |
|
vals = [v for v in self.columns.values() if v.index == name] |
|
if vals: |
|
return vals[0] |
|
return None |
|
|
|
def newCell(self, col_name, text, value = None, **properties): |
|
if self.ridx < 0: |
|
self.newRow() |
|
col = self.getColumn(col_name) |
|
row = self.rows[self.ridx] |
|
if not col: |
|
return None |
|
if isinstance(text, tblCell): |
|
cl = text |
|
else: |
|
cl = tblCell(text, value, properties) |
|
row.cells[col.index] = cl |
|
return cl |
|
|
|
def layoutTable(self): |
|
columns = self.columns.values() |
|
columns = sorted(columns, key=lambda c: c.index) |
|
|
|
colspanned = [] |
|
rowspanned = [] |
|
|
|
self.headerHeight = 1 |
|
rowsToAppend = 0 |
|
|
|
for col in columns: |
|
self.measureCell(col) |
|
if col.height > self.headerHeight: |
|
self.headerHeight = col.height |
|
col.minwidth = col.width |
|
col.line = None |
|
|
|
for r in range(len(self.rows)): |
|
row = self.rows[r] |
|
row.minheight = 1 |
|
for i in range(len(row.cells)): |
|
cell = row.cells[i] |
|
if row.cells[i] is None: |
|
continue |
|
cell.line = None |
|
self.measureCell(cell) |
|
colspan = int(self.getValue("colspan", cell)) |
|
rowspan = int(self.getValue("rowspan", cell)) |
|
if colspan > 1: |
|
colspanned.append((r,i)) |
|
if i + colspan > len(columns): |
|
colspan = len(columns) - i |
|
cell.colspan = colspan |
|
#clear spanned cells |
|
for j in range(i+1, min(len(row.cells), i + colspan)): |
|
row.cells[j] = None |
|
elif columns[i].minwidth < cell.width: |
|
columns[i].minwidth = cell.width |
|
if rowspan > 1: |
|
rowspanned.append((r,i)) |
|
rowsToAppend2 = r + colspan - len(self.rows) |
|
if rowsToAppend2 > rowsToAppend: |
|
rowsToAppend = rowsToAppend2 |
|
cell.rowspan = rowspan |
|
#clear spanned cells |
|
for j in range(r+1, min(len(self.rows), r + rowspan)): |
|
if len(self.rows[j].cells) > i: |
|
self.rows[j].cells[i] = None |
|
elif row.minheight < cell.height: |
|
row.minheight = cell.height |
|
|
|
self.ridx = len(self.rows) - 1 |
|
for r in range(rowsToAppend): |
|
self.newRow() |
|
self.rows[len(self.rows) - 1].minheight = 1 |
|
|
|
while colspanned: |
|
colspanned_new = [] |
|
for r, c in colspanned: |
|
cell = self.rows[r].cells[c] |
|
sum([col.minwidth for col in columns[c:c + cell.colspan]]) |
|
cell.awailable = sum([col.minwidth for col in columns[c:c + cell.colspan]]) + cell.colspan - 1 |
|
if cell.awailable < cell.width: |
|
colspanned_new.append((r,c)) |
|
colspanned = colspanned_new |
|
if colspanned: |
|
r,c = colspanned[0] |
|
cell = self.rows[r].cells[c] |
|
cols = columns[c:c + cell.colspan] |
|
total = cell.awailable - cell.colspan + 1 |
|
budget = cell.width - cell.awailable |
|
spent = 0 |
|
s = 0 |
|
for col in cols: |
|
s += col.minwidth |
|
addition = s * budget / total - spent |
|
spent += addition |
|
col.minwidth += addition |
|
|
|
while rowspanned: |
|
rowspanned_new = [] |
|
for r, c in rowspanned: |
|
cell = self.rows[r].cells[c] |
|
cell.awailable = sum([row.minheight for row in self.rows[r:r + cell.rowspan]]) |
|
if cell.awailable < cell.height: |
|
rowspanned_new.append((r,c)) |
|
rowspanned = rowspanned_new |
|
if rowspanned: |
|
r,c = rowspanned[0] |
|
cell = self.rows[r].cells[c] |
|
rows = self.rows[r:r + cell.rowspan] |
|
total = cell.awailable |
|
budget = cell.height - cell.awailable |
|
spent = 0 |
|
s = 0 |
|
for row in rows: |
|
s += row.minheight |
|
addition = s * budget / total - spent |
|
spent += addition |
|
row.minheight += addition |
|
|
|
return columns |
|
|
|
def measureCell(self, cell): |
|
text = self.getValue("text", cell) |
|
cell.text = self.reformatTextValue(text) |
|
cell.height = len(cell.text) |
|
cell.width = len(max(cell.text, key = lambda line: len(line))) |
|
|
|
def reformatTextValue(self, value): |
|
if isinstance(value, str): |
|
vstr = value |
|
else: |
|
try: |
|
vstr = '\n'.join([str(v) for v in value]) |
|
except TypeError: |
|
vstr = str(value) |
|
return vstr.splitlines() |
|
|
|
def adjustColWidth(self, cols, width): |
|
total = sum([c.minWidth for c in cols]) |
|
if total + len(cols) - 1 >= width: |
|
return |
|
budget = width - len(cols) + 1 - total |
|
spent = 0 |
|
s = 0 |
|
for col in cols: |
|
s += col.minWidth |
|
addition = s * budget / total - spent |
|
spent += addition |
|
col.minWidth += addition |
|
|
|
def getValue(self, name, *elements): |
|
for el in elements: |
|
try: |
|
return getattr(el, name) |
|
except AttributeError: |
|
pass |
|
try: |
|
val = el.props[name] |
|
if val: |
|
return val |
|
except AttributeError: |
|
pass |
|
except KeyError: |
|
pass |
|
try: |
|
return getattr(self.__class__, "def_" + name) |
|
except AttributeError: |
|
return None |
|
|
|
def consolePrintTable(self, out): |
|
columns = self.layoutTable() |
|
colrizer = getColorizer(out) if not (self.is_markdown or self.is_tabs) else dummyColorizer(out) |
|
|
|
if self.caption: |
|
out.write("%s%s%s" % ( os.linesep, os.linesep.join(self.reformatTextValue(self.caption)), os.linesep * 2)) |
|
|
|
headerRow = tblRow(len(columns), {"align": "center", "valign": "top", "bold": True, "header": True}) |
|
headerRow.cells = columns |
|
headerRow.minheight = self.headerHeight |
|
|
|
self.consolePrintRow2(colrizer, headerRow, columns) |
|
|
|
for i in range(0, len(self.rows)): |
|
self.consolePrintRow2(colrizer, i, columns) |
|
|
|
def consolePrintRow2(self, out, r, columns): |
|
if isinstance(r, tblRow): |
|
row = r |
|
r = -1 |
|
else: |
|
row = self.rows[r] |
|
|
|
#evaluate initial values for line numbers |
|
i = 0 |
|
while i < len(row.cells): |
|
cell = row.cells[i] |
|
colspan = self.getValue("colspan", cell) |
|
if cell is not None: |
|
cell.wspace = sum([col.minwidth for col in columns[i:i + colspan]]) + colspan - 1 |
|
if cell.line is None: |
|
if r < 0: |
|
rows = [row] |
|
else: |
|
rows = self.rows[r:r + self.getValue("rowspan", cell)] |
|
cell.line = self.evalLine(cell, rows, columns[i]) |
|
if len(rows) > 1: |
|
for rw in rows: |
|
rw.cells[i] = cell |
|
i += colspan |
|
|
|
#print content |
|
if self.is_markdown: |
|
out.write("|") |
|
for c in row.cells: |
|
text = ' '.join(self.getValue('text', c) or []) |
|
out.write(text + "|") |
|
out.write(os.linesep) |
|
elif self.is_tabs: |
|
cols_to_join=[' '.join(self.getValue('text', c) or []) for c in row.cells] |
|
out.write('\t'.join(cols_to_join)) |
|
out.write(os.linesep) |
|
else: |
|
for ln in range(row.minheight): |
|
i = 0 |
|
while i < len(row.cells): |
|
if i > 0: |
|
out.write(" ") |
|
cell = row.cells[i] |
|
column = columns[i] |
|
if cell is None: |
|
out.write(" " * column.minwidth) |
|
i += 1 |
|
else: |
|
self.consolePrintLine(cell, row, column, out) |
|
i += self.getValue("colspan", cell) |
|
if self.is_markdown: |
|
out.write("|") |
|
out.write(os.linesep) |
|
|
|
if self.is_markdown and row.props.get('header', False): |
|
out.write("|") |
|
for th in row.cells: |
|
align = self.getValue("align", th) |
|
if align == 'center': |
|
out.write(":-:|") |
|
elif align == 'right': |
|
out.write("--:|") |
|
else: |
|
out.write("---|") |
|
out.write(os.linesep) |
|
|
|
def consolePrintLine(self, cell, row, column, out): |
|
if cell.line < 0 or cell.line >= cell.height: |
|
line = "" |
|
else: |
|
line = cell.text[cell.line] |
|
width = cell.wspace |
|
align = self.getValue("align", ((None, cell)[isinstance(cell, tblCell)]), row, column) |
|
|
|
if align == "right": |
|
pattern = "%" + str(width) + "s" |
|
elif align == "center": |
|
pattern = "%" + str((width - len(line)) // 2 + len(line)) + "s" + " " * (width - len(line) - (width - len(line)) // 2) |
|
else: |
|
pattern = "%-" + str(width) + "s" |
|
|
|
out.write(pattern % line, color = self.getValue("color", cell, row, column)) |
|
cell.line += 1 |
|
|
|
def evalLine(self, cell, rows, column): |
|
height = cell.height |
|
valign = self.getValue("valign", cell, rows[0], column) |
|
space = sum([row.minheight for row in rows]) |
|
if valign == "bottom": |
|
return height - space |
|
if valign == "middle": |
|
return (height - space + 1) // 2 |
|
return 0 |
|
|
|
def htmlPrintTable(self, out, embeedcss = False): |
|
columns = self.layoutTable() |
|
|
|
if embeedcss: |
|
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") |
|
else: |
|
out.write("<div class=\"tableFormatter\">\n<table class=\"tbl\">\n") |
|
if self.caption: |
|
if embeedcss: |
|
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))) |
|
else: |
|
out.write(" <caption>%s</caption>\n" % htmlEncode(self.reformatTextValue(self.caption))) |
|
out.write(" <thead>\n") |
|
|
|
headerRow = tblRow(len(columns), {"align": "center", "valign": "top", "bold": True, "header": True}) |
|
headerRow.cells = columns |
|
|
|
header_rows = [headerRow] |
|
header_rows.extend([row for row in self.rows if self.getValue("header")]) |
|
last_row = header_rows[len(header_rows) - 1] |
|
|
|
for row in header_rows: |
|
out.write(" <tr>\n") |
|
for th in row.cells: |
|
align = self.getValue("align", ((None, th)[isinstance(th, tblCell)]), row, row) |
|
valign = self.getValue("valign", th, row) |
|
cssclass = self.getValue("cssclass", th) |
|
attr = "" |
|
if align: |
|
attr += " align=\"%s\"" % align |
|
if valign: |
|
attr += " valign=\"%s\"" % valign |
|
if cssclass: |
|
attr += " class=\"%s\"" % cssclass |
|
css = "" |
|
if embeedcss: |
|
css = " style=\"border:none;color:#003399;font-size:16px;font-weight:normal;white-space:nowrap;padding:3px 10px;\"" |
|
if row == last_row: |
|
css = css[:-1] + "padding-bottom:5px;\"" |
|
out.write(" <th%s%s>\n" % (attr, css)) |
|
if th is not None: |
|
out.write(" %s\n" % htmlEncode(th.text)) |
|
out.write(" </th>\n") |
|
out.write(" </tr>\n") |
|
|
|
out.write(" </thead>\n <tbody>\n") |
|
|
|
rows = [row for row in self.rows if not self.getValue("header")] |
|
for r in range(len(rows)): |
|
row = rows[r] |
|
rowattr = "" |
|
cssclass = self.getValue("cssclass", row) |
|
if cssclass: |
|
rowattr += " class=\"%s\"" % cssclass |
|
out.write(" <tr%s>\n" % (rowattr)) |
|
i = 0 |
|
while i < len(row.cells): |
|
column = columns[i] |
|
td = row.cells[i] |
|
if isinstance(td, int): |
|
i += td |
|
continue |
|
colspan = self.getValue("colspan", td) |
|
rowspan = self.getValue("rowspan", td) |
|
align = self.getValue("align", td, row, column) |
|
valign = self.getValue("valign", td, row, column) |
|
color = self.getValue("color", td, row, column) |
|
bold = self.getValue("bold", td, row, column) |
|
italic = self.getValue("italic", td, row, column) |
|
style = "" |
|
attr = "" |
|
if color: |
|
style += "color:%s;" % color |
|
if bold: |
|
style += "font-weight: bold;" |
|
if italic: |
|
style += "font-style: italic;" |
|
if align and align != "left": |
|
attr += " align=\"%s\"" % align |
|
if valign and valign != "middle": |
|
attr += " valign=\"%s\"" % valign |
|
if colspan > 1: |
|
attr += " colspan=\"%s\"" % colspan |
|
if rowspan > 1: |
|
attr += " rowspan=\"%s\"" % rowspan |
|
for q in range(r+1, min(r+rowspan, len(rows))): |
|
rows[q].cells[i] = colspan |
|
if style: |
|
attr += " style=\"%s\"" % style |
|
css = "" |
|
if embeedcss: |
|
css = " style=\"border:none;border-bottom:1px solid #CCCCCC;color:#666699;padding:6px 8px;white-space:nowrap;\"" |
|
if r == 0: |
|
css = css[:-1] + "border-top:2px solid #6678B1;\"" |
|
out.write(" <td%s%s>\n" % (attr, css)) |
|
if td is not None: |
|
out.write(" %s\n" % htmlEncode(td.text)) |
|
out.write(" </td>\n") |
|
i += colspan |
|
out.write(" </tr>\n") |
|
|
|
out.write(" </tbody>\n</table>\n</div>\n") |
|
|
|
def htmlPrintHeader(out, title = None): |
|
if title: |
|
titletag = "<title>%s</title>\n" % htmlEncode([str(title)]) |
|
else: |
|
titletag = "" |
|
out.write("""<!DOCTYPE HTML> |
|
<html> |
|
<head> |
|
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> |
|
%s<style type="text/css"> |
|
html, body {font-family: Lucida Console, Courier New, Courier;font-size: 16px;color:#3e4758;} |
|
.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;} |
|
.tbl span{display:block;white-space:nowrap;} |
|
.tbl thead tr:last-child th {padding-bottom:5px;} |
|
.tbl tbody tr:first-child td {border-top:3px solid #6678B1;} |
|
.tbl th{border:none;color:#003399;font-size:16px;font-weight:normal;white-space:nowrap;padding:3px 10px;} |
|
.tbl td{border:none;border-bottom:1px solid #CCCCCC;color:#666699;padding:6px 8px;white-space:nowrap;} |
|
.tbl tbody tr:hover td{color:#000099;} |
|
.tbl caption{font:italic 16px "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;padding:0 0 5px;text-align:right;white-space:normal;} |
|
.firstingroup {border-top:2px solid #6678B1;} |
|
</style> |
|
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script> |
|
<script type="text/javascript"> |
|
function abs(val) { return val < 0 ? -val : val } |
|
$(function(){ |
|
//generate filter rows |
|
$("div.tableFormatter table.tbl").each(function(tblIdx, tbl) { |
|
var head = $("thead", tbl) |
|
var filters = $("<tr></tr>") |
|
var hasAny = false |
|
$("tr:first th", head).each(function(colIdx, col) { |
|
col = $(col) |
|
var cell |
|
var id = "t" + tblIdx + "r" + colIdx |
|
if (col.hasClass("col_name")){ |
|
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>") |
|
hasAny = true |
|
} |
|
else if (col.hasClass("col_rel")){ |
|
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>") |
|
hasAny = true |
|
} |
|
else if (col.hasClass("col_cr")){ |
|
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>") |
|
hasAny = true |
|
} |
|
else |
|
cell = $("<th></th>") |
|
cell.appendTo(filters) |
|
}) |
|
|
|
if (hasAny){ |
|
$(tbl).wrap("<form id='form_t" + tblIdx + "' method='get' action=''></form>") |
|
$("<input it='test' type='submit' value='Apply Filters' style='margin-left:10px;'></input>") |
|
.appendTo($("th:last", filters.appendTo(head))) |
|
} |
|
}) |
|
|
|
//get filter values |
|
var vars = [] |
|
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&') |
|
for(var i = 0; i < hashes.length; ++i) |
|
{ |
|
hash = hashes[i].split('=') |
|
vars.push(decodeURIComponent(hash[0])) |
|
vars[decodeURIComponent(hash[0])] = decodeURIComponent(hash[1]); |
|
} |
|
|
|
//set filter values |
|
for(var i = 0; i < vars.length; ++i) |
|
$("#" + vars[i]).val(vars[vars[i]]) |
|
|
|
//apply filters |
|
$("div.tableFormatter table.tbl").each(function(tblIdx, tbl) { |
|
filters = $("input:text", tbl) |
|
var predicate = function(row) {return true;} |
|
var empty = true |
|
$.each($("input:text", tbl), function(i, flt) { |
|
flt = $(flt) |
|
var val = flt.val() |
|
var pred = predicate; |
|
if(val) { |
|
empty = false |
|
var colIdx = parseInt(flt.attr("id").slice(flt.attr("id").indexOf('r') + 1)) |
|
if(flt.hasClass("filter_col_name")) { |
|
var re = new RegExp(val); |
|
predicate = function(row) { |
|
if (re.exec($(row.get(colIdx)).text()) == null) |
|
return false |
|
return pred(row) |
|
} |
|
} else if(flt.hasClass("filter_col_rel")) { |
|
var percent = parseFloat(val) |
|
if (percent < 0) { |
|
predicate = function(row) { |
|
var val = parseFloat($(row.get(colIdx)).text()) |
|
if (!val || val >= 1 || val > 1+percent) |
|
return false |
|
return pred(row) |
|
} |
|
} else { |
|
predicate = function(row) { |
|
var val = parseFloat($(row.get(colIdx)).text()) |
|
if (!val || val < percent) |
|
return false |
|
return pred(row) |
|
} |
|
} |
|
} else if(flt.hasClass("filter_col_cr")) { |
|
var percent = parseFloat(val) |
|
predicate = function(row) { |
|
var val = parseFloat($(row.get(colIdx)).text()) |
|
if (!val || val < percent) |
|
return false |
|
return pred(row) |
|
} |
|
} |
|
} |
|
}); |
|
if (!empty){ |
|
$("tbody tr", tbl).each(function (i, tbl_row) { |
|
if(!predicate($("td", tbl_row))) |
|
$(tbl_row).remove() |
|
}) |
|
if($("tbody tr", tbl).length == 0) { |
|
$("<tr><td colspan='"+$("thead tr:first th", tbl).length+"'>No results matching your search criteria</td></tr>") |
|
.appendTo($("tbody", tbl)) |
|
} |
|
} |
|
}) |
|
}) |
|
</script> |
|
</head> |
|
<body> |
|
""" % titletag) |
|
|
|
def htmlPrintFooter(out): |
|
out.write("</body>\n</html>") |
|
|
|
def getStdoutFilename(): |
|
try: |
|
if os.name == "nt": |
|
import msvcrt, ctypes |
|
handle = msvcrt.get_osfhandle(sys.stdout.fileno()) |
|
size = ctypes.c_ulong(1024) |
|
nameBuffer = ctypes.create_string_buffer(size.value) |
|
ctypes.windll.kernel32.GetFinalPathNameByHandleA(handle, nameBuffer, size, 4) |
|
return nameBuffer.value |
|
else: |
|
return os.readlink('/proc/self/fd/1') |
|
except: |
|
return "" |
|
|
|
def detectHtmlOutputType(requestedType): |
|
if requestedType in ['txt', 'markdown']: |
|
return False |
|
elif requestedType in ["html", "moinwiki"]: |
|
return True |
|
else: |
|
if sys.stdout.isatty(): |
|
return False |
|
else: |
|
outname = getStdoutFilename() |
|
if outname: |
|
if outname.endswith(".htm") or outname.endswith(".html"): |
|
return True |
|
else: |
|
return False |
|
else: |
|
return False |
|
|
|
def getRelativeVal(test, test0, metric): |
|
if not test or not test0: |
|
return None |
|
val0 = test0.get(metric, "s") |
|
if not val0: |
|
return None |
|
val = test.get(metric, "s") |
|
if not val or val == 0: |
|
return None |
|
return float(val0)/val |
|
|
|
def getCycleReduction(test, test0, metric): |
|
if not test or not test0: |
|
return None |
|
val0 = test0.get(metric, "s") |
|
if not val0 or val0 == 0: |
|
return None |
|
val = test.get(metric, "s") |
|
if not val: |
|
return None |
|
return (1.0-float(val)/val0)*100 |
|
|
|
def getScore(test, test0, metric): |
|
if not test or not test0: |
|
return None |
|
m0 = float(test.get("gmean", None)) |
|
m1 = float(test0.get("gmean", None)) |
|
if m0 == 0 or m1 == 0: |
|
return None |
|
s0 = float(test.get("gstddev", None)) |
|
s1 = float(test0.get("gstddev", None)) |
|
s = math.sqrt(s0*s0 + s1*s1) |
|
m0 = math.log(m0) |
|
m1 = math.log(m1) |
|
if s == 0: |
|
return None |
|
return (m0-m1)/s |
|
|
|
metrix_table = \ |
|
{ |
|
"name": ("Name of Test", lambda test,test0,units: str(test)), |
|
|
|
"samples": ("Number of\ncollected samples", lambda test,test0,units: test.get("samples", units)), |
|
"outliers": ("Number of\noutliers", lambda test,test0,units: test.get("outliers", units)), |
|
|
|
"gmean": ("Geometric mean", lambda test,test0,units: test.get("gmean", units)), |
|
"mean": ("Mean", lambda test,test0,units: test.get("mean", units)), |
|
"min": ("Min", lambda test,test0,units: test.get("min", units)), |
|
"median": ("Median", lambda test,test0,units: test.get("median", units)), |
|
"stddev": ("Standard deviation", lambda test,test0,units: test.get("stddev", units)), |
|
"gstddev": ("Standard deviation of Ln(time)", lambda test,test0,units: test.get("gstddev")), |
|
|
|
"gmean%": ("Geometric mean (relative)", lambda test,test0,units: getRelativeVal(test, test0, "gmean")), |
|
"mean%": ("Mean (relative)", lambda test,test0,units: getRelativeVal(test, test0, "mean")), |
|
"min%": ("Min (relative)", lambda test,test0,units: getRelativeVal(test, test0, "min")), |
|
"median%": ("Median (relative)", lambda test,test0,units: getRelativeVal(test, test0, "median")), |
|
"stddev%": ("Standard deviation (relative)", lambda test,test0,units: getRelativeVal(test, test0, "stddev")), |
|
"gstddev%": ("Standard deviation of Ln(time) (relative)", lambda test,test0,units: getRelativeVal(test, test0, "gstddev")), |
|
|
|
"gmean$": ("Geometric mean (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "gmean")), |
|
"mean$": ("Mean (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "mean")), |
|
"min$": ("Min (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "min")), |
|
"median$": ("Median (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "median")), |
|
"stddev$": ("Standard deviation (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "stddev")), |
|
"gstddev$": ("Standard deviation of Ln(time) (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "gstddev")), |
|
|
|
"score": ("SCORE", lambda test,test0,units: getScore(test, test0, "gstddev")), |
|
} |
|
|
|
def formatValue(val, metric, units = None): |
|
if val is None: |
|
return "-" |
|
if metric.endswith("%"): |
|
return "%.2f" % val |
|
if metric.endswith("$"): |
|
return "%.2f%%" % val |
|
if metric.endswith("S"): |
|
if val > 3.5: |
|
return "SLOWER" |
|
if val < -3.5: |
|
return "FASTER" |
|
if val > -1.5 and val < 1.5: |
|
return " " |
|
if val < 0: |
|
return "faster" |
|
if val > 0: |
|
return "slower" |
|
#return "%.4f" % val |
|
if units: |
|
return "%.3f %s" % (val, units) |
|
else: |
|
return "%.3f" % val |
|
|
|
if __name__ == "__main__": |
|
if len(sys.argv) < 2: |
|
print("Usage:\n", os.path.basename(sys.argv[0]), "<log_name>.xml") |
|
exit(0) |
|
|
|
parser = OptionParser() |
|
parser.add_option("-o", "--output", dest="format", help="output results in text format (can be 'txt', 'html', 'markdown' or 'auto' - default)", metavar="FMT", default="auto") |
|
parser.add_option("-m", "--metric", dest="metric", help="output metric", metavar="NAME", default="gmean") |
|
parser.add_option("-u", "--units", dest="units", help="units for output values (s, ms (default), us, ns or ticks)", metavar="UNITS", default="ms") |
|
(options, args) = parser.parse_args() |
|
|
|
options.generateHtml = detectHtmlOutputType(options.format) |
|
if options.metric not in metrix_table: |
|
options.metric = "gmean" |
|
|
|
#print options |
|
#print args |
|
|
|
# tbl = table() |
|
# tbl.newColumn("first", "qqqq", align = "left") |
|
# tbl.newColumn("second", "wwww\nz\nx\n") |
|
# tbl.newColumn("third", "wwasdas") |
|
# |
|
# tbl.newCell(0, "ccc111", align = "right") |
|
# tbl.newCell(1, "dddd1") |
|
# tbl.newCell(2, "8768756754") |
|
# tbl.newRow() |
|
# tbl.newCell(0, "1\n2\n3\n4\n5\n6\n7", align = "center", colspan = 2, rowspan = 2) |
|
# tbl.newCell(2, "xxx\nqqq", align = "center", colspan = 1, valign = "middle") |
|
# tbl.newRow() |
|
# tbl.newCell(2, "+", align = "center", colspan = 1, valign = "middle") |
|
# tbl.newRow() |
|
# tbl.newCell(0, "vcvvbasdsadassdasdasv", align = "right", colspan = 2) |
|
# tbl.newCell(2, "dddd1") |
|
# tbl.newRow() |
|
# tbl.newCell(0, "vcvvbv") |
|
# tbl.newCell(1, "3445324", align = "right") |
|
# tbl.newCell(2, None) |
|
# tbl.newCell(1, "0000") |
|
# if sys.stdout.isatty(): |
|
# tbl.consolePrintTable(sys.stdout) |
|
# else: |
|
# htmlPrintHeader(sys.stdout) |
|
# tbl.htmlPrintTable(sys.stdout) |
|
# htmlPrintFooter(sys.stdout) |
|
|
|
import testlog_parser |
|
|
|
if options.generateHtml: |
|
htmlPrintHeader(sys.stdout, "Tables demo") |
|
|
|
getter = metrix_table[options.metric][1] |
|
|
|
for arg in args: |
|
tests = testlog_parser.parseLogFile(arg) |
|
tbl = table(arg, format=options.format) |
|
tbl.newColumn("name", "Name of Test", align = "left") |
|
tbl.newColumn("value", metrix_table[options.metric][0], align = "center", bold = "true") |
|
|
|
for t in sorted(tests): |
|
tbl.newRow() |
|
tbl.newCell("name", str(t)) |
|
|
|
status = t.get("status") |
|
if status != "run": |
|
tbl.newCell("value", status) |
|
else: |
|
val = getter(t, None, options.units) |
|
if val: |
|
if options.metric.endswith("%"): |
|
tbl.newCell("value", "%.2f" % val, val) |
|
else: |
|
tbl.newCell("value", "%.3f %s" % (val, options.units), val) |
|
else: |
|
tbl.newCell("value", "-") |
|
|
|
if options.generateHtml: |
|
tbl.htmlPrintTable(sys.stdout) |
|
else: |
|
tbl.consolePrintTable(sys.stdout) |
|
|
|
if options.generateHtml: |
|
htmlPrintFooter(sys.stdout)
|
|
|