# Switcher performance — measured bottlenecks Benchmark harness: `src/project/bench_switcher.cpp` (manual target `bench_switcher`, not a ctest). Run: ```sh cmake -S . -B build-rel -DCMAKE_BUILD_TYPE=Release cmake --build build-rel --target bench_switcher ./build-rel/bin/bench_switcher /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 | - `listFiles` is a `git ls-files` subprocess — acceptable but blocks the UI. - `listSymbols` is 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.