| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | """Benchmark some basic import use-cases.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The assumption is made that this benchmark is run in a fresh interpreter and | 
					
						
							|  |  |  | thus has no external changes made to import-related attributes in sys. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2012-07-20 14:54:53 -04:00
										 |  |  | from test.test_importlib import util | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  | import decimal | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | import imp | 
					
						
							|  |  |  | import importlib | 
					
						
							| 
									
										
										
										
											2012-05-11 11:12:00 -04:00
										 |  |  | import importlib.machinery | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  | import json | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | import os | 
					
						
							|  |  |  | import py_compile | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  | import tabnanny | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | import timeit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  | def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3): | 
					
						
							|  |  |  |     """Bench the given statement as many times as necessary until total
 | 
					
						
							|  |  |  |     executions take one second."""
 | 
					
						
							|  |  |  |     stmt = "__import__({!r})".format(name) | 
					
						
							|  |  |  |     timer = timeit.Timer(stmt) | 
					
						
							|  |  |  |     for x in range(repeat): | 
					
						
							|  |  |  |         total_time = 0 | 
					
						
							|  |  |  |         count = 0 | 
					
						
							|  |  |  |         while total_time < seconds: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 total_time += timer.timeit(1) | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 cleanup() | 
					
						
							|  |  |  |             count += 1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # One execution too far | 
					
						
							|  |  |  |             if total_time > seconds: | 
					
						
							|  |  |  |                 count -= 1 | 
					
						
							| 
									
										
										
										
											2010-07-15 06:24:04 +00:00
										 |  |  |         yield count // seconds | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def from_cache(seconds, repeat): | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  |     """sys.modules""" | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  |     name = '<benchmark import>' | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  |     module = imp.new_module(name) | 
					
						
							|  |  |  |     module.__file__ = '<test>' | 
					
						
							|  |  |  |     module.__package__ = '' | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  |     with util.uncache(name): | 
					
						
							|  |  |  |         sys.modules[name] = module | 
					
						
							| 
									
										
										
										
											2012-10-01 15:34:31 -07:00
										 |  |  |         yield from bench(name, repeat=repeat, seconds=seconds) | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def builtin_mod(seconds, repeat): | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  |     """Built-in module""" | 
					
						
							|  |  |  |     name = 'errno' | 
					
						
							|  |  |  |     if name in sys.modules: | 
					
						
							|  |  |  |         del sys.modules[name] | 
					
						
							| 
									
										
										
										
											2010-07-15 06:24:04 +00:00
										 |  |  |     # Relying on built-in importer being implicit. | 
					
						
							| 
									
										
										
										
											2012-10-01 15:34:31 -07:00
										 |  |  |     yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                      seconds=seconds) | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def source_wo_bytecode(seconds, repeat): | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  |     """Source w/o bytecode: small""" | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |     sys.dont_write_bytecode = True | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         name = '__importlib_test_benchmark__' | 
					
						
							|  |  |  |         # Clears out sys.modules and puts an entry at the front of sys.path. | 
					
						
							| 
									
										
										
										
											2016-06-30 10:33:17 +03:00
										 |  |  |         with util.create_modules(name) as mapping: | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |             assert not os.path.exists(imp.cache_from_source(mapping[name])) | 
					
						
							| 
									
										
										
										
											2012-05-11 11:12:00 -04:00
										 |  |  |             sys.meta_path.append(importlib.machinery.PathFinder) | 
					
						
							|  |  |  |             loader = (importlib.machinery.SourceFileLoader, | 
					
						
							| 
									
										
										
										
											2016-06-30 10:33:17 +03:00
										 |  |  |                       importlib.machinery.SOURCE_SUFFIXES) | 
					
						
							| 
									
										
										
										
											2012-05-11 11:12:00 -04:00
										 |  |  |             sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader)) | 
					
						
							| 
									
										
										
										
											2012-10-01 15:34:31 -07:00
										 |  |  |             yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                              seconds=seconds) | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |     finally: | 
					
						
							|  |  |  |         sys.dont_write_bytecode = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  | def _wo_bytecode(module): | 
					
						
							|  |  |  |     name = module.__name__ | 
					
						
							|  |  |  |     def benchmark_wo_bytecode(seconds, repeat): | 
					
						
							|  |  |  |         """Source w/o bytecode: {}""" | 
					
						
							|  |  |  |         bytecode_path = imp.cache_from_source(module.__file__) | 
					
						
							|  |  |  |         if os.path.exists(bytecode_path): | 
					
						
							|  |  |  |             os.unlink(bytecode_path) | 
					
						
							|  |  |  |         sys.dont_write_bytecode = True | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2012-10-01 15:34:31 -07:00
										 |  |  |             yield from bench(name, lambda: sys.modules.pop(name), | 
					
						
							|  |  |  |                              repeat=repeat, seconds=seconds) | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  |         finally: | 
					
						
							|  |  |  |             sys.dont_write_bytecode = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     benchmark_wo_bytecode.__doc__ = benchmark_wo_bytecode.__doc__.format(name) | 
					
						
							|  |  |  |     return benchmark_wo_bytecode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | tabnanny_wo_bytecode = _wo_bytecode(tabnanny) | 
					
						
							|  |  |  | decimal_wo_bytecode = _wo_bytecode(decimal) | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def source_writing_bytecode(seconds, repeat): | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  |     """Source writing bytecode: small""" | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |     assert not sys.dont_write_bytecode | 
					
						
							|  |  |  |     name = '__importlib_test_benchmark__' | 
					
						
							| 
									
										
										
										
											2016-06-30 10:33:17 +03:00
										 |  |  |     with util.create_modules(name) as mapping: | 
					
						
							| 
									
										
										
										
											2012-05-11 11:12:00 -04:00
										 |  |  |         sys.meta_path.append(importlib.machinery.PathFinder) | 
					
						
							|  |  |  |         loader = (importlib.machinery.SourceFileLoader, | 
					
						
							| 
									
										
										
										
											2016-06-30 10:33:17 +03:00
										 |  |  |                   importlib.machinery.SOURCE_SUFFIXES) | 
					
						
							| 
									
										
										
										
											2012-05-11 11:12:00 -04:00
										 |  |  |         sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader)) | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |         def cleanup(): | 
					
						
							|  |  |  |             sys.modules.pop(name) | 
					
						
							|  |  |  |             os.unlink(imp.cache_from_source(mapping[name])) | 
					
						
							|  |  |  |         for result in bench(name, cleanup, repeat=repeat, seconds=seconds): | 
					
						
							|  |  |  |             assert not os.path.exists(imp.cache_from_source(mapping[name])) | 
					
						
							|  |  |  |             yield result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  | def _writing_bytecode(module): | 
					
						
							|  |  |  |     name = module.__name__ | 
					
						
							|  |  |  |     def writing_bytecode_benchmark(seconds, repeat): | 
					
						
							|  |  |  |         """Source writing bytecode: {}""" | 
					
						
							|  |  |  |         assert not sys.dont_write_bytecode | 
					
						
							|  |  |  |         def cleanup(): | 
					
						
							|  |  |  |             sys.modules.pop(name) | 
					
						
							|  |  |  |             os.unlink(imp.cache_from_source(module.__file__)) | 
					
						
							| 
									
										
										
										
											2012-10-01 15:34:31 -07:00
										 |  |  |         yield from bench(name, cleanup, repeat=repeat, seconds=seconds) | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     writing_bytecode_benchmark.__doc__ = ( | 
					
						
							|  |  |  |                                 writing_bytecode_benchmark.__doc__.format(name)) | 
					
						
							|  |  |  |     return writing_bytecode_benchmark | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | tabnanny_writing_bytecode = _writing_bytecode(tabnanny) | 
					
						
							|  |  |  | decimal_writing_bytecode = _writing_bytecode(decimal) | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def source_using_bytecode(seconds, repeat): | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  |     """Source w/ bytecode: small""" | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |     name = '__importlib_test_benchmark__' | 
					
						
							| 
									
										
										
										
											2016-06-30 10:33:17 +03:00
										 |  |  |     with util.create_modules(name) as mapping: | 
					
						
							| 
									
										
										
										
											2012-05-11 11:12:00 -04:00
										 |  |  |         sys.meta_path.append(importlib.machinery.PathFinder) | 
					
						
							|  |  |  |         loader = (importlib.machinery.SourceFileLoader, | 
					
						
							| 
									
										
										
										
											2016-06-30 10:33:17 +03:00
										 |  |  |                   importlib.machinery.SOURCE_SUFFIXES) | 
					
						
							| 
									
										
										
										
											2012-05-11 11:12:00 -04:00
										 |  |  |         sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader)) | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |         py_compile.compile(mapping[name]) | 
					
						
							|  |  |  |         assert os.path.exists(imp.cache_from_source(mapping[name])) | 
					
						
							| 
									
										
										
										
											2012-10-01 15:34:31 -07:00
										 |  |  |         yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                          seconds=seconds) | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  | def _using_bytecode(module): | 
					
						
							|  |  |  |     name = module.__name__ | 
					
						
							|  |  |  |     def using_bytecode_benchmark(seconds, repeat): | 
					
						
							|  |  |  |         """Source w/ bytecode: {}""" | 
					
						
							|  |  |  |         py_compile.compile(module.__file__) | 
					
						
							| 
									
										
										
										
											2012-10-01 15:34:31 -07:00
										 |  |  |         yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                          seconds=seconds) | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     using_bytecode_benchmark.__doc__ = ( | 
					
						
							|  |  |  |                                 using_bytecode_benchmark.__doc__.format(name)) | 
					
						
							|  |  |  |     return using_bytecode_benchmark | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | tabnanny_using_bytecode = _using_bytecode(tabnanny) | 
					
						
							|  |  |  | decimal_using_bytecode = _using_bytecode(decimal) | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  | def main(import_, options): | 
					
						
							|  |  |  |     if options.source_file: | 
					
						
							|  |  |  |         with options.source_file: | 
					
						
							|  |  |  |             prev_results = json.load(options.source_file) | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |     else: | 
					
						
							|  |  |  |         prev_results = {} | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  |     __builtins__.__import__ = import_ | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  |     benchmarks = (from_cache, builtin_mod, | 
					
						
							|  |  |  |                   source_writing_bytecode, | 
					
						
							| 
									
										
										
										
											2012-02-07 09:40:33 -05:00
										 |  |  |                   source_wo_bytecode, source_using_bytecode, | 
					
						
							| 
									
										
										
										
											2012-02-07 09:19:12 -05:00
										 |  |  |                   tabnanny_writing_bytecode, | 
					
						
							| 
									
										
										
										
											2012-02-07 09:40:33 -05:00
										 |  |  |                   tabnanny_wo_bytecode, tabnanny_using_bytecode, | 
					
						
							|  |  |  |                   decimal_writing_bytecode, | 
					
						
							|  |  |  |                   decimal_wo_bytecode, decimal_using_bytecode, | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  |     if options.benchmark: | 
					
						
							| 
									
										
										
										
											2012-01-30 19:27:51 -05:00
										 |  |  |         for b in benchmarks: | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  |             if b.__doc__ == options.benchmark: | 
					
						
							| 
									
										
										
										
											2012-01-30 19:27:51 -05:00
										 |  |  |                 benchmarks = [b] | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2019-04-05 00:18:19 -07:00
										 |  |  |             print('Unknown benchmark: {!r}'.format(options.benchmark), | 
					
						
							|  |  |  |                   file=sys.stderr) | 
					
						
							| 
									
										
										
										
											2012-01-30 19:27:51 -05:00
										 |  |  |             sys.exit(1) | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  |     seconds = 1 | 
					
						
							|  |  |  |     seconds_plural = 's' if seconds > 1 else '' | 
					
						
							|  |  |  |     repeat = 3 | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |     header = ('Measuring imports/second over {} second{}, best out of {}\n' | 
					
						
							| 
									
										
										
										
											2012-02-07 09:40:33 -05:00
										 |  |  |               'Entire benchmark run should take about {} seconds\n' | 
					
						
							|  |  |  |               'Using {!r} as __import__\n') | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |     print(header.format(seconds, seconds_plural, repeat, | 
					
						
							| 
									
										
										
										
											2012-02-07 09:40:33 -05:00
										 |  |  |                         len(benchmarks) * seconds * repeat, __import__)) | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |     new_results = {} | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  |     for benchmark in benchmarks: | 
					
						
							|  |  |  |         print(benchmark.__doc__, "[", end=' ') | 
					
						
							|  |  |  |         sys.stdout.flush() | 
					
						
							|  |  |  |         results = [] | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  |         for result in benchmark(seconds=seconds, repeat=repeat): | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  |             results.append(result) | 
					
						
							|  |  |  |             print(result, end=' ') | 
					
						
							|  |  |  |             sys.stdout.flush() | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |         assert not sys.dont_write_bytecode | 
					
						
							| 
									
										
										
										
											2010-07-16 19:26:23 +00:00
										 |  |  |         print("]", "best is", format(max(results), ',d')) | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |         new_results[benchmark.__doc__] = results | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  |     if prev_results: | 
					
						
							|  |  |  |         print('\n\nComparing new vs. old\n') | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |         for benchmark in benchmarks: | 
					
						
							|  |  |  |             benchmark_name = benchmark.__doc__ | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  |             old_result = max(prev_results[benchmark_name]) | 
					
						
							|  |  |  |             new_result = max(new_results[benchmark_name]) | 
					
						
							|  |  |  |             result = '{:,d} vs. {:,d} ({:%})'.format(new_result, | 
					
						
							|  |  |  |                                                      old_result, | 
					
						
							|  |  |  |                                               new_result/old_result) | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |             print(benchmark_name, ':', result) | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  |     if options.dest_file: | 
					
						
							|  |  |  |         with options.dest_file: | 
					
						
							|  |  |  |             json.dump(new_results, options.dest_file, indent=2) | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |     import argparse | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |     parser = argparse.ArgumentParser() | 
					
						
							|  |  |  |     parser.add_argument('-b', '--builtin', dest='builtin', action='store_true', | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  |                         default=False, help="use the built-in __import__") | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  |     parser.add_argument('-r', '--read', dest='source_file', | 
					
						
							|  |  |  |                         type=argparse.FileType('r'), | 
					
						
							|  |  |  |                         help='file to read benchmark data from to compare ' | 
					
						
							|  |  |  |                              'against') | 
					
						
							|  |  |  |     parser.add_argument('-w', '--write', dest='dest_file', | 
					
						
							|  |  |  |                         type=argparse.FileType('w'), | 
					
						
							|  |  |  |                         help='file to write benchmark data to') | 
					
						
							| 
									
										
										
										
											2012-01-30 19:27:51 -05:00
										 |  |  |     parser.add_argument('--benchmark', dest='benchmark', | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  |                         help='specific benchmark to run') | 
					
						
							| 
									
										
										
										
											2012-01-30 19:12:29 -05:00
										 |  |  |     options = parser.parse_args() | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  |     import_ = __import__ | 
					
						
							|  |  |  |     if not options.builtin: | 
					
						
							|  |  |  |         import_ = importlib.__import__ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-23 19:34:35 -05:00
										 |  |  |     main(import_, options) |