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