115 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
 | |
| 
 | |
| from __future__ import division, unicode_literals, print_function, absolute_import
 | |
| 
 | |
| import fnmatch
 | |
| import os
 | |
| import copy
 | |
| from timeit import Timer
 | |
| 
 | |
| import yaml
 | |
| 
 | |
| 
 | |
| def time_stmt(stmt='pass', setup='pass', number=0, repeat=3):
 | |
|     """Timer function with the same behaviour as running `python -m timeit `
 | |
|     in the command line.
 | |
| 
 | |
|     :return: elapsed time in seconds or NaN if the command failed.
 | |
|     :rtype: float
 | |
|     """
 | |
| 
 | |
|     t = Timer(stmt, setup)
 | |
| 
 | |
|     if not number:
 | |
|         # determine number so that 0.2 <= total time < 2.0
 | |
|         for i in range(1, 10):
 | |
|             number = 10**i
 | |
| 
 | |
|             try:
 | |
|                 x = t.timeit(number)
 | |
|             except:
 | |
|                 print(t.print_exc())
 | |
|                 return float('NaN')
 | |
| 
 | |
|             if x >= 0.2:
 | |
|                 break
 | |
| 
 | |
|     try:
 | |
|         r = t.repeat(repeat, number)
 | |
|     except:
 | |
|         print(t.print_exc())
 | |
|         return float('NaN')
 | |
| 
 | |
|     best = min(r)
 | |
| 
 | |
|     return best / number
 | |
| 
 | |
| 
 | |
| def build_task(task, name='', setup='', number=0, repeat=3):
 | |
|     nt = copy.copy(task)
 | |
| 
 | |
|     nt['name'] = (name + ' ' + task.get('name', '')).strip()
 | |
|     nt['setup'] = (setup + '\n' + task.get('setup', '')).strip('\n')
 | |
|     nt['stmt'] = task.get('stmt', '')
 | |
|     nt['number'] = task.get('number', number)
 | |
|     nt['repeat'] = task.get('repeat', repeat)
 | |
| 
 | |
|     return nt
 | |
| 
 | |
| 
 | |
| def time_task(name, stmt='pass', setup='pass', number=0, repeat=3, stmts='', base=''):
 | |
| 
 | |
|     if base:
 | |
|         nvalue = time_stmt(stmt=base, setup=setup, number=number, repeat=repeat)
 | |
|         yield name + ' (base)', nvalue
 | |
|         suffix = ' (normalized)'
 | |
|     else:
 | |
|         nvalue = 1.
 | |
|         suffix = ''
 | |
| 
 | |
|     if stmt:
 | |
|         value = time_stmt(stmt=stmt, setup=setup, number=number, repeat=repeat)
 | |
|         yield name, value / nvalue
 | |
| 
 | |
|     for task in stmts:
 | |
|         new_task = build_task(task, name, setup, number, repeat)
 | |
|         for task_name, value in time_task(**new_task):
 | |
|             yield task_name + suffix, value / nvalue
 | |
| 
 | |
| 
 | |
| def time_file(filename, name='', setup='', number=0, repeat=3):
 | |
|     """Open a yaml benchmark file an time each statement,
 | |
| 
 | |
|     yields a tuple with filename, task name, time in seconds.
 | |
|     """
 | |
|     with open(filename, 'r') as fp:
 | |
|         tasks = yaml.load(fp)
 | |
| 
 | |
|     for task in tasks:
 | |
|         new_task = build_task(task, name, setup, number, repeat)
 | |
|         for task_name, value in time_task(**new_task):
 | |
|             yield task_name, value
 | |
| 
 | |
| 
 | |
| def recursive_glob(rootdir='.', pattern='*'):
 | |
|     return [os.path.join(looproot, filename)
 | |
|             for looproot, _, filenames in os.walk(rootdir)
 | |
|             for filename in filenames
 | |
|             if fnmatch.fnmatch(filename, pattern)]
 | |
| 
 | |
| def main(filenames=None):
 | |
|     if not filenames:
 | |
|         filenames = recursive_glob('.', 'bench_*.yaml')
 | |
|     elif isinstance(filenames, basestring):
 | |
|         filenames = [filenames, ]
 | |
| 
 | |
|     for filename in filenames:
 | |
|         print(filename)
 | |
|         print('-' * len(filename))
 | |
|         print()
 | |
|         for task_name, value in time_file(filename):
 | |
|             print('%.2e   %s' % (value, task_name))
 | |
|         print()
 | |
| 
 | |
| main()
 | 
