summaryrefslogtreecommitdiffstats
path: root/Tools
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2019-02-03 06:54:56 (GMT)
committerGitHub <noreply@github.com>2019-02-03 06:54:56 (GMT)
commitf75d59e1a896115bd52f543a417c665d6edc331f (patch)
tree2844619da81c9c03ae3cdd7fb4576a23782a9a87 /Tools
parent2c2ba05a6be0b7fafa0e2a833a65876e41d4733d (diff)
downloadcpython-f75d59e1a896115bd52f543a417c665d6edc331f.zip
cpython-f75d59e1a896115bd52f543a417c665d6edc331f.tar.gz
cpython-f75d59e1a896115bd52f543a417c665d6edc331f.tar.bz2
bpo-35884: Add variable access benchmarking script (GH-11725)
Diffstat (limited to 'Tools')
-rw-r--r--Tools/scripts/var_access_benchmark.py272
1 files changed, 272 insertions, 0 deletions
diff --git a/Tools/scripts/var_access_benchmark.py b/Tools/scripts/var_access_benchmark.py
new file mode 100644
index 0000000..b4f3b97
--- /dev/null
+++ b/Tools/scripts/var_access_benchmark.py
@@ -0,0 +1,272 @@
+'Show relative speeds of local, nonlocal, global, and built-in access.'
+
+# Please leave this code so that it runs under older versions of
+# Python 3 (no f-strings). That will allow benchmarking for
+# cross-version comparisons. To run the benchmark on Python 2,
+# comment-out the nonlocal reads and writes.
+
+from collections import deque, namedtuple
+
+trials = [None] * 500
+steps_per_trial = 25
+
+class A(object):
+ def m(self):
+ pass
+
+class B(object):
+ __slots__ = 'x'
+ def __init__(self, x):
+ self.x = x
+
+class C(object):
+ def __init__(self, x):
+ self.x = x
+
+def read_local(trials=trials):
+ v_local = 1
+ for t in trials:
+ v_local; v_local; v_local; v_local; v_local
+ v_local; v_local; v_local; v_local; v_local
+ v_local; v_local; v_local; v_local; v_local
+ v_local; v_local; v_local; v_local; v_local
+ v_local; v_local; v_local; v_local; v_local
+
+def make_nonlocal_reader():
+ v_nonlocal = 1
+ def inner(trials=trials):
+ for t in trials:
+ v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal
+ v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal
+ v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal
+ v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal
+ v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal
+ inner.__name__ = 'read_nonlocal'
+ return inner
+
+read_nonlocal = make_nonlocal_reader()
+
+v_global = 1
+def read_global(trials=trials):
+ for t in trials:
+ v_global; v_global; v_global; v_global; v_global
+ v_global; v_global; v_global; v_global; v_global
+ v_global; v_global; v_global; v_global; v_global
+ v_global; v_global; v_global; v_global; v_global
+ v_global; v_global; v_global; v_global; v_global
+
+def read_builtin(trials=trials):
+ for t in trials:
+ oct; oct; oct; oct; oct
+ oct; oct; oct; oct; oct
+ oct; oct; oct; oct; oct
+ oct; oct; oct; oct; oct
+ oct; oct; oct; oct; oct
+
+def read_classvar_from_class(trials=trials, A=A):
+ A.x = 1
+ for t in trials:
+ A.x; A.x; A.x; A.x; A.x
+ A.x; A.x; A.x; A.x; A.x
+ A.x; A.x; A.x; A.x; A.x
+ A.x; A.x; A.x; A.x; A.x
+ A.x; A.x; A.x; A.x; A.x
+
+def read_classvar_from_instance(trials=trials, A=A):
+ A.x = 1
+ a = A()
+ for t in trials:
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+
+def read_instancevar(trials=trials, a=C(1)):
+ for t in trials:
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+
+def read_instancevar_slots(trials=trials, a=B(1)):
+ for t in trials:
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+
+def read_namedtuple(trials=trials, D=namedtuple('D', ['x'])):
+ a = D(1)
+ for t in trials:
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+ a.x; a.x; a.x; a.x; a.x
+
+def read_boundmethod(trials=trials, a=A()):
+ for t in trials:
+ a.m; a.m; a.m; a.m; a.m
+ a.m; a.m; a.m; a.m; a.m
+ a.m; a.m; a.m; a.m; a.m
+ a.m; a.m; a.m; a.m; a.m
+ a.m; a.m; a.m; a.m; a.m
+
+def write_local(trials=trials):
+ v_local = 1
+ for t in trials:
+ v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1
+ v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1
+ v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1
+ v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1
+ v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1
+
+def make_nonlocal_writer():
+ v_nonlocal = 1
+ def inner(trials=trials):
+ nonlocal v_nonlocal
+ for t in trials:
+ v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1
+ v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1
+ v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1
+ v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1
+ v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1
+ inner.__name__ = 'write_nonlocal'
+ return inner
+
+write_nonlocal = make_nonlocal_writer()
+
+def write_global(trials=trials):
+ global v_global
+ for t in trials:
+ v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1
+ v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1
+ v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1
+ v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1
+ v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1
+
+def write_classvar(trials=trials, A=A):
+ for t in trials:
+ A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1
+ A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1
+ A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1
+ A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1
+ A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1
+
+def write_instancevar(trials=trials, a=C(1)):
+ for t in trials:
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+
+def write_instancevar_slots(trials=trials, a=B(1)):
+ for t in trials:
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+ a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
+
+def read_list(trials=trials, a=[1]):
+ for t in trials:
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+
+def read_deque(trials=trials, a=deque([1])):
+ for t in trials:
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+
+def read_dict(trials=trials, a={0: 1}):
+ for t in trials:
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+ a[0]; a[0]; a[0]; a[0]; a[0]
+
+def list_append_pop(trials=trials, a=[1]):
+ ap, pop = a.append, a.pop
+ for t in trials:
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+
+def deque_append_pop(trials=trials, a=deque([1])):
+ ap, pop = a.append, a.pop
+ for t in trials:
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+ ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop();
+
+def write_list(trials=trials, a=[1]):
+ for t in trials:
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+
+def write_deque(trials=trials, a=deque([1])):
+ for t in trials:
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+
+def write_dict(trials=trials, a={0: 1}):
+ for t in trials:
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+ a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1
+
+def loop_overhead(trials=trials):
+ for t in trials:
+ pass
+
+
+if __name__=='__main__':
+
+ from timeit import Timer
+
+ for f in [
+ 'Variable and attribute read access:',
+ read_local, read_nonlocal, read_global, read_builtin,
+ read_classvar_from_class, read_classvar_from_instance,
+ read_instancevar, read_instancevar_slots,
+ read_namedtuple, read_boundmethod,
+ '\nVariable and attribute write access:',
+ write_local, write_nonlocal, write_global,
+ write_classvar, write_instancevar, write_instancevar_slots,
+ '\nData structure read access:',
+ read_list, read_deque, read_dict,
+ '\nData structure write access:',
+ write_list, write_deque, write_dict,
+ '\nStack (or queue) operations:',
+ list_append_pop, deque_append_pop,
+ '\nTiming loop overhead:',
+ loop_overhead]:
+ if isinstance(f, str):
+ print(f)
+ continue
+ timing = min(Timer(f).repeat(7, 1000))
+ timing *= 1000000 / (len(trials) * steps_per_trial)
+ print(u'{:6.1f} \N{greek small letter mu}s\t{}'.format(timing, f.__name__))