Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-23 09:34:10

0001 #!/usr/bin/env python3
0002 
0003 """
0004 Collect the json files from individual benchmark tests into
0005 a larger json file that combines all benchmark information,
0006 and do additional accounting for the benchmark.
0007 
0008 Tests results are expected to have the following file name and directory
0009 structure:
0010    results/<BENCHMARK_NAME>/**/<SOME_NAME>.json
0011 where ** implies we check recursively check all sub-directories of <BENCHMARK_NAME>
0012 
0013 Internally, we will look for the "tests" keyword in each of these
0014 files to identify them as benchmark components.
0015 """
0016 
0017 ## Our benchmark definition file, stored in the benchmark root directory
0018 BENCHMARK_FILE=r'benchmarks/{}/benchmark.json'
0019 
0020 ## Our benchmark results directory
0021 RESULTS_PATH=r'results/{}'
0022 
0023 ## Output json file with benchmark results
0024 OUTPUT_FILE=r'results/{}.json'
0025 
0026 import argparse
0027 import json
0028 from pathlib import Path
0029 
0030 ## Exceptions for this module
0031 class Error(Exception):
0032     '''Base class for exceptions in this module.'''
0033     pass
0034 class FileNotFoundError(Exception):
0035     '''File does not exist.
0036 
0037     Attributes:
0038         file: the file name
0039         message: error message
0040     '''
0041     def __init__(self, file):
0042         self.file = file
0043         self.message = 'No such file or directory: {}'.format(file)
0044 
0045 class InvalidBenchmarkDefinitionError(Exception):
0046     '''Raised for missing keys in the benchmark definition.
0047 
0048     Attributes:
0049         key: the missing key
0050         file: the benchmark definition file
0051         message: error message
0052     '''
0053     def __init__(self, key, file):
0054         self.key = key
0055         self.file = file
0056         self.message = "key '{}' not found in benchmark file '{}'".format(key, file)
0057 
0058 class InvalidTestDefinitionError(Exception):
0059     '''Raised for missing keys in the test result.
0060 
0061     Attributes:
0062         key: the missing key
0063         file: the test result file
0064         message: error message
0065     '''
0066     def __init__(self, key, file):
0067         self.key = key
0068         self.file = file
0069         self.message = "key '{}' not found in test file '{}'".format(key, file)
0070 class InvalidTestResultError(Exception):
0071     '''Raised for invalid test result value.
0072 
0073     Attributes:
0074         key: the missing key
0075         value: the invalid value
0076         file: the benchmark definition file
0077         message: error message
0078     '''
0079     def __init__(self, key, value, file):
0080         self.key = key
0081         self.value = value
0082         self.file = file
0083         self.message = "value '{}' for key '{}' invalid in test file '{}'".format(
0084                 value, key, file)
0085     
0086     
0087 parser = argparse.ArgumentParser()
0088 parser.add_argument(
0089         'benchmark',
0090         action='append',
0091         help='One or more benchmarks for which to collect test results.')
0092 
0093 def collect_results(benchmark):
0094     '''Collect benchmark tests and write results to file.'''
0095     print("Collecting results for benchmark '{}'".format(benchmark))
0096 
0097     ## load the test definition for this benchmark
0098     results = _load_benchmark(benchmark)
0099 
0100     ## collect the test results
0101     results['tests'] = _load_tests(benchmark)
0102     
0103     ## calculate aggregate test statistics
0104     results = _aggregate_results(results)
0105 
0106     ## save results to output file
0107     _save(benchmark, results)
0108 
0109     ## Summarize results
0110     _print_summary(results)
0111 
0112 def _load_benchmark(benchmark):
0113     '''Load benchmark definition.'''
0114     benchfile = Path(BENCHMARK_FILE.format(benchmark))
0115     if not benchfile.exists():
0116         raise FileNotFoundError(benchfile)
0117     print('  --> Loading benchmark definition from:', benchfile)
0118     results = None
0119     with benchfile.open() as f:
0120         results = json.load(f)
0121     ## ensure this is a valid benchmark file
0122     for key in ('name', 'title', 'description', 'target'):
0123         if not key in results:
0124             raise InvalidBenchmarkDefinitionError('target', benchfile)
0125     return results
0126 
0127 def _load_tests(benchmark):
0128     '''Loop over all test results in benchmark folder and return results.'''
0129     print('  --> Collecting all test results')
0130     rootdir = Path(RESULTS_PATH.format(benchmark))
0131     results = []
0132     for file in rootdir.glob('**/*.json'):
0133         print('    --> Loading file:', file, '... ', end='')
0134         with open(file) as f:
0135             new_results = json.load(f)
0136             ## skip files that don't include test results
0137             if not 'tests' in new_results:
0138                 print('not a test result')
0139                 continue
0140             ## check if these are valid test results,
0141             ## raise exception otherwise
0142             for test in new_results['tests']:
0143                 for key in ('name', 'title', 'description', 'quantity', 'target',
0144                         'value', 'result'):
0145                     if not key in test:
0146                         raise InvalidTestDefinitionError(key, file)
0147                 if test['result'] not in ('pass', 'fail', 'error'):
0148                     raise InvalidTestResultError('result', test['result'], file)
0149                 ## ensure 'weight' key present, defaulting to 1 in needed
0150                 if not 'weight' in test:
0151                     test['weight'] = 1.
0152                 ## Append to our test results
0153                 results.append(test)
0154             print('done')
0155     return results
0156 
0157 def _aggregate_results(results):
0158     '''Aggregate test results for our benchmark.'''
0159     print('  --> Aggregating benchmark statistics')
0160     results['target'] = float(results['target'])
0161     results['n_tests'] = len(results['tests'])
0162     results['n_pass'] = len([1 for t in results['tests'] if t['result'] == 'pass'])
0163     results['n_fail'] = len([1 for t in results['tests'] if t['result'] == 'fail'])
0164     results['n_error'] = len([1 for t in results['tests'] if t['result'] == 'error'])
0165     results['maximum'] = sum([t['weight'] for t in results['tests']])
0166     results['sum'] = sum([t['weight'] for t in results['tests'] if t['result'] == 'pass'])
0167     if (results['n_tests'] > 0):
0168         results['value'] = results['sum'] / results['maximum']
0169         if results['n_error'] > 0:
0170             results['result'] = 'error'
0171         elif results['value'] >= results['target']:
0172             results['result'] = 'pass'
0173         else:
0174             results['result'] = 'fail'
0175     else:
0176         results['value'] = -1
0177         results['result'] = 'error'
0178     return results
0179 
0180 def _save(benchmark, results):
0181     '''Save benchmark results'''
0182     ofile = Path(OUTPUT_FILE.format(Path(benchmark).name))
0183     print('  --> Saving benchmark results to:', ofile)
0184     with ofile.open('w') as f:
0185         json.dump(results, f, indent=4)
0186 
0187 def _print_summary(results):
0188     '''Print benchmark summary to the terminal.'''
0189     print('====================================================================')
0190     print('Summary for:', results['title'])
0191     print('Pass: {}, Fail: {}, Error: {} out of {} total tests'.format(
0192         results['n_pass'], results['n_fail'], results['n_error'],
0193         results['n_tests']))
0194     print('Weighted sum: {} / {}'.format(results['sum'], results['maximum']))
0195     print('Benchmark value: {} (target: {})'.format(
0196         results['value'], results['target']))
0197     print('===> status:', results['result'])
0198     print('====================================================================')
0199 
0200 
0201 if __name__ == "__main__":
0202     args = parser.parse_args()
0203     for benchmark in args.benchmark:
0204         collect_results(benchmark)