summaryrefslogtreecommitdiff
path: root/benchmarks
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2020-03-06 18:38:50 -0600
committerJason Madden <jamadden@gmail.com>2020-03-18 12:26:35 -0500
commit8ac3bd088d9b924cfb3170b77b41effd2de39d23 (patch)
tree42c4c9f92b09dab763c0ecd0a9a916a7f24caad7 /benchmarks
parent13de77d4edfc64c89533656220030230bcf2d895 (diff)
downloadzope-interface-8ac3bd088d9b924cfb3170b77b41effd2de39d23.tar.gz
Move Interface hashing and comparison to C; 2.5 to 15x speedup in micro benchmarks
Included benchmark numbers: Current master, Python 3.8: ..................... contains (empty dict): Mean +- std dev: 198 ns +- 5 ns ..................... contains (populated dict): Mean +- std dev: 197 ns +- 6 ns ..................... contains (populated list): Mean +- std dev: 53.1 us +- 1.2 us This code: ..................... contains (empty dict): Mean +- std dev: 77.9 ns +- 2.3 ns ..................... contains (populated dict): Mean +- std dev: 78.4 ns +- 3.1 ns ..................... contains (populated list): Mean +- std dev: 3.69 us +- 0.08 us So anywhere from 2.5 to 15x faster. Not sure how that will translate to larger benchmarks, but I'm hopeful. It turns out that messing with ``__module__`` is nasty, tricky business, especially when you do it from C. Everytime you define a new subclass, the descriptors that you set get overridden by the type machinery (PyType_Ready). I'm using a data descriptor and a meta class right now to avoid that but I'm not super happy with that and would like to find a better way. (At least, maybe the data part of the descriptor isn't necessary?) It may be needed to move more code into C, I don't want a slowdown accessing ``__module__`` either; copying around the standard PyGetSet or PyMember descriptors isn't enough because they don't work on the class object (so ``classImplements(InterfaceClass, IInterface)`` fails).
Diffstat (limited to 'benchmarks')
-rw-r--r--benchmarks/micro.py42
1 files changed, 42 insertions, 0 deletions
diff --git a/benchmarks/micro.py b/benchmarks/micro.py
new file mode 100644
index 0000000..0494b56
--- /dev/null
+++ b/benchmarks/micro.py
@@ -0,0 +1,42 @@
+import pyperf
+
+from zope.interface import Interface
+from zope.interface.interface import InterfaceClass
+
+ifaces = [
+ InterfaceClass('I' + str(i), (Interface,), {})
+ for i in range(100)
+]
+
+INNER = 1000
+
+def bench_in(loops, o):
+ t0 = pyperf.perf_counter()
+ for _ in range(loops):
+ for _ in range(INNER):
+ o.__contains__(Interface)
+
+ return pyperf.perf_counter() - t0
+
+runner = pyperf.Runner()
+
+runner.bench_time_func(
+ 'contains (empty dict)',
+ bench_in,
+ {},
+ inner_loops=INNER
+)
+
+runner.bench_time_func(
+ 'contains (populated dict)',
+ bench_in,
+ {k: k for k in ifaces},
+ inner_loops=INNER
+)
+
+runner.bench_time_func(
+ 'contains (populated list)',
+ bench_in,
+ ifaces,
+ inner_loops=INNER
+)