sphinx-numref-performance

sphinx-numref-performance makes Sphinx resolve :numref: references without loading the doctree of the document that holds the target.

It provides community testing for a fix to sphinx-doc/sphinx#12611, and is meant to be retired once a Sphinx release contains that fix. Until then it is safe to install: it changes build time, not output, and it takes no configuration.

Note

This site is built with the extension enabled, so the numbers below are resolved by it. Table 1 reports what the extension saves.

The problem

Sphinx resolves each :numref: by reading the document that holds the target:

target_node = env.get_doctree(docname).ids.get(labelid)
figtype = self.get_enumerable_node_type(target_node)
fignumber = self.get_fignumber(env, builder, figtype, docname, target_node)

env.get_doctree() caches the pickled bytes of a document but unpickles a fresh copy on every call, because callers are allowed to modify what they get back. A page with N references into documents whose trees are O(N) therefore costs O(N²), which is why the cost grows faster than the page does.

Table 1 Build time of one page of captioned tables, each referenced once with :numref:

page

Sphinx

extension

50 tables

1.00s

0.43s

100 tables

3.39s

0.60s

200 tables

16.31s

1.06s

Projects that reference numbered tables and figures from a page of their own, such as a list of tables or a summary page, feel this most. Measure your own project with tox -e bench, described in Measuring the difference.