Skip to content

Fix multi-second UI freeze when toggling severity filters on large logs - #22

Open
Schogol wants to merge 3 commits into
ccpgames:masterfrom
Schogol:perf/log-filter-freeze-cmake
Open

Fix multi-second UI freeze when toggling severity filters on large logs#22
Schogol wants to merge 3 commits into
ccpgames:masterfrom
Schogol:perf/log-filter-freeze-cmake

Conversation

@Schogol

@Schogol Schogol commented Jul 19, 2026

Copy link
Copy Markdown

Problem

On large logs, clicking the severity filter buttons (show/hide notice/info) froze the UI for several seconds. LogFilter was a QSortFilterProxyModel, so each toggle re-tested every source row and rebuilt the whole mapping, emitting a storm of granular row-insert/remove signals that the table and header processed one at a time - effectively O(N²) with the view attached.

Change

Replace QSortFilterProxyModel with a purpose-built flat filter proxy:

  • Keeps a sorted index of accepted source rows (m_proxyToSource).
  • A severity/text-filter change rebuilds that index in a single pass and emits layoutChanged (selection preserved via persistent indexes) instead of re-testing every row.
  • Streaming inserts/removals stay incremental; mapToSource is O(1).
  • The logmap repaints on layoutChanged/modelReset (filter changes no longer arrive as row insert/remove).
  • Drop the now-obsolete setFilterCaseSensitivity call.

Results

  • 100k rows, hide-info toggle: ~5350 ms -> ~8 ms.
  • Validated with QAbstractItemModelTester (no consistency warnings) across inserts, streaming-while-filtered, removal, clear, severity toggles, and text filtering.
  • Builds and runs on the current Qt6/CMake codebase.

Files changed

File +/-
src/logfilter.cpp +387 / -45
include/logfilter.h +50 / -4
src/logmap.cpp +7 / -4
src/mainwindow.cpp 0 / -1
clients/qtclient/qloglitelogger.cpp 0 / -1

Note: clients/qtclient/qloglitelogger.cpp is an unrelated one-line cleanup (removes a duplicate channel fillString) that rode along on the branch. Happy to drop it for a fix-only PR if preferred.

Disclaimer: Issue encountered, reproduced by me. Fix created with help by Claude. Fix has been live tested by me for a bit now and I've not noticed any issues

Schogol added 3 commits June 10, 2026 23:10
Port of the flat-filter-proxy fix onto the current CMake/Qt6 codebase
(headers under include/, upstream's modernized logfilter).

Replace QSortFilterProxyModel with a purpose-built flat filter proxy.
LogFilter keeps a sorted index of accepted source rows; a severity toggle
rebuilds that index in a single pass and emits layoutChanged (preserving
selection) instead of re-testing every row through the generic proxy
machinery. Streaming inserts/removals stay incremental and mapToSource
becomes an O(1) lookup.

- logfilter.{h,cpp}: rewrite LogFilter as a flat QAbstractProxyModel;
  keep the highlight data() override using Qt::ForegroundRole/BackgroundRole.
- logmap.cpp: repaint the logmap on layoutChanged/modelReset.
- mainwindow.cpp: drop the now-obsolete setFilterCaseSensitivity call.

Measured on the Qt6/CMake build, 100k rows, hide-info toggle:
~5350 ms -> ~8 ms. Validated with QAbstractItemModelTester (no
consistency warnings).
@Schogol

Schogol commented Jul 19, 2026

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant