Measure the sidebar rebuild before optimising it #17

Open
opened 2026-08-19 23:57:43 +00:00 by dusan · 1 comment
Owner

Context

The sidebar is rebuilt from scratch whenever anything changes:
rebuild_sidebar in crates/terminalko/src/window.rs calls
adw::Sidebar::remove_all, then rebuilds every section and every row, and
restores the selection by session id.

That is deliberate and documented (docs/spec/session-sidebar.md):
AdwSidebarItem has no setters, so a row cannot be updated in place, and with
tens of sessions rebuilding is cheaper than the bookkeeping incremental updates
would need — and cannot drift from the model.

It is called from: session state changes, foreground-program changes (every two
seconds per session, when the program changes), bells, colour changes, and every
create, delete, rename or move.

The concern

With hundreds of sessions this is wasteful, and the foreground-program path makes
it periodic rather than only user-driven. Nobody has reported a problem, and
nobody has measured it — this issue is to measure first and only then change
anything.

Work

  1. Measure. Generate a tree of, say, 500 sessions across 20 folders (a small
    program against terminalko_config::Store, or dconf load), then time
    rebuild_sidebar and watch for dropped frames while a session's foreground
    program changes. GTK_DEBUG=interactive and GSK_RENDERER timings are enough;
    there is no need for a profiler at first.
  2. If it is fine, write the number down in the spec and close this. A
    documented measurement is worth more than an optimisation nobody needed.
  3. If it is not fine, the fix is almost certainly the same work as issue #1
    (drag-reorder), which replaces adw::Sidebar with a GtkListView over a
    GListStore of row objects — and a list model can be updated in place.
    Doing this issue separately would mean writing that machinery twice.

Acceptance criteria

  • A measurement, in docs/spec/session-sidebar.md: how many sessions, how long a
    rebuild takes, and whether anything is visibly dropped.
  • Either a note that it is acceptable at that size, or a change — and if a change,
    it should be issue #1's list view rather than a second mechanism.

Notes

  • Read this together with issue #1 before starting either.
## Context The sidebar is rebuilt from scratch whenever anything changes: `rebuild_sidebar` in `crates/terminalko/src/window.rs` calls `adw::Sidebar::remove_all`, then rebuilds every section and every row, and restores the selection by session id. That is deliberate and documented (`docs/spec/session-sidebar.md`): `AdwSidebarItem` has no setters, so a row cannot be updated in place, and with tens of sessions rebuilding is cheaper than the bookkeeping incremental updates would need — and cannot drift from the model. It is called from: session state changes, foreground-program changes (every two seconds per session, when the program changes), bells, colour changes, and every create, delete, rename or move. ## The concern With hundreds of sessions this is wasteful, and the foreground-program path makes it periodic rather than only user-driven. Nobody has reported a problem, and nobody has measured it — this issue is to measure first and only then change anything. ## Work 1. **Measure.** Generate a tree of, say, 500 sessions across 20 folders (a small program against `terminalko_config::Store`, or `dconf load`), then time `rebuild_sidebar` and watch for dropped frames while a session's foreground program changes. `GTK_DEBUG=interactive` and `GSK_RENDERER` timings are enough; there is no need for a profiler at first. 2. If it is fine, **write the number down** in the spec and close this. A documented measurement is worth more than an optimisation nobody needed. 3. If it is not fine, the fix is almost certainly the same work as issue #1 (drag-reorder), which replaces `adw::Sidebar` with a `GtkListView` over a `GListStore` of row objects — and a list model **can** be updated in place. Doing this issue separately would mean writing that machinery twice. ## Acceptance criteria - A measurement, in `docs/spec/session-sidebar.md`: how many sessions, how long a rebuild takes, and whether anything is visibly dropped. - Either a note that it is acceptable at that size, or a change — and if a change, it should be issue #1's list view rather than a second mechanism. ## Notes - Read this together with issue #1 before starting either.
Author
Owner

Measured. PR #27 has the spec change and the generator.

Release build, five hundred sessions across twenty folders: 152.6 ms median per rebuild. The curve is roughly linear at ~0.3 ms a session — 3.5 ms at ten, 5.3 ms at twenty, 13.2 ms at fifty, 46.6 ms at two hundred. The 60 Hz frame budget runs out at about sixty sessions.

Nothing is visibly dropped at the sizes anyone has. It very much is at five hundred: with twenty sessions running something whose foreground program keeps changing, the sidebar rebuilds ~6.8 times a second at ~149 ms each, which is about a second of main-thread work per second — the window stops drawing rather than dropping the odd frame. The same test at fifty sessions with ten busy is ~4% of the main thread.

Two things the measurement settled that the issue could not assume:

  • Building the widgets is 99% of it. Store::layout plus every per-row settings read is 1.7 ms of the 152.6 ms. So the model is not the problem and caching it would buy nothing — a list view is exactly the right fix.
  • Sections cost about as much as the rows in them. Five hundred sessions in one section is 83 ms; across twenty sections it is 153 ms. Worth knowing before #1 picks between a header factory and a flattened model.

Leaving this open, per the issue: the fix is #1's GtkListView + GListStore, not a second mechanism here.

Measured. PR #27 has the spec change and the generator. Release build, five hundred sessions across twenty folders: **152.6 ms** median per rebuild. The curve is roughly linear at ~0.3 ms a session — 3.5 ms at ten, 5.3 ms at twenty, 13.2 ms at fifty, 46.6 ms at two hundred. The 60 Hz frame budget runs out at about **sixty sessions**. Nothing is visibly dropped at the sizes anyone has. It very much is at five hundred: with twenty sessions running something whose foreground program keeps changing, the sidebar rebuilds ~6.8 times a second at ~149 ms each, which is about a second of main-thread work per second — the window stops drawing rather than dropping the odd frame. The same test at fifty sessions with ten busy is ~4% of the main thread. Two things the measurement settled that the issue could not assume: - **Building the widgets is 99% of it.** `Store::layout` plus every per-row settings read is 1.7 ms of the 152.6 ms. So the model is not the problem and caching it would buy nothing — a list view is exactly the right fix. - **Sections cost about as much as the rows in them.** Five hundred sessions in one section is 83 ms; across twenty sections it is 153 ms. Worth knowing before #1 picks between a header factory and a flattened model. Leaving this open, per the issue: the fix is #1's `GtkListView` + `GListStore`, not a second mechanism here.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dusan/terminalko#17
No description provided.