2.8 KiB
Switcher performance — measured bottlenecks
Benchmark harness: src/project/bench_switcher.cpp (manual target bench_switcher,
not a ctest). Run:
cmake -S . -B build-rel -DCMAKE_BUILD_TYPE=Release
cmake --build build-rel --target bench_switcher
./build-rel/bin/bench_switcher <project-root> /tmp/switcher_metrics.txt
Reference project: ~/prj/r7.20/mobydick — 12,234 files, 17,184 ctags
symbols, 6.3 GB tree.
One-time cost when the switcher opens (UI thread, synchronous)
| Stage | Release | Debug (shipped) |
|---|---|---|
ProjectIndex::listFiles |
~84 ms | ~78 ms |
SymbolIndex::listSymbols |
~974 ms | ~499 ms |
build items + setItems |
~5 ms | ~45-70 ms |
listFilesis agit ls-filessubprocess — acceptable but blocks the UI.listSymbolsis a ctags subprocess (~0.5-1 s) — the dominant open-cost, and it blocks the UI thread. (Cost is in the external binary, not our parse.)
Per-keystroke cost — the interactive bottleneck
PaletteModel::setQuery → re-rank. Originally O(N) every keystroke; the cost
grew with query length even as the result set shrank.
Full-scan (every keystroke re-scores all N), Release:
| Query | files | symbols |
|---|---|---|
server |
~14 ms | ~30 ms |
src server go |
~17 ms | ~36 ms |
Debug (what ships): 270-342 ms (files), 459-598 ms (symbols) per keystroke — unusable.
Fix 1 — incremental narrowing (done)
When a query only appends to the previous one, re-score only the currently
visible subset (the match set is monotonic under lengthening/adding a needle),
turning later keystrokes from O(N) into O(previous matches). Exactness is
guarded by test_palettemodel::incrementalMatchesFullScan (incremental ==
full-scan, incl. the typo tier).
Effect once the set narrows (Release, type-forward):
| Query | full-scan | incremental |
|---|---|---|
files server |
~14 ms | ~6.6 ms |
symbols server |
~30 ms | ~9.0 ms |
Early keystrokes (s, se) remain full-N because almost everything matches —
correct and unavoidable without a prefix index.
Fix 2 — build the installed plugin optimized (recommended)
The shipped olliepalette.so is a Debug build (-g, no -O). Release is
~5-8× faster on every hot path above. Install a Release or RelWithDebInfo
build.
Open follow-up — move indexing off the UI thread
listFiles (~85 ms) and especially listSymbols (~0.5-1 s) run synchronously
when the switcher opens. For large projects they should run on a worker thread
(or be cached + refreshed on KateProjectBridge::projectChanged) so the palette
appears instantly and fills in as results arrive. Not yet done.