forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			159 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
| """util.py - General utilities for running, loading, and processing benchmarks
 | |
| """
 | |
| import json
 | |
| import os
 | |
| import tempfile
 | |
| import subprocess
 | |
| import sys
 | |
| 
 | |
| # Input file type enumeration
 | |
| IT_Invalid    = 0
 | |
| IT_JSON       = 1
 | |
| IT_Executable = 2
 | |
| 
 | |
| _num_magic_bytes = 2 if sys.platform.startswith('win') else 4
 | |
| def is_executable_file(filename):
 | |
|     """
 | |
|     Return 'True' if 'filename' names a valid file which is likely
 | |
|     an executable. A file is considered an executable if it starts with the
 | |
|     magic bytes for a EXE, Mach O, or ELF file.
 | |
|     """
 | |
|     if not os.path.isfile(filename):
 | |
|         return False
 | |
|     with open(filename, mode='rb') as f:
 | |
|         magic_bytes = f.read(_num_magic_bytes)
 | |
|     if sys.platform == 'darwin':
 | |
|         return magic_bytes in [
 | |
|             b'\xfe\xed\xfa\xce',  # MH_MAGIC
 | |
|             b'\xce\xfa\xed\xfe',  # MH_CIGAM
 | |
|             b'\xfe\xed\xfa\xcf',  # MH_MAGIC_64
 | |
|             b'\xcf\xfa\xed\xfe',  # MH_CIGAM_64
 | |
|             b'\xca\xfe\xba\xbe',  # FAT_MAGIC
 | |
|             b'\xbe\xba\xfe\xca'   # FAT_CIGAM
 | |
|         ]
 | |
|     elif sys.platform.startswith('win'):
 | |
|         return magic_bytes == b'MZ'
 | |
|     else:
 | |
|         return magic_bytes == b'\x7FELF'
 | |
| 
 | |
| 
 | |
| def is_json_file(filename):
 | |
|     """
 | |
|     Returns 'True' if 'filename' names a valid JSON output file.
 | |
|     'False' otherwise.
 | |
|     """
 | |
|     try:
 | |
|         with open(filename, 'r') as f:
 | |
|             json.load(f)
 | |
|         return True
 | |
|     except:
 | |
|         pass
 | |
|     return False
 | |
| 
 | |
| 
 | |
| def classify_input_file(filename):
 | |
|     """
 | |
|     Return a tuple (type, msg) where 'type' specifies the classified type
 | |
|     of 'filename'. If 'type' is 'IT_Invalid' then 'msg' is a human readable
 | |
|     string represeting the error.
 | |
|     """
 | |
|     ftype = IT_Invalid
 | |
|     err_msg = None
 | |
|     if not os.path.exists(filename):
 | |
|         err_msg = "'%s' does not exist" % filename
 | |
|     elif not os.path.isfile(filename):
 | |
|         err_msg = "'%s' does not name a file" % filename
 | |
|     elif is_executable_file(filename):
 | |
|         ftype = IT_Executable
 | |
|     elif is_json_file(filename):
 | |
|         ftype = IT_JSON
 | |
|     else:
 | |
|         err_msg = "'%s' does not name a valid benchmark executable or JSON file" % filename
 | |
|     return ftype, err_msg
 | |
| 
 | |
| 
 | |
| def check_input_file(filename):
 | |
|     """
 | |
|     Classify the file named by 'filename' and return the classification.
 | |
|     If the file is classified as 'IT_Invalid' print an error message and exit
 | |
|     the program.
 | |
|     """
 | |
|     ftype, msg = classify_input_file(filename)
 | |
|     if ftype == IT_Invalid:
 | |
|         print("Invalid input file: %s" % msg)
 | |
|         sys.exit(1)
 | |
|     return ftype
 | |
| 
 | |
| def find_benchmark_flag(prefix, benchmark_flags):
 | |
|     """
 | |
|     Search the specified list of flags for a flag matching `<prefix><arg>` and
 | |
|     if it is found return the arg it specifies. If specified more than once the
 | |
|     last value is returned. If the flag is not found None is returned.
 | |
|     """
 | |
|     assert prefix.startswith('--') and prefix.endswith('=')
 | |
|     result = None
 | |
|     for f in benchmark_flags:
 | |
|         if f.startswith(prefix):
 | |
|             result = f[len(prefix):]
 | |
|     return result
 | |
| 
 | |
| def remove_benchmark_flags(prefix, benchmark_flags):
 | |
|     """
 | |
|     Return a new list containing the specified benchmark_flags except those
 | |
|     with the specified prefix.
 | |
|     """
 | |
|     assert prefix.startswith('--') and prefix.endswith('=')
 | |
|     return [f for f in benchmark_flags if not f.startswith(prefix)]
 | |
| 
 | |
| def load_benchmark_results(fname):
 | |
|     """
 | |
|     Read benchmark output from a file and return the JSON object.
 | |
|     REQUIRES: 'fname' names a file containing JSON benchmark output.
 | |
|     """
 | |
|     with open(fname, 'r') as f:
 | |
|         return json.load(f)
 | |
| 
 | |
| 
 | |
| def run_benchmark(exe_name, benchmark_flags):
 | |
|     """
 | |
|     Run a benchmark specified by 'exe_name' with the specified
 | |
|     'benchmark_flags'. The benchmark is run directly as a subprocess to preserve
 | |
|     real time console output.
 | |
|     RETURNS: A JSON object representing the benchmark output
 | |
|     """
 | |
|     output_name = find_benchmark_flag('--benchmark_out=',
 | |
|                                       benchmark_flags)
 | |
|     is_temp_output = False
 | |
|     if output_name is None:
 | |
|         is_temp_output = True
 | |
|         thandle, output_name = tempfile.mkstemp()
 | |
|         os.close(thandle)
 | |
|         benchmark_flags = list(benchmark_flags) + \
 | |
|                           ['--benchmark_out=%s' % output_name]
 | |
| 
 | |
|     cmd = [exe_name] + benchmark_flags
 | |
|     print("RUNNING: %s" % ' '.join(cmd))
 | |
|     exitCode = subprocess.call(cmd)
 | |
|     if exitCode != 0:
 | |
|         print('TEST FAILED...')
 | |
|         sys.exit(exitCode)
 | |
|     json_res = load_benchmark_results(output_name)
 | |
|     if is_temp_output:
 | |
|         os.unlink(output_name)
 | |
|     return json_res
 | |
| 
 | |
| 
 | |
| def run_or_load_benchmark(filename, benchmark_flags):
 | |
|     """
 | |
|     Get the results for a specified benchmark. If 'filename' specifies
 | |
|     an executable benchmark then the results are generated by running the
 | |
|     benchmark. Otherwise 'filename' must name a valid JSON output file,
 | |
|     which is loaded and the result returned.
 | |
|     """
 | |
|     ftype = check_input_file(filename)
 | |
|     if ftype == IT_JSON:
 | |
|         return load_benchmark_results(filename)
 | |
|     elif ftype == IT_Executable:
 | |
|         return run_benchmark(filename, benchmark_flags)
 | |
|     else:
 | |
|         assert False # This branch is unreachable |