chart.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #!/usr/bin/env python
  2. from __future__ import print_function
  3. import testlog_parser, sys, os, xml, re
  4. from table_formatter import *
  5. from optparse import OptionParser
  6. cvsize_re = re.compile("^\d+x\d+$")
  7. cvtype_re = re.compile("^(CV_)(8U|8S|16U|16S|32S|32F|64F)(C\d{1,3})?$")
  8. def keyselector(a):
  9. if cvsize_re.match(a):
  10. size = [int(d) for d in a.split('x')]
  11. return size[0] * size[1]
  12. elif cvtype_re.match(a):
  13. if a.startswith("CV_"):
  14. a = a[3:]
  15. depth = 7
  16. if a[0] == '8':
  17. depth = (0, 1) [a[1] == 'S']
  18. elif a[0] == '1':
  19. depth = (2, 3) [a[2] == 'S']
  20. elif a[2] == 'S':
  21. depth = 4
  22. elif a[0] == '3':
  23. depth = 5
  24. elif a[0] == '6':
  25. depth = 6
  26. cidx = a.find('C')
  27. if cidx < 0:
  28. channels = 1
  29. else:
  30. channels = int(a[a.index('C') + 1:])
  31. #return (depth & 7) + ((channels - 1) << 3)
  32. return ((channels-1) & 511) + (depth << 9)
  33. return a
  34. convert = lambda text: int(text) if text.isdigit() else text
  35. alphanum_keyselector = lambda key: [ convert(c) for c in re.split('([0-9]+)', str(keyselector(key))) ]
  36. def getValueParams(test):
  37. param = test.get("value_param")
  38. if not param:
  39. return []
  40. if param.startswith("("):
  41. param = param[1:]
  42. if param.endswith(")"):
  43. param = param[:-1]
  44. args = []
  45. prev_pos = 0
  46. start = 0
  47. balance = 0
  48. while True:
  49. idx = param.find(",", prev_pos)
  50. if idx < 0:
  51. break
  52. idxlb = param.find("(", prev_pos, idx)
  53. while idxlb >= 0:
  54. balance += 1
  55. idxlb = param.find("(", idxlb+1, idx)
  56. idxrb = param.find(")", prev_pos, idx)
  57. while idxrb >= 0:
  58. balance -= 1
  59. idxrb = param.find(")", idxrb+1, idx)
  60. assert(balance >= 0)
  61. if balance == 0:
  62. args.append(param[start:idx].strip())
  63. start = idx + 1
  64. prev_pos = idx + 1
  65. args.append(param[start:].strip())
  66. return args
  67. #return [p.strip() for p in param.split(",")]
  68. def nextPermutation(indexes, lists, x, y):
  69. idx = len(indexes)-1
  70. while idx >= 0:
  71. while idx == x or idx == y:
  72. idx -= 1
  73. if idx < 0:
  74. return False
  75. v = indexes[idx] + 1
  76. if v < len(lists[idx]):
  77. indexes[idx] = v;
  78. return True;
  79. else:
  80. indexes[idx] = 0;
  81. idx -= 1
  82. return False
  83. def getTestWideName(sname, indexes, lists, x, y):
  84. name = sname + "::("
  85. for i in range(len(indexes)):
  86. if i > 0:
  87. name += ", "
  88. if i == x:
  89. name += "X"
  90. elif i == y:
  91. name += "Y"
  92. else:
  93. name += lists[i][indexes[i]]
  94. return str(name + ")")
  95. def getTest(stests, x, y, row, col):
  96. for pair in stests:
  97. if pair[1][x] == row and pair[1][y] == col:
  98. return pair[0]
  99. return None
  100. if __name__ == "__main__":
  101. parser = OptionParser()
  102. parser.add_option("-o", "--output", dest="format", help="output results in text format (can be 'txt', 'html' or 'auto' - default)", metavar="FMT", default="auto")
  103. parser.add_option("-u", "--units", dest="units", help="units for output values (s, ms (default), us, ns or ticks)", metavar="UNITS", default="ms")
  104. parser.add_option("-m", "--metric", dest="metric", help="output metric", metavar="NAME", default="gmean")
  105. parser.add_option("-x", "", dest="x", help="argument number for rows", metavar="ROW", default=1)
  106. parser.add_option("-y", "", dest="y", help="argument number for columns", metavar="COL", default=0)
  107. parser.add_option("-f", "--filter", dest="filter", help="regex to filter tests", metavar="REGEX", default=None)
  108. (options, args) = parser.parse_args()
  109. if len(args) != 1:
  110. print("Usage:\n", os.path.basename(sys.argv[0]), "<log_name1>.xml", file=sys.stderr)
  111. exit(1)
  112. options.generateHtml = detectHtmlOutputType(options.format)
  113. if options.metric not in metrix_table:
  114. options.metric = "gmean"
  115. if options.metric.endswith("%"):
  116. options.metric = options.metric[:-1]
  117. getter = metrix_table[options.metric][1]
  118. tests = testlog_parser.parseLogFile(args[0])
  119. if options.filter:
  120. expr = re.compile(options.filter)
  121. tests = [(t,getValueParams(t)) for t in tests if expr.search(str(t))]
  122. else:
  123. tests = [(t,getValueParams(t)) for t in tests]
  124. args[0] = os.path.basename(args[0])
  125. if not tests:
  126. print("Error - no tests matched", file=sys.stderr)
  127. exit(1)
  128. argsnum = len(tests[0][1])
  129. sname = tests[0][0].shortName()
  130. arglists = []
  131. for i in range(argsnum):
  132. arglists.append({})
  133. names = set()
  134. names1 = set()
  135. for pair in tests:
  136. sn = pair[0].shortName()
  137. if len(pair[1]) > 1:
  138. names.add(sn)
  139. else:
  140. names1.add(sn)
  141. if sn == sname:
  142. if len(pair[1]) != argsnum:
  143. print("Error - unable to create chart tables for functions having different argument numbers", file=sys.stderr)
  144. sys.exit(1)
  145. for i in range(argsnum):
  146. arglists[i][pair[1][i]] = 1
  147. if names1 or len(names) != 1:
  148. print("Error - unable to create tables for functions from different test suits:", file=sys.stderr)
  149. i = 1
  150. for name in sorted(names):
  151. print("%4s: %s" % (i, name), file=sys.stderr)
  152. i += 1
  153. if names1:
  154. print("Other suits in this log (can not be chosen):", file=sys.stderr)
  155. for name in sorted(names1):
  156. print("%4s: %s" % (i, name), file=sys.stderr)
  157. i += 1
  158. sys.exit(1)
  159. if argsnum < 2:
  160. print("Error - tests from %s have less than 2 parameters" % sname, file=sys.stderr)
  161. exit(1)
  162. for i in range(argsnum):
  163. arglists[i] = sorted([str(key) for key in arglists[i].iterkeys()], key=alphanum_keyselector)
  164. if options.generateHtml and options.format != "moinwiki":
  165. htmlPrintHeader(sys.stdout, "Report %s for %s" % (args[0], sname))
  166. indexes = [0] * argsnum
  167. x = int(options.x)
  168. y = int(options.y)
  169. if x == y or x < 0 or y < 0 or x >= argsnum or y >= argsnum:
  170. x = 1
  171. y = 0
  172. while True:
  173. stests = []
  174. for pair in tests:
  175. t = pair[0]
  176. v = pair[1]
  177. for i in range(argsnum):
  178. if i != x and i != y:
  179. if v[i] != arglists[i][indexes[i]]:
  180. t = None
  181. break
  182. if t:
  183. stests.append(pair)
  184. tbl = table(metrix_table[options.metric][0] + " for\n" + getTestWideName(sname, indexes, arglists, x, y))
  185. tbl.newColumn("x", "X\Y")
  186. for col in arglists[y]:
  187. tbl.newColumn(col, col, align="center")
  188. for row in arglists[x]:
  189. tbl.newRow()
  190. tbl.newCell("x", row)
  191. for col in arglists[y]:
  192. case = getTest(stests, x, y, row, col)
  193. if case:
  194. status = case.get("status")
  195. if status != "run":
  196. tbl.newCell(col, status, color = "red")
  197. else:
  198. val = getter(case, None, options.units)
  199. if isinstance(val, float):
  200. tbl.newCell(col, "%.2f %s" % (val, options.units), val)
  201. else:
  202. tbl.newCell(col, val, val)
  203. else:
  204. tbl.newCell(col, "-")
  205. if options.generateHtml:
  206. tbl.htmlPrintTable(sys.stdout, options.format == "moinwiki")
  207. else:
  208. tbl.consolePrintTable(sys.stdout)
  209. if not nextPermutation(indexes, arglists, x, y):
  210. break
  211. if options.generateHtml and options.format != "moinwiki":
  212. htmlPrintFooter(sys.stdout)