1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
"""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.
"""
from . import util
from .source import util as source_util
import decimal
import imp
import importlib
import os
import py_compile
import sys
import timeit
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
yield count // seconds
def from_cache(seconds, repeat):
"""sys.modules"""
name = '<benchmark import>'
module = imp.new_module(name)
module.__file__ = '<test>'
module.__package__ = ''
with util.uncache(name):
sys.modules[name] = module
for result in bench(name, repeat=repeat, seconds=seconds):
yield result
def builtin_mod(seconds, repeat):
"""Built-in module"""
name = 'errno'
if name in sys.modules:
del sys.modules[name]
# Relying on built-in importer being implicit.
for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
seconds=seconds):
yield result
def source_wo_bytecode(seconds, repeat):
"""Source w/o bytecode: simple"""
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
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
def source_writing_bytecode(seconds, repeat):
"""Source writing bytecode: simple"""
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
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
def source_using_bytecode(seconds, repeat):
"""Bytecode w/ source: simple"""
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
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
def main(import_):
__builtins__.__import__ = import_
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))
for benchmark in benchmarks:
print(benchmark.__doc__, "[", end=' ')
sys.stdout.flush()
results = []
for result in benchmark(seconds=seconds, repeat=repeat):
results.append(result)
print(result, end=' ')
sys.stdout.flush()
assert not sys.dont_write_bytecode
print("]", "best is", format(max(results), ',d'))
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:
raise RuntimeError("unrecognized args: {}".format(args))
import_ = __import__
if not options.builtin:
import_ = importlib.__import__
main(import_)
|