#!/usr/bin/env python import testlog_parser, sys, os, xml, re from table_formatter import * from optparse import OptionParser cvsize_re = re.compile("^\d+x\d+$") cvtype_re = re.compile("^(CV_)(8U|8S|16U|16S|32S|32F|64F)(C\d{1,3})?$") def keyselector(a): if cvsize_re.match(a): size = [int(d) for d in a.split('x')] return size[0] * size[1] elif cvtype_re.match(a): if a.startswith("CV_"): a = a[3:] depth = 7 if a[0] == '8': depth = (0, 1) [a[1] == 'S'] elif a[0] == '1': depth = (2, 3) [a[2] == 'S'] elif a[2] == 'S': depth = 4 elif a[0] == '3': depth = 5 elif a[0] == '6': depth = 6 cidx = a.find('C') if cidx < 0: channels = 1 else: channels = int(a[a.index('C') + 1:]) #return (depth & 7) + ((channels - 1) << 3) return ((channels-1) & 511) + (depth << 9) return a convert = lambda text: int(text) if text.isdigit() else text alphanum_keyselector = lambda key: [ convert(c) for c in re.split('([0-9]+)', str(keyselector(key))) ] def getValueParams(test): param = test.get("value_param") if not param: return [] if param.startswith("("): param = param[1:] if param.endswith(")"): param = param[:-1] args = [] prev_pos = 0 start = 0 balance = 0 while True: idx = param.find(",", prev_pos) if idx < 0: break idxlb = param.find("(", prev_pos, idx) while idxlb >= 0: balance += 1 idxlb = param.find("(", idxlb+1, idx) idxrb = param.find(")", prev_pos, idx) while idxrb >= 0: balance -= 1 idxrb = param.find(")", idxrb+1, idx) assert(balance >= 0) if balance == 0: args.append(param[start:idx].strip()) start = idx + 1 prev_pos = idx + 1 args.append(param[start:].strip()) return args #return [p.strip() for p in param.split(",")] def nextPermutation(indexes, lists, x, y): idx = len(indexes)-1 while idx >= 0: while idx == x or idx == y: idx -= 1 if idx < 0: return False v = indexes[idx] + 1 if v < len(lists[idx]): indexes[idx] = v; return True; else: indexes[idx] = 0; idx -= 1 return False def getTestWideName(sname, indexes, lists, x, y): name = sname + "::(" for i in range(len(indexes)): if i > 0: name += ", " if i == x: name += "X" elif i == y: name += "Y" else: name += lists[i][indexes[i]] return str(name + ")") def getTest(stests, x, y, row, col): for pair in stests: if pair[1][x] == row and pair[1][y] == col: return pair[0] return None if __name__ == "__main__": parser = OptionParser() parser.add_option("-o", "--output", dest="format", help="output results in text format (can be 'txt', 'html' or 'auto' - default)", metavar="FMT", default="auto") parser.add_option("-u", "--units", dest="units", help="units for output values (s, ms (default), us, ns or ticks)", metavar="UNITS", default="ms") parser.add_option("-m", "--metric", dest="metric", help="output metric", metavar="NAME", default="gmean") parser.add_option("-x", "", dest="x", help="argument number for rows", metavar="ROW", default=1) parser.add_option("-y", "", dest="y", help="argument number for columns", metavar="COL", default=0) parser.add_option("-f", "--filter", dest="filter", help="regex to filter tests", metavar="REGEX", default=None) (options, args) = parser.parse_args() if len(args) != 1: print >> sys.stderr, "Usage:\n", os.path.basename(sys.argv[0]), ".xml" exit(1) options.generateHtml = detectHtmlOutputType(options.format) if options.metric not in metrix_table: options.metric = "gmean" if options.metric.endswith("%"): options.metric = options.metric[:-1] getter = metrix_table[options.metric][1] tests = testlog_parser.parseLogFile(args[0]) if options.filter: expr = re.compile(options.filter) tests = [(t,getValueParams(t)) for t in tests if expr.search(str(t))] else: tests = [(t,getValueParams(t)) for t in tests] args[0] = os.path.basename(args[0]) if not tests: print >> sys.stderr, "Error - no tests matched" exit(1) argsnum = len(tests[0][1]) sname = tests[0][0].shortName() arglists = [] for i in range(argsnum): arglists.append({}) names = set() names1 = set() for pair in tests: sn = pair[0].shortName() if len(pair[1]) > 1: names.add(sn) else: names1.add(sn) if sn == sname: if len(pair[1]) != argsnum: print >> sys.stderr, "Error - unable to create chart tables for functions having different argument numbers" sys.exit(1) for i in range(argsnum): arglists[i][pair[1][i]] = 1 if names1 or len(names) != 1: print >> sys.stderr, "Error - unable to create tables for functions from different test suits:" i = 1 for name in sorted(names): print >> sys.stderr, "%4s: %s" % (i, name) i += 1 if names1: print >> sys.stderr, "Other suits in this log (can not be chosen):" for name in sorted(names1): print >> sys.stderr, "%4s: %s" % (i, name) i += 1 sys.exit(1) if argsnum < 2: print >> sys.stderr, "Error - tests from %s have less than 2 parameters" % sname exit(1) for i in range(argsnum): arglists[i] = sorted([str(key) for key in arglists[i].iterkeys()], key=alphanum_keyselector) if options.generateHtml and options.format != "moinwiki": htmlPrintHeader(sys.stdout, "Report %s for %s" % (args[0], sname)) indexes = [0] * argsnum x = int(options.x) y = int(options.y) if x == y or x < 0 or y < 0 or x >= argsnum or y >= argsnum: x = 1 y = 0 while True: stests = [] for pair in tests: t = pair[0] v = pair[1] for i in range(argsnum): if i != x and i != y: if v[i] != arglists[i][indexes[i]]: t = None break if t: stests.append(pair) tbl = table(metrix_table[options.metric][0] + " for\n" + getTestWideName(sname, indexes, arglists, x, y)) tbl.newColumn("x", "X\Y") for col in arglists[y]: tbl.newColumn(col, col, align="center") for row in arglists[x]: tbl.newRow() tbl.newCell("x", row) for col in arglists[y]: case = getTest(stests, x, y, row, col) if case: status = case.get("status") if status != "run": tbl.newCell(col, status, color = "red") else: val = getter(case, None, options.units) if isinstance(val, float): tbl.newCell(col, "%.2f %s" % (val, options.units), val) else: tbl.newCell(col, val, val) else: tbl.newCell(col, "-") if options.generateHtml: tbl.htmlPrintTable(sys.stdout, options.format == "moinwiki") else: tbl.consolePrintTable(sys.stdout) if not nextPermutation(indexes, arglists, x, y): break if options.generateHtml and options.format != "moinwiki": htmlPrintFooter(sys.stdout)