Changeset 97267 in vbox for trunk/src/VBox/ValidationKit/analysis/analyze.py
- Timestamp:
- Oct 24, 2022 12:09:44 AM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/analysis/analyze.py
r97266 r97267 40 40 __version__ = "$Revision$" 41 41 42 43 import os.path 44 import sys 42 # Standard python imports. 43 import re; 44 import os; 45 import textwrap; 46 import sys; 45 47 46 48 # Only the main script needs to modify the path. … … 51 53 52 54 # Validation Kit imports. 53 from analysis import reader ## @todo fix testanalysis/__init__.py.55 from analysis import reader 54 56 from analysis import reporting 55 #from analysis import diff56 57 57 58 58 59 def usage(): 59 """ Display usage """ 60 print('usage: %s [options] <test1.xml/txt> <test2.xml/txt> [..] [-- <baseline1.file> [baseline2.file] [..]]' 61 % (sys.argv[0])); 62 print('') 63 print('options:') 64 print(' --filter <test-sub-string>') 60 """ 61 Display usage. 62 """ 63 # Set up the output wrapper. 64 try: cCols = os.get_terminal_size()[0] # since 3.3 65 except: cCols = 79; 66 oWrapper = textwrap.TextWrapper(width = cCols); 67 68 # Do the outputting. 69 print('Tool for comparing test results.'); 70 print(''); 71 oWrapper.subsequent_indent = ' ' * (len('usage: ') + 4); 72 print(oWrapper.fill('usage: analyze.py [options] [collection-1] -- [collection-2] [-- [collection3] [..]])')) 73 oWrapper.subsequent_indent = ''; 74 print(''); 75 print(oWrapper.fill('This tool compares two or more result collections, using one as a baseline (first by default) ' 76 'and showing how the results in others differs from it.')); 77 print(''); 78 print(oWrapper.fill('The results (XML file) from one or more test runs makes up a collection. A collection can be ' 79 'named using the --name <name> option, or will get a sequential name automatically. The baseline ' 80 'collection will have "(baseline)" appended to its name.')); 81 print(''); 82 print(oWrapper.fill('A test run produces one XML file, either via the testdriver/reporter.py machinery or via the IPRT ' 83 'test.cpp code. In the latter case it can be enabled and controlled via IPRT_TEST_FILE. A collection ' 84 'consists of one or more of test runs (i.e. XML result files). These are combined (aka distilled) ' 85 'into a single set of results before comparing them with the others. The --best and --avg options ' 86 'controls how this combining is done. The need for this is mainly to try counteract some of the ' 87 'instability typically found in the restuls. Just because one test run produces a better result ' 88 'after a change does not necessarily mean this will always be the case and that the change was to ' 89 'the better, it might just have been regular fluctuations in the test results.')); 90 91 oWrapper.initial_indent = ' '; 92 oWrapper.subsequent_indent = ' '; 93 print(''); 94 print('Options governing combining (distillation):'); 95 print(' --avg, --average'); 96 print(oWrapper.fill('Picks the best result by calculating the average values across all the runs.')); 97 print(''); 98 print(' --best'); 99 print(oWrapper.fill('Picks the best result from all the runs. For values, this means making guessing what result is ' 100 'better based on the unit. This may not always lead to the right choices.')); 101 print(oWrapper.initial_indent + 'Default: --best'); 102 103 print(''); 104 print('Options relating to collections:'); 105 print(' --name <name>'); 106 print(oWrapper.fill('Sets the name of the current collection. By default a collection gets a sequential number.')); 107 print(''); 108 print(' --baseline <num>'); 109 print(oWrapper.fill('Sets collection given by <num> (0-based) as the baseline collection.')); 110 print(oWrapper.initial_indent + 'Default: --baseline 0') 111 112 print(''); 113 print('Filtering options:'); 114 print(' --filter-test <substring>'); 115 print(oWrapper.fill('Exclude tests not containing any of the substrings given via the --filter-test option. The ' 116 'matching is done with full test name, i.e. all parent names are prepended with ", " as separator ' 117 '(for example "tstIOInstr, CPUID EAX=1").')); 118 print(''); 119 print(' --filter-test-out <substring>'); 120 print(oWrapper.fill('Exclude tests containing the given substring. As with --filter-test, the matching is done against ' 121 'the full test name.')); 122 print(''); 123 print(' --filter-value <substring>'); 124 print(oWrapper.fill('Exclude values not containing any of the substrings given via the --filter-value option. The ' 125 'matching is done against the value name prefixed by the full test name and ": " ' 126 '(for example "tstIOInstr, CPUID EAX=1: real mode, CPUID").')); 127 print(''); 128 print(' --filter-value-out <substring>'); 129 print(oWrapper.fill('Exclude value containing the given substring. As with --filter-value, the matching is done against ' 130 'the value name prefixed by the full test name.')); 131 132 print(''); 133 print(' --regex-test <expr>'); 134 print(oWrapper.fill('Same as --filter-test except the substring matching is done via a regular expression.')); 135 print(''); 136 print(' --regex-test-out <expr>'); 137 print(oWrapper.fill('Same as --filter-test-out except the substring matching is done via a regular expression.')); 138 print(''); 139 print(' --regex-value <expr>'); 140 print(oWrapper.fill('Same as --filter-value except the substring matching is done via a regular expression.')); 141 print(''); 142 print(' --regex-value-out <expr>'); 143 print(oWrapper.fill('Same as --filter-value-out except the substring matching is done via a regular expression.')); 144 print(''); 145 print(' --filter-out-empty-leaf-tests'); 146 print(oWrapper.fill('Removes any leaf tests that are without any values or sub-tests. This is useful when ' 147 'only considering values, especially when doing additional value filtering.')); 148 149 print(''); 150 print('Output options:'); 151 print(' --brief, --verbose'); 152 print(oWrapper.fill('Whether to omit (--brief) the value for non-baseline runs and just get along with the difference.')); 153 print(oWrapper.initial_indent + 'Default: --brief'); 154 print(''); 155 print(' --pct <num>, --pct-precision <num>'); 156 print(oWrapper.fill('Specifies the number of decimal place to use when formatting the difference as percent.')); 157 print(oWrapper.initial_indent + 'Default: --pct 2'); 65 158 return 1; 159 66 160 67 161 class ResultCollection(object): … … 94 188 def filterTests(self, asFilters): 95 189 """ 96 Filters all the test trees using asFilters.190 Keeps all the tests in the test trees sub-string matching asFilters (str or re). 97 191 """ 98 192 for oTestTree in self.aoTestTrees: 99 193 oTestTree.filterTests(asFilters); 194 return self; 195 196 def filterOutTests(self, asFilters): 197 """ 198 Removes all the tests in the test trees sub-string matching asFilters (str or re). 199 """ 200 for oTestTree in self.aoTestTrees: 201 oTestTree.filterOutTests(asFilters); 202 return self; 203 204 def filterValues(self, asFilters): 205 """ 206 Keeps all the tests in the test trees sub-string matching asFilters (str or re). 207 """ 208 for oTestTree in self.aoTestTrees: 209 oTestTree.filterValues(asFilters); 210 return self; 211 212 def filterOutValues(self, asFilters): 213 """ 214 Removes all the tests in the test trees sub-string matching asFilters (str or re). 215 """ 216 for oTestTree in self.aoTestTrees: 217 oTestTree.filterOutValues(asFilters); 218 return self; 219 220 def filterOutEmptyLeafTests(self): 221 """ 222 Removes all the tests in the test trees that have neither child tests nor values. 223 """ 224 for oTestTree in self.aoTestTrees: 225 oTestTree.filterOutEmptyLeafTests(); 100 226 return self; 101 227 … … 145 271 146 272 273 # matchWithValue hacks. 274 g_asOptions = []; 275 g_iOptInd = 1; 276 g_sOptArg = ''; 277 278 def matchWithValue(sOption): 279 """ Matches an option with a value, placing the value in g_sOptArg if it matches. """ 280 global g_asOptions, g_iOptInd, g_sOptArg; 281 sArg = g_asOptions[g_iOptInd]; 282 if sArg.startswith(sOption): 283 if len(sArg) == len(sOption): 284 if g_iOptInd + 1 < len(g_asOptions): 285 g_iOptInd += 1; 286 g_sOptArg = g_asOptions[g_iOptInd]; 287 return True; 288 289 print('syntax error: Option %s takes a value!' % (sOption,)); 290 raise Exception('syntax error: Option %s takes a value!' % (sOption,)); 291 292 if sArg[len(sOption)] in ('=', ':'): 293 g_sOptArg = sArg[len(sOption) + 1:]; 294 return True; 295 return False; 147 296 148 297 … … 152 301 # Parse arguments 153 302 # 154 oCurCollection = ResultCollection('#0'); 155 aoCollections = [ oCurCollection, ]; 156 iBaseline = 0; 157 sDistillationMethod = 'best'; 158 fBrief = True; 159 cPctPrecision = 2; 160 asFilters = []; 161 162 iArg = 1; 163 while iArg < len(asArgs): 164 #print("dbg: iArg=%s '%s'" % (iArg, asArgs[iArg],)); 165 if asArgs[iArg].startswith('--help'): 303 oCurCollection = ResultCollection('#0'); 304 aoCollections = [ oCurCollection, ]; 305 iBaseline = 0; 306 sDistillationMethod = 'best'; 307 fBrief = True; 308 cPctPrecision = 2; 309 asTestFilters = []; 310 asTestOutFilters = []; 311 asValueFilters = []; 312 asValueOutFilters = []; 313 fFilterOutEmptyLeafTest = True; 314 315 global g_asOptions, g_iOptInd, g_sOptArg; 316 g_asOptions = asArgs; 317 g_iOptInd = 1; 318 while g_iOptInd < len(asArgs): 319 sArg = asArgs[g_iOptInd]; 320 g_sOptArg = ''; 321 #print("dbg: g_iOptInd=%s '%s'" % (g_iOptInd, sArg,)); 322 323 if sArg.startswith('--help'): 166 324 return usage(); 167 if asArgs[iArg] == '--filter': 168 iArg += 1; 169 asFilters.append(asArgs[iArg]); 170 elif asArgs[iArg] == '--best': 325 326 if matchWithValue('--filter-test'): 327 asTestFilters.append(g_sOptArg); 328 elif matchWithValue('--filter-test-out'): 329 asTestOutFilters.append(g_sOptArg); 330 elif matchWithValue('--filter-value'): 331 asValueFilters.append(g_sOptArg); 332 elif matchWithValue('--filter-value-out'): 333 asValueOutFilters.append(g_sOptArg); 334 335 elif matchWithValue('--regex-test'): 336 asTestFilters.append(re.compile(g_sOptArg)); 337 elif matchWithValue('--regex-test-out'): 338 asTestOutFilters.append(re.compile(g_sOptArg)); 339 elif matchWithValue('--regex-value'): 340 asValueFilters.append(re.compile(g_sOptArg)); 341 elif matchWithValue('--regex-value-out'): 342 asValueOutFilters.append(re.compile(g_sOptArg)); 343 344 elif sArg == '--filter-out-empty-leaf-tests': 345 fFilterOutEmptyLeafTest = True; 346 elif sArg == '--no-filter-out-empty-leaf-tests': 347 fFilterOutEmptyLeafTest = False; 348 349 elif sArg == '--best': 171 350 sDistillationMethod = 'best'; 172 elif asArgs[iArg]in ('--avg', '--average'):351 elif sArg in ('--avg', '--average'): 173 352 sDistillationMethod = 'avg'; 174 elif asArgs[iArg] == '--brief': 353 354 elif sArg == '--brief': 175 355 fBrief = True; 176 elif asArgs[iArg]== '--verbose':356 elif sArg == '--verbose': 177 357 fBrief = False; 178 elif asArgs[iArg] in ('--pct', '--pct-precision'): 179 iArg += 1;180 cPctPrecision = int( asArgs[iArg]);181 elif asArgs[iArg] in ('--base','--baseline'):182 i Arg += 1;183 iBaseline = int(asArgs[iArg]); 358 359 elif matchWithValue('--pct') or matchWithValue('--pct-precision'): 360 cPctPrecision = int(g_sOptArg); 361 elif matchWithValue('--base') or matchWithValue('--baseline'): 362 iBaseline = int(g_sOptArg); 363 184 364 # '--' starts a new collection. If current one is empty, drop it. 185 elif asArgs[iArg]== '--':365 elif sArg == '--': 186 366 print("dbg: new collection"); 187 367 #if oCurCollection.isEmpty(): … … 189 369 oCurCollection = ResultCollection("#%s" % (len(aoCollections),)); 190 370 aoCollections.append(oCurCollection); 371 191 372 # Name the current result collection. 192 elif asArgs[iArg] == '--name':193 iArg += 1;194 oCurCollection.sName = asArgs[iArg]; 373 elif matchWithValue('--name'): 374 oCurCollection.sName = g_sOptArg; 375 195 376 # Read in a file and add it to the current data set. 196 377 else: 197 if not oCurCollection.append( asArgs[iArg]):378 if not oCurCollection.append(sArg): 198 379 return 1; 199 iArg+= 1;380 g_iOptInd += 1; 200 381 201 382 # … … 218 399 219 400 # 220 # Apply filtering before distilling each collection into a single result 221 # tree and comparing them to the first one. 222 # 223 if asFilters: 401 # Apply filtering before distilling each collection into a single result tree. 402 # 403 if asTestFilters: 224 404 for oCollection in aoCollections: 225 oCollection.filterTests(asFilters); 226 405 oCollection.filterTests(asTestFilters); 406 if asTestOutFilters: 407 for oCollection in aoCollections: 408 oCollection.filterOutTests(asTestOutFilters); 409 410 if asValueFilters: 411 for oCollection in aoCollections: 412 oCollection.filterValues(asValueFilters); 413 if asValueOutFilters: 414 for oCollection in aoCollections: 415 oCollection.filterOutValues(asValueOutFilters); 416 417 if fFilterOutEmptyLeafTest: 418 for oCollection in aoCollections: 419 oCollection.filterOutEmptyLeafTests(); 420 421 # Distillation. 227 422 for oCollection in aoCollections: 228 423 oCollection.distill(sDistillationMethod);
Note:
See TracChangeset
for help on using the changeset viewer.