| 
									
										
										
										
											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. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | from . import util | 
					
						
							|  |  |  | from .source import util as source_util | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  | import decimal | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | import imp | 
					
						
							|  |  |  | import importlib | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | import os | 
					
						
							|  |  |  | import py_compile | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | import sys | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |         for result in bench(name, repeat=repeat, seconds=seconds): | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  |             yield result | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |     for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                         seconds=seconds): | 
					
						
							| 
									
										
										
										
											2009-09-03 20:45:21 +00:00
										 |  |  |         yield result | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def source_wo_bytecode(seconds, repeat): | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  |     """Source w/o bytecode: simple""" | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							|  |  |  |         with source_util.create_modules(name) as mapping: | 
					
						
							|  |  |  |             assert not os.path.exists(imp.cache_from_source(mapping[name])) | 
					
						
							|  |  |  |             for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                                 seconds=seconds): | 
					
						
							|  |  |  |                 yield result | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         sys.dont_write_bytecode = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  | def decimal_wo_bytecode(seconds, repeat): | 
					
						
							|  |  |  |     """Source w/o bytecode: decimal""" | 
					
						
							|  |  |  |     name = 'decimal' | 
					
						
							|  |  |  |     decimal_bytecode = imp.cache_from_source(decimal.__file__) | 
					
						
							|  |  |  |     if os.path.exists(decimal_bytecode): | 
					
						
							|  |  |  |         os.unlink(decimal_bytecode) | 
					
						
							|  |  |  |     sys.dont_write_bytecode = True | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                             seconds=seconds): | 
					
						
							|  |  |  |             yield result | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         sys.dont_write_bytecode = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def source_writing_bytecode(seconds, repeat): | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  |     """Source writing bytecode: simple""" | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |     assert not sys.dont_write_bytecode | 
					
						
							|  |  |  |     name = '__importlib_test_benchmark__' | 
					
						
							|  |  |  |     with source_util.create_modules(name) as mapping: | 
					
						
							|  |  |  |         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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  | def decimal_writing_bytecode(seconds, repeat): | 
					
						
							|  |  |  |     """Source writing bytecode: decimal""" | 
					
						
							|  |  |  |     assert not sys.dont_write_bytecode | 
					
						
							|  |  |  |     name = 'decimal' | 
					
						
							|  |  |  |     def cleanup(): | 
					
						
							|  |  |  |         sys.modules.pop(name) | 
					
						
							|  |  |  |         os.unlink(imp.cache_from_source(decimal.__file__)) | 
					
						
							|  |  |  |     for result in bench(name, cleanup, repeat=repeat, seconds=seconds): | 
					
						
							|  |  |  |         yield result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def source_using_bytecode(seconds, repeat): | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  |     """Bytecode w/ source: simple""" | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  |     name = '__importlib_test_benchmark__' | 
					
						
							|  |  |  |     with source_util.create_modules(name) as mapping: | 
					
						
							|  |  |  |         py_compile.compile(mapping[name]) | 
					
						
							|  |  |  |         assert os.path.exists(imp.cache_from_source(mapping[name])) | 
					
						
							|  |  |  |         for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                             seconds=seconds): | 
					
						
							|  |  |  |             yield result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-22 07:40:56 +00:00
										 |  |  | def decimal_using_bytecode(seconds, repeat): | 
					
						
							|  |  |  |     """Bytecode w/ source: decimal""" | 
					
						
							|  |  |  |     name = 'decimal' | 
					
						
							|  |  |  |     py_compile.compile(decimal.__file__) | 
					
						
							|  |  |  |     for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat, | 
					
						
							|  |  |  |                         seconds=seconds): | 
					
						
							|  |  |  |         yield result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-16 19:04:29 +00:00
										 |  |  | def main(import_): | 
					
						
							| 
									
										
										
										
											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_using_bytecode, source_wo_bytecode, | 
					
						
							|  |  |  |                   source_writing_bytecode, | 
					
						
							|  |  |  |                   decimal_using_bytecode, decimal_writing_bytecode, | 
					
						
							|  |  |  |                   decimal_wo_bytecode,) | 
					
						
							|  |  |  |     seconds = 1 | 
					
						
							|  |  |  |     seconds_plural = 's' if seconds > 1 else '' | 
					
						
							|  |  |  |     repeat = 3 | 
					
						
							|  |  |  |     header = "Measuring imports/second over {} second{}, best out of {}\n" | 
					
						
							|  |  |  |     print(header.format(seconds, seconds_plural, repeat)) | 
					
						
							| 
									
										
										
										
											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')) | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     import optparse | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser = optparse.OptionParser() | 
					
						
							|  |  |  |     parser.add_option('-b', '--builtin', dest='builtin', action='store_true', | 
					
						
							|  |  |  |                         default=False, help="use the built-in __import__") | 
					
						
							|  |  |  |     options, args = parser.parse_args() | 
					
						
							|  |  |  |     if args: | 
					
						
							| 
									
										
										
										
											2010-07-15 06:24:04 +00:00
										 |  |  |         raise RuntimeError("unrecognized args: {}".format(args)) | 
					
						
							| 
									
										
										
										
											2009-03-30 15:53:01 +00:00
										 |  |  |     import_ = __import__ | 
					
						
							|  |  |  |     if not options.builtin: | 
					
						
							|  |  |  |         import_ = importlib.__import__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     main(import_) |