From abc51b17a278db1e6ef7e7ad5ab4621818b75960 Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Tue, 10 Mar 2020 17:47:21 -0500 Subject: [PATCH] Benchmarks looking up adapters from components. Current results (this branch vs master, 354faccebd5b612a2ac8e081a7e5d2f7fb1089c1): | Benchmark | 38-master | 38-faster | |-------------------------------------------|-----------|-------------------------------| | query adapter (no registrations) | 3.81 ms | 3.03 ms: 1.26x faster (-20%) | | query adapter (all trivial registrations) | 4.65 ms | 3.90 ms: 1.19x faster (-16%) | | contains (empty dict) | 163 ns | 76.1 ns: 2.14x faster (-53%) | | contains (populated dict) | 162 ns | 76.9 ns: 2.11x faster (-53%) | | contains (populated list) | 40.3 us | 3.09 us: 13.04x faster (-92%) | Also need benchmarks using inheritance. The 'implied' data structures are also hash/equality based. --- benchmarks/micro.py | 62 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/benchmarks/micro.py b/benchmarks/micro.py index 0494b560..9031261e 100644 --- a/benchmarks/micro.py +++ b/benchmarks/micro.py @@ -1,14 +1,33 @@ import pyperf from zope.interface import Interface +from zope.interface import classImplements from zope.interface.interface import InterfaceClass +from zope.interface.registry import Components +# Long, mostly similar names are a worst case for equality +# comparisons. ifaces = [ - InterfaceClass('I' + str(i), (Interface,), {}) + InterfaceClass('I' + ('0' * 20) + str(i), (Interface,), {}) for i in range(100) ] -INNER = 1000 +def make_implementer(iface): + c = type('Implementer' + iface.__name__, (object,), {}) + classImplements(c, iface) + return c + +implementers = [ + make_implementer(iface) + for iface in ifaces +] + +providers = [ + implementer() + for implementer in implementers +] + +INNER = 10 def bench_in(loops, o): t0 = pyperf.perf_counter() @@ -18,8 +37,47 @@ def bench_in(loops, o): return pyperf.perf_counter() - t0 +def bench_query_adapter(loops, components): + # One time through to prime the caches + for iface in ifaces: + for provider in providers: + components.queryAdapter(provider, iface) + + t0 = pyperf.perf_counter() + for _ in range(loops): + for iface in ifaces: + for provider in providers: + components.queryAdapter(provider, iface) + return pyperf.perf_counter() - t0 + runner = pyperf.Runner() +runner.bench_time_func( + 'query adapter (no registrations)', + bench_query_adapter, + Components(), + inner_loops=1 +) + +def populate_components(): + + def factory(o): + return 42 + + pop_components = Components() + for iface in ifaces: + for other_iface in ifaces: + pop_components.registerAdapter(factory, (iface,), other_iface, event=False) + + return pop_components + +runner.bench_time_func( + 'query adapter (all trivial registrations)', + bench_query_adapter, + populate_components(), + inner_loops=1 +) + runner.bench_time_func( 'contains (empty dict)', bench_in,