Perf: debounce palette filter + default to optimized build
Two fixes for the Alt+G typing lag: 1. Default CMAKE_BUILD_TYPE to RelWithDebInfo when unspecified — the shipped plugin was -O0. On mobydick (17k symbols) the worst type-forward keystroke drops ~340ms -> ~29ms (~12x). 2. Debounce the PaletteWidget filter with an 80ms single-shot timer so a fast typist's burst triggers one re-rank, not one per character. applyQueryNow() flushes the pending query on Enter so activation uses the latest text; activate() resets the debounce state. The broad early-query keystrokes (1-2 chars matching most of N) are the only ones still ~O(N); debounce ensures they are paid at most once per pause. docs/PERF.md updated with measured numbers.
This commit is contained in:
parent
2bf8d4a3c2
commit
a5b8d628b3
|
|
@ -9,6 +9,14 @@ set(CMAKE_AUTOMOC ON)
|
|||
set(QT_MIN_VERSION 6.5.0)
|
||||
set(KF_MIN_VERSION 6.0.0)
|
||||
|
||||
# Default to an optimized build when the user did not pick one. The palette
|
||||
# re-rank and indexing are measurably ~5-8x slower under -O0 (see docs/PERF.md),
|
||||
# so an unqualified `cmake -B build` should not ship a Debug plugin.
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
|
||||
"Build type (Debug, Release, RelWithDebInfo, MinSizeRel)" FORCE)
|
||||
endif()
|
||||
|
||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
|
||||
|
||||
|
|
|
|||
21
docs/PERF.md
21
docs/PERF.md
|
|
@ -57,11 +57,24 @@ Effect once the set narrows (Release, type-forward):
|
|||
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)
|
||||
## Fix 2 — build the installed plugin optimized (done)
|
||||
|
||||
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.
|
||||
The root `CMakeLists.txt` now defaults `CMAKE_BUILD_TYPE` to `RelWithDebInfo`
|
||||
when the user does not specify one, so an unqualified `cmake -B build` no longer
|
||||
ships a `-O0` plugin. Measured effect on the symbol switcher (mobydick,
|
||||
type-forward "serv", 17k symbols): **~340 ms → ~29 ms per keystroke** (~12×).
|
||||
|
||||
## Fix 3 — debounce the filter (done)
|
||||
|
||||
`PaletteWidget` coalesces rapid keystrokes with an 80 ms single-shot timer
|
||||
before re-ranking (`applyQueryNow` flushes on Enter so activation always uses
|
||||
the latest text). A fast typist's burst (`s`,`se`,`ser`…) triggers one re-rank
|
||||
instead of three, so the broad-query early keystrokes — the only ones that still
|
||||
scan most of N — are paid at most once per pause, not per character.
|
||||
|
||||
Net result after fixes 1-3: the worst single symbol keystroke on a 17k-symbol
|
||||
project is ~29 ms (RelWithDebInfo), and bursts are coalesced; the Alt+G panel
|
||||
is responsive.
|
||||
|
||||
## Follow-up — move indexing off the UI thread (done)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <QStyledItemDelegate>
|
||||
#include <QTextCharFormat>
|
||||
#include <QTextDocument>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPainter>
|
||||
#include <QPoint>
|
||||
|
|
@ -118,12 +119,19 @@ PaletteWidget::PaletteWidget(QWidget *parent)
|
|||
layout->addWidget(m_filter);
|
||||
layout->addWidget(m_list);
|
||||
|
||||
// Live, company-style updates: re-rank and keep the top row selected.
|
||||
// Live updates, but debounced: a fast typist generates several keystrokes
|
||||
// in a few ms, and on a large project each re-rank scores thousands of
|
||||
// items. Coalesce bursts into a single re-rank so early (broad) queries do
|
||||
// not stall the UI. 80 ms is below the threshold of feeling laggy while
|
||||
// still absorbing a typing burst.
|
||||
m_filterDebounce = new QTimer(this);
|
||||
m_filterDebounce->setSingleShot(true);
|
||||
m_filterDebounce->setInterval(80);
|
||||
connect(m_filterDebounce, &QTimer::timeout, this, [this]() { applyQueryNow(); });
|
||||
|
||||
connect(m_filter, &QLineEdit::textChanged, this, [this](const QString &text) {
|
||||
m_model->setQuery(text);
|
||||
if (m_model->rowCount() > 0) {
|
||||
m_list->setCurrentIndex(m_model->index(0, 0));
|
||||
}
|
||||
m_pendingQuery = text;
|
||||
m_filterDebounce->start(); // (re)arm; applied on timeout
|
||||
});
|
||||
|
||||
// Mouse: a click activates immediately.
|
||||
|
|
@ -143,9 +151,20 @@ void PaletteWidget::setItems(const QList<PaletteItem> &items)
|
|||
}
|
||||
}
|
||||
|
||||
void PaletteWidget::applyQueryNow()
|
||||
{
|
||||
m_filterDebounce->stop();
|
||||
m_model->setQuery(m_pendingQuery);
|
||||
if (m_model->rowCount() > 0) {
|
||||
m_list->setCurrentIndex(m_model->index(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteWidget::activate()
|
||||
{
|
||||
m_filterDebounce->stop();
|
||||
m_filter->clear();
|
||||
m_pendingQuery.clear();
|
||||
m_model->setQuery(QString());
|
||||
if (m_model->rowCount() > 0) {
|
||||
m_list->setCurrentIndex(m_model->index(0, 0));
|
||||
|
|
@ -170,6 +189,11 @@ void PaletteWidget::moveSelection(int delta)
|
|||
|
||||
void PaletteWidget::acceptCurrent()
|
||||
{
|
||||
// Flush any pending debounced query so Enter acts on the latest text even
|
||||
// if the user typed and immediately hit Enter within the debounce window.
|
||||
if (m_filterDebounce->isActive()) {
|
||||
applyQueryNow();
|
||||
}
|
||||
const int row = m_list->currentIndex().row();
|
||||
const PaletteItem *item = m_model->itemAt(row);
|
||||
if (!item) {
|
||||
|
|
|
|||
|
|
@ -19,9 +19,11 @@
|
|||
|
||||
#include <QFrame>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
class QLineEdit;
|
||||
class QListView;
|
||||
class QTimer;
|
||||
|
||||
namespace katecustom
|
||||
{
|
||||
|
|
@ -52,10 +54,14 @@ private:
|
|||
void moveSelection(int delta);
|
||||
void acceptCurrent();
|
||||
void dismiss();
|
||||
// Apply the pending filter text to the model now (flushes the debounce).
|
||||
void applyQueryNow();
|
||||
|
||||
PaletteModel *m_model;
|
||||
QLineEdit *m_filter;
|
||||
QListView *m_list;
|
||||
QTimer *m_filterDebounce; // coalesces rapid keystrokes before re-ranking
|
||||
QString m_pendingQuery;
|
||||
};
|
||||
|
||||
} // namespace katecustom
|
||||
|
|
|
|||
Loading…
Reference in New Issue