Performance¶
Generated page
Written by tools/perf_report.py render from the nightly
benchmark run (.github/workflows/performance-nightly.yml) and
redeployed to the dev docs version. Editing it by hand is
pointless — the next nightly overwrites it.
This is Phase 0 of #131: the measurement the later phases are supposed to be argued from. It is a dashboard, not a gate — nothing in CI fails because a number here moved, because hosted runners are shared VMs and a nightly that cried wolf would be muted inside a week. Read it for trends, not for single runs.
Latest run¶
- When: 2026-08-20T18:00:23.371329+00:00
- Commit:
188767e1fb98(refs/heads/master) - Runner: seed (local, macOS arm64), Python 3.12.11
- Recorded runs in history: 1
This is the seed run committed with #132 — the trend charts appear once the nightly has recorded a second one.
Percentages compare against the baseline recorded on seed (local, macOS arm64) (2026-08-20, 188767e1fb98).
EventBus.publish¶
The floor under everything else. publish snapshots both subscriber lists defensively, which is the allocation #131 Phase 1 proposes to replace with copy-on-write — the 0-subscriber row is what that would be measured against.
| Benchmark | Mean | vs baseline | |
|---|---|---|---|
test_bench_bus_publish[0] |
160 ns | +0.0% | |
test_bench_bus_publish[10] |
499 ns | +0.0% | |
test_bench_bus_publish[1] |
184 ns | +0.0% | |
test_bench_bus_publish[50] |
1.84 µs | +0.0% | |
test_bench_bus_publish_to_firehose |
182 ns | +0.0% |
LogPipeline.process (full backend)¶
One replay of 60 in-game seconds of traffic through the parser chain and every handler subscribed to it. Divide by the line count in the table for per-line cost; the driver thread has 100 ms per poll to absorb whatever arrived in it.
| Benchmark | Mean | vs baseline | |
|---|---|---|---|
test_bench_pipeline_cold_backend |
115.29 ms | +0.0% | |
test_bench_pipeline_corpus |
1.56 ms | +0.0% | |
test_bench_pipeline_profile[group] |
9.97 ms | +0.0% | |
test_bench_pipeline_profile[raid] |
27.03 ms | +0.0% | |
test_bench_pipeline_profile[solo] |
3.81 ms | +0.0% |
Per line: test_bench_pipeline_cold_backend: 633 lines, 182.14 µs/line; test_bench_pipeline_corpus: 93 lines, 16.77 µs/line; test_bench_pipeline_profile[group]: 440 lines, 22.67 µs/line; test_bench_pipeline_profile[raid]: 1264 lines, 21.38 µs/line; test_bench_pipeline_profile[solo]: 167 lines, 22.84 µs/line.
Plugin subscriber dispatch¶
The same publish, but through HostPluginContext — so the per-plugin try/except guard and the telemetry gate are both inside the number. off and on are collection disabled and enabled: the gap is the entire cost of #132's measurement on the dispatch path.
| Benchmark | Mean | vs baseline | |
|---|---|---|---|
test_bench_plugin_dispatch[1-off] |
203 ns | +0.0% | |
test_bench_plugin_dispatch[1-on] |
484 ns | +0.0% | |
test_bench_plugin_dispatch[10-off] |
745 ns | +0.0% | |
test_bench_plugin_dispatch[10-on] |
3.32 µs | +0.0% | |
test_bench_plugin_dispatch[50-off] |
3.06 µs | +0.0% | |
test_bench_plugin_dispatch[50-on] |
16.64 µs | +0.0% |
Plugin parser in the chain¶
A plugin parser appended after the built-in chain, over a raid burst. It never consumes a line, which is the worst case: every line reaches it.
| Benchmark | Mean | vs baseline | |
|---|---|---|---|
test_bench_plugin_parser[off] |
18.94 ms | +0.0% | |
test_bench_plugin_parser[on] |
14.36 ms | +0.0% |
Per line: test_bench_plugin_parser[off]: 633 lines, 29.93 µs/line; test_bench_plugin_parser[on]: 633 lines, 22.69 µs/line.
Qt bridge (buffer + coalesced flush)¶
1000 events published from a worker thread and delivered in one coalesced GUI-thread flush. burst has a per-event slot connected, batch_only just the bulk signal.
| Benchmark | Mean | vs baseline | |
|---|---|---|---|
test_bench_qt_bridge_batch_only |
1.05 ms | +0.0% | |
test_bench_qt_bridge_burst |
1.19 ms | +0.0% |
Map canvas render¶
The heaviest widget in the app, coalescing 120 location fixes into one render.
| Benchmark | Mean | vs baseline | |
|---|---|---|---|
test_bench_map_location_burst |
348.55 µs | +0.0% |
End-to-end latency (log append -> UI slot)¶
A real LogDriver tailing a real file, so this includes the 100 ms poll interval it is dominated by. That is the honest end-to-end figure — it is what the user waits.
| Benchmark | Mean | vs baseline | |
|---|---|---|---|
test_bench_latency_append_to_ui |
102.05 ms | +0.0% | |
test_bench_latency_parse_to_ui |
72.24 µs | +0.0% |
Running it yourself¶
QT_QPA_PLATFORM=offscreen uv run pytest -m benchmark --benchmark-only
Benchmarks are excluded from the default uv run pytest (see the
addopts in pyproject.toml) because timing assertions in CI are noise.
The fixtures they replay are in tests/perf/profiles.py: solo, group and
raid traffic composed from the EQtoolsTests line corpus.