[WIP] sphinx-benchmark
This is a Sphinx extension that benchmarks and profiles a docs build process event-wise(handler-wise), and the gaps in between the events-- so you can tell which extension, theme, or part of Sphinx itself is slowing your builds.
You can find the benchmarking outputs for different Scientific Python projects and learn more about the benchmarking output in the benchmarking_outputs directory.
Usage
-
Add the extension to your
conf.py:extensions = ["sphinx_benchmark", ...]
Put it first in the list as it minimizes (but doesn't eliminate) the untracked starting time.
-
Then build your docs as usual:
sphinx-build -b html docs/ docs/_build/html
The build generates a
sphinx_benchmarks.jsonin the present working directory. -
Run the
print_summary.pyscript to get the benchmarking output:python path/to/sphinx-benchmark/src/sphinx_benchmark/print_summary.pyFor what the output actually mean, see the benchmarking_outputs README.
How are benchmarks calculated?
Nearly everything an extension does in Sphinx goes through app.events.emit().
Sphinx calls it at certain points in the build process, and it runs all the
registered handler for that event. This extension wraps and puts timers around this path.
wrap_emit() wraps app.events.emit that times the whole emission, and
wrap_listener() swaps each handler for a wrapped and timed copy of it.
So for every event you get the total time it took and the split across its handlers.
A stack is maintained to keep track of nested event, and the child event's time is
later subtracted so it isn't counted twice. wrap_all_listeners() wraps everything
already registered when the extension loads, and wrap_connect() wraps
app.events.connect so handlers and events registered later, also get wrapped as they are called.
Each timed call becomes a HandlerCall record and each event emission becomes an
Event record, both kept in one EventLogger. All times are measured from the moment
the extension started, so everything shares a starting point.
At build-finished (at priority 999, so other extensions' handlers gets executed first)
the extension works out each event's own time, classify every handler with where it came from,
and dumps everything into a JSON.
Limitations of this extension - WIP
- No parallel builds: The recorder lives in the main process only, so
parallel_read_safeandparallel_write_safeare bothFalse. Sphinx will fall back to a serial build even if you pass-j auto, which means the wall-clock total won't match what you'd normally see, when you are building with parallelism. - The
build-finishedemission hasduration=None. The handler that writes the JSON runs inside that emission, so the emission hasn't ended yet when it's serialised. It's stored withduration=Noneand the summary skips it. Anything after it, likebuilder.cleanup()isn't measured at all. - The startup blind spot: Timing begins at the extension's
setup(). The "startup, before first emission" row in the gaps table covers only what happened after that point. - Some handlers can't be classified: Handlers defined in
conf.py, or in a package that doesn't match anything inapp.extensions, are classified asunknownand reported by module or file name. Partials and callable objects have no__qualname__, so they're labelled by whatever name could be recovered. - the extension itself also adds a little bit of overhead to the build process.
- Wall clock time is not CPU time: caches, background processes, and network fetches all are included in the total time. Run benchmarks more than once before concluding anything.
Thank you for stopping by :)
Release files for sphinx-benchmark 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sphinx_benchmark-0.1.0.tar.gz | 36.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sphinx_benchmark-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.7 kB
Release files / sphinx_benchmark-0.1.0.tar.gz
| Download URL | sphinx_benchmark-0.1.0.tar.gz |
|---|---|
| Size | 36.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
57df7d6c353748883cdc6521e978f33b01fb3b6fc6787f89aa1e183aaf5c864f
|
|
BLAKE2b-256 checksum How to use checksums |
3248377d61fe48d9f771abdb462626a4e0b701fdcd8d3c0b07690f0318215273
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Hatch/1.18.0 {"ci":null,"cpu":"arm64","distro":{"name":"macOS","version":"26.3.1"},"implementation":{"name":"CPython","version":"3.12.13"},"installer":{"name":"hatch","version":"1.18.0"},"openssl_version":"OpenSSL 3.6.1 27 Jan 2026","python":"3.12.13","system":{"name":"Darwin","release":"25.3.0"}} HTTPX2/2.12.0
|
Release files / sphinx_benchmark-0.1.0-py3-none-any.whl
| Download URL | sphinx_benchmark-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c185ccecea40551252659ed166c9523e06922b6955d0bbe6b71238d58a37e96f
|
|
BLAKE2b-256 checksum How to use checksums |
e726b564c40758b7afb93b40228d6eb84dac7dcf9d5b1e2ad99f4675c5c1a08f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Hatch/1.18.0 {"ci":null,"cpu":"arm64","distro":{"name":"macOS","version":"26.3.1"},"implementation":{"name":"CPython","version":"3.12.13"},"installer":{"name":"hatch","version":"1.18.0"},"openssl_version":"OpenSSL 3.6.1 27 Jan 2026","python":"3.12.13","system":{"name":"Darwin","release":"25.3.0"}} HTTPX2/2.12.0
|