blob: b5de6c6b010aada4e5a3d0f9c5afeadecf0a1dc5 [file] [log] [blame]
Brett Cannon3b0a19e2010-07-16 19:04:29 +00001"""Benchmark some basic import use-cases.
2
3The assumption is made that this benchmark is run in a fresh interpreter and
4thus has no external changes made to import-related attributes in sys.
5
6"""
Brett Cannon6ae7a7d2009-03-30 15:53:01 +00007from . import util
8from .source import util as source_util
Brett Cannon5db0c942010-07-22 07:40:56 +00009import decimal
Brett Cannon6ae7a7d2009-03-30 15:53:01 +000010import imp
11import importlib
Brett Cannon3b0a19e2010-07-16 19:04:29 +000012import os
13import py_compile
Brett Cannon6ae7a7d2009-03-30 15:53:01 +000014import sys
15import timeit
16
17
Brett Cannon23cf5742009-09-03 20:45:21 +000018def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3):
19 """Bench the given statement as many times as necessary until total
20 executions take one second."""
21 stmt = "__import__({!r})".format(name)
22 timer = timeit.Timer(stmt)
23 for x in range(repeat):
24 total_time = 0
25 count = 0
26 while total_time < seconds:
27 try:
28 total_time += timer.timeit(1)
29 finally:
30 cleanup()
31 count += 1
32 else:
33 # One execution too far
34 if total_time > seconds:
35 count -= 1
Brett Cannon7b9bcb82010-07-15 06:24:04 +000036 yield count // seconds
Brett Cannon23cf5742009-09-03 20:45:21 +000037
Brett Cannon3b0a19e2010-07-16 19:04:29 +000038def from_cache(seconds, repeat):
Brett Cannon23cf5742009-09-03 20:45:21 +000039 """sys.modules"""
Brett Cannon6ae7a7d2009-03-30 15:53:01 +000040 name = '<benchmark import>'
Brett Cannon23cf5742009-09-03 20:45:21 +000041 module = imp.new_module(name)
42 module.__file__ = '<test>'
43 module.__package__ = ''
Brett Cannon6ae7a7d2009-03-30 15:53:01 +000044 with util.uncache(name):
Brett Cannon6ae7a7d2009-03-30 15:53:01 +000045 sys.modules[name] = module
Brett Cannon3b0a19e2010-07-16 19:04:29 +000046 for result in bench(name, repeat=repeat, seconds=seconds):
Brett Cannon23cf5742009-09-03 20:45:21 +000047 yield result
Brett Cannon6ae7a7d2009-03-30 15:53:01 +000048
49
Brett Cannon3b0a19e2010-07-16 19:04:29 +000050def builtin_mod(seconds, repeat):
Brett Cannon23cf5742009-09-03 20:45:21 +000051 """Built-in module"""
52 name = 'errno'
53 if name in sys.modules:
54 del sys.modules[name]
Brett Cannon7b9bcb82010-07-15 06:24:04 +000055 # Relying on built-in importer being implicit.
Brett Cannon3b0a19e2010-07-16 19:04:29 +000056 for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
57 seconds=seconds):
Brett Cannon23cf5742009-09-03 20:45:21 +000058 yield result
Brett Cannon6ae7a7d2009-03-30 15:53:01 +000059
60
Brett Cannon3b0a19e2010-07-16 19:04:29 +000061def source_wo_bytecode(seconds, repeat):
Brett Cannon5db0c942010-07-22 07:40:56 +000062 """Source w/o bytecode: simple"""
Brett Cannon3b0a19e2010-07-16 19:04:29 +000063 sys.dont_write_bytecode = True
64 try:
65 name = '__importlib_test_benchmark__'
66 # Clears out sys.modules and puts an entry at the front of sys.path.
67 with source_util.create_modules(name) as mapping:
68 assert not os.path.exists(imp.cache_from_source(mapping[name]))
69 for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
70 seconds=seconds):
71 yield result
72 finally:
73 sys.dont_write_bytecode = False
74
75
Brett Cannon5db0c942010-07-22 07:40:56 +000076def decimal_wo_bytecode(seconds, repeat):
77 """Source w/o bytecode: decimal"""
78 name = 'decimal'
79 decimal_bytecode = imp.cache_from_source(decimal.__file__)
80 if os.path.exists(decimal_bytecode):
81 os.unlink(decimal_bytecode)
82 sys.dont_write_bytecode = True
83 try:
84 for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
85 seconds=seconds):
86 yield result
87 finally:
88 sys.dont_write_bytecode = False
89
90
Brett Cannon3b0a19e2010-07-16 19:04:29 +000091def source_writing_bytecode(seconds, repeat):
Brett Cannon5db0c942010-07-22 07:40:56 +000092 """Source writing bytecode: simple"""
Brett Cannon3b0a19e2010-07-16 19:04:29 +000093 assert not sys.dont_write_bytecode
94 name = '__importlib_test_benchmark__'
95 with source_util.create_modules(name) as mapping:
96 def cleanup():
97 sys.modules.pop(name)
98 os.unlink(imp.cache_from_source(mapping[name]))
99 for result in bench(name, cleanup, repeat=repeat, seconds=seconds):
100 assert not os.path.exists(imp.cache_from_source(mapping[name]))
101 yield result
102
103
Brett Cannon5db0c942010-07-22 07:40:56 +0000104def decimal_writing_bytecode(seconds, repeat):
105 """Source writing bytecode: decimal"""
106 assert not sys.dont_write_bytecode
107 name = 'decimal'
108 def cleanup():
109 sys.modules.pop(name)
110 os.unlink(imp.cache_from_source(decimal.__file__))
111 for result in bench(name, cleanup, repeat=repeat, seconds=seconds):
112 yield result
113
114
Brett Cannon3b0a19e2010-07-16 19:04:29 +0000115def source_using_bytecode(seconds, repeat):
Brett Cannon5db0c942010-07-22 07:40:56 +0000116 """Bytecode w/ source: simple"""
Brett Cannon3b0a19e2010-07-16 19:04:29 +0000117 name = '__importlib_test_benchmark__'
118 with source_util.create_modules(name) as mapping:
119 py_compile.compile(mapping[name])
120 assert os.path.exists(imp.cache_from_source(mapping[name]))
121 for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
122 seconds=seconds):
123 yield result
124
125
Brett Cannon5db0c942010-07-22 07:40:56 +0000126def decimal_using_bytecode(seconds, repeat):
127 """Bytecode w/ source: decimal"""
128 name = 'decimal'
129 py_compile.compile(decimal.__file__)
130 for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
131 seconds=seconds):
132 yield result
133
134
Brett Cannon3b0a19e2010-07-16 19:04:29 +0000135def main(import_):
Brett Cannon23cf5742009-09-03 20:45:21 +0000136 __builtins__.__import__ = import_
Brett Cannon5db0c942010-07-22 07:40:56 +0000137 benchmarks = (from_cache, builtin_mod,
138 source_using_bytecode, source_wo_bytecode,
139 source_writing_bytecode,
140 decimal_using_bytecode, decimal_writing_bytecode,
141 decimal_wo_bytecode,)
142 seconds = 1
143 seconds_plural = 's' if seconds > 1 else ''
144 repeat = 3
145 header = "Measuring imports/second over {} second{}, best out of {}\n"
146 print(header.format(seconds, seconds_plural, repeat))
Brett Cannon23cf5742009-09-03 20:45:21 +0000147 for benchmark in benchmarks:
148 print(benchmark.__doc__, "[", end=' ')
149 sys.stdout.flush()
150 results = []
Brett Cannon5db0c942010-07-22 07:40:56 +0000151 for result in benchmark(seconds=seconds, repeat=repeat):
Brett Cannon23cf5742009-09-03 20:45:21 +0000152 results.append(result)
153 print(result, end=' ')
154 sys.stdout.flush()
Brett Cannon3b0a19e2010-07-16 19:04:29 +0000155 assert not sys.dont_write_bytecode
Brett Cannoncbe1a4e2010-07-16 19:26:23 +0000156 print("]", "best is", format(max(results), ',d'))
Brett Cannon6ae7a7d2009-03-30 15:53:01 +0000157
158
159if __name__ == '__main__':
160 import optparse
161
162 parser = optparse.OptionParser()
163 parser.add_option('-b', '--builtin', dest='builtin', action='store_true',
164 default=False, help="use the built-in __import__")
165 options, args = parser.parse_args()
166 if args:
Brett Cannon7b9bcb82010-07-15 06:24:04 +0000167 raise RuntimeError("unrecognized args: {}".format(args))
Brett Cannon6ae7a7d2009-03-30 15:53:01 +0000168 import_ = __import__
169 if not options.builtin:
170 import_ = importlib.__import__
171
172 main(import_)