report.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #!/usr/bin/env python
  2. """ Print performance test run statistics.
  3. Performance data is stored in the GTest log file created by performance tests. Default name is
  4. `test_details.xml`. It can be changed with the `--gtest_output=xml:<location>/<filename>.xml` test
  5. option. See https://github.com/opencv/opencv/wiki/HowToUsePerfTests for more details.
  6. This script produces configurable performance report tables in text and HTML formats. It allows to
  7. filter test cases by name and parameter string and select specific performance metrics columns. One
  8. or multiple test results can be used for input.
  9. ### Example
  10. ./report.py -c min,mean,median -f '(LUT|Match).*640' opencv_perf_core.xml opencv_perf_features2d.xml
  11. opencv_perf_features2d.xml, opencv_perf_core.xml
  12. Name of Test Min Mean Median
  13. KnnMatch::OCL_BruteForceMatcherFixture::(640x480, 32FC1) 1365.04 ms 1368.18 ms 1368.52 ms
  14. LUT::OCL_LUTFixture::(640x480, 32FC1) 2.57 ms 2.62 ms 2.64 ms
  15. LUT::OCL_LUTFixture::(640x480, 32FC4) 21.15 ms 21.25 ms 21.24 ms
  16. LUT::OCL_LUTFixture::(640x480, 8UC1) 2.22 ms 2.28 ms 2.29 ms
  17. LUT::OCL_LUTFixture::(640x480, 8UC4) 19.12 ms 19.24 ms 19.19 ms
  18. LUT::SizePrm::640x480 2.22 ms 2.27 ms 2.29 ms
  19. Match::OCL_BruteForceMatcherFixture::(640x480, 32FC1) 1364.15 ms 1367.73 ms 1365.45 ms
  20. RadiusMatch::OCL_BruteForceMatcherFixture::(640x480, 32FC1) 1372.68 ms 1375.52 ms 1375.42 ms
  21. ### Options
  22. -o FMT, --output=FMT - output results in text format (can be 'txt', 'html' or 'auto' - default)
  23. -u UNITS, --units=UNITS - units for output values (s, ms (default), us, ns or ticks)
  24. -c COLS, --columns=COLS - comma-separated list of columns to show
  25. -f REGEX, --filter=REGEX - regex to filter tests
  26. --show-all - also include empty and "notrun" lines
  27. """
  28. from __future__ import print_function
  29. import testlog_parser, sys, os, xml, re, glob
  30. from table_formatter import *
  31. from optparse import OptionParser
  32. if __name__ == "__main__":
  33. parser = OptionParser()
  34. parser.add_option("-o", "--output", dest="format", help="output results in text format (can be 'txt', 'html' or 'auto' - default)", metavar="FMT", default="auto")
  35. parser.add_option("-u", "--units", dest="units", help="units for output values (s, ms (default), us, ns or ticks)", metavar="UNITS", default="ms")
  36. parser.add_option("-c", "--columns", dest="columns", help="comma-separated list of columns to show", metavar="COLS", default="")
  37. parser.add_option("-f", "--filter", dest="filter", help="regex to filter tests", metavar="REGEX", default=None)
  38. parser.add_option("", "--show-all", action="store_true", dest="showall", default=False, help="also include empty and \"notrun\" lines")
  39. (options, args) = parser.parse_args()
  40. if len(args) < 1:
  41. print("Usage:\n", os.path.basename(sys.argv[0]), "<log_name1>.xml", file=sys.stderr)
  42. exit(0)
  43. options.generateHtml = detectHtmlOutputType(options.format)
  44. # expand wildcards and filter duplicates
  45. files = []
  46. files1 = []
  47. for arg in args:
  48. if ("*" in arg) or ("?" in arg):
  49. files1.extend([os.path.abspath(f) for f in glob.glob(arg)])
  50. else:
  51. files.append(os.path.abspath(arg))
  52. seen = set()
  53. files = [ x for x in files if x not in seen and not seen.add(x)]
  54. files.extend((set(files1) - set(files)))
  55. args = files
  56. # load test data
  57. tests = []
  58. files = []
  59. for arg in set(args):
  60. try:
  61. cases = testlog_parser.parseLogFile(arg)
  62. if cases:
  63. files.append(os.path.basename(arg))
  64. tests.extend(cases)
  65. except:
  66. pass
  67. if options.filter:
  68. expr = re.compile(options.filter)
  69. tests = [t for t in tests if expr.search(str(t))]
  70. tbl = table(", ".join(files))
  71. if options.columns:
  72. metrics = [s.strip() for s in options.columns.split(",")]
  73. metrics = [m for m in metrics if m and not m.endswith("%") and m in metrix_table]
  74. else:
  75. metrics = None
  76. if not metrics:
  77. metrics = ["name", "samples", "outliers", "min", "median", "gmean", "mean", "stddev"]
  78. if "name" not in metrics:
  79. metrics.insert(0, "name")
  80. for m in metrics:
  81. if m == "name":
  82. tbl.newColumn(m, metrix_table[m][0])
  83. else:
  84. tbl.newColumn(m, metrix_table[m][0], align = "center")
  85. needNewRow = True
  86. for case in sorted(tests, key=lambda x: str(x)):
  87. if needNewRow:
  88. tbl.newRow()
  89. if not options.showall:
  90. needNewRow = False
  91. status = case.get("status")
  92. if status != "run":
  93. if status != "notrun":
  94. needNewRow = True
  95. for m in metrics:
  96. if m == "name":
  97. tbl.newCell(m, str(case))
  98. else:
  99. tbl.newCell(m, status, color = "red")
  100. else:
  101. needNewRow = True
  102. for m in metrics:
  103. val = metrix_table[m][1](case, None, options.units)
  104. if isinstance(val, float):
  105. tbl.newCell(m, "%.2f %s" % (val, options.units), val)
  106. else:
  107. tbl.newCell(m, val, val)
  108. if not needNewRow:
  109. tbl.trimLastRow()
  110. # output table
  111. if options.generateHtml:
  112. if options.format == "moinwiki":
  113. tbl.htmlPrintTable(sys.stdout, True)
  114. else:
  115. htmlPrintHeader(sys.stdout, "Report %s tests from %s" % (len(tests), ", ".join(files)))
  116. tbl.htmlPrintTable(sys.stdout)
  117. htmlPrintFooter(sys.stdout)
  118. else:
  119. tbl.consolePrintTable(sys.stdout)