Skip to content

Membrane performance

The challenge

While looking at content creation in a Membrane scenario, we noticed that object_implements took a lot of time. object_implements is a catalog index wrapper that lists both the directly implemented interfaces and any interfaces that can be adapted into. This is used when looking up user objects, as you normally associate adapters with your member types to make them behave like users.

There was a note in object_implements about it being slow. Timing the method call while running tests indicated that the method typically took 1.2 seconds on a MBP laptop. It also did not help that objects are reindexed 4 times when creating content, but that's another story.

The problem

Previously, object_implements was using the getRequiredAdapters  method from zope.app.apidoc.component to list all required adapters for an interface. getRequiredAdapters would check all adapters and instantiate a registration info object for each matching adapter. It would be called once for each interface implemented by the object currently being examined. Judging by the package name, this info object was originally intended to be used for API documentation, and contains more info than we need for this use case.

Poking the adapter registry

As we were not aware of any current methods in the adapter registries that would give the result we were looking for, we started poking the internals of the registry from membrane. The registry has a dictionary of interfaces and their corresponding adapters, and we used that to look up the adapters. If an exception occurs in the new code, we have a fallback to the old code.

Poking the internals of the adapter registry is not future proof, as we are circumventing interfaces and depending on the internal data structures of the adapter registry to stay the same. While not very likely to change, the data structure might change between Zope versions - requiring us to update Membrane.

object_implements optimization

Measuring improvement

After testing again, the time spent in object_implements was 0.0006 seconds, and the set of interfaces returned were exactly the same with both methods.

The difference was difficult to express in our regular go-faster-graphs, so we used an area plot instead. The four pixels on the right indicate the time after optimization relative to before the optimization.

This change is checked in on membrane trunk, and will be part of the next release unless there are any unforeseen problems.

--
Helge Tesdal

Powered by Plone.