Skip to content

Cut first-paint latency by parallelizing startup work - #2300

Open
futpib wants to merge 1 commit into
davatorium:nextfrom
futpib:async-startup-prefetch
Open

futpib wants to merge 1 commit into
davatorium:nextfrom
futpib:async-startup-prefetch

Conversation

@futpib

@futpib futpib commented May 29, 2026

Copy link
Copy Markdown

rofi did all of its startup work serially before showing the window, so time-to-first-paint paid for every step up front. Two changes move the biggest filesystem/CPU-bound chunks off the critical path:

  • Initialize the icon fetcher lazily on the first icon query instead of eagerly in main(). Modes that show no icons (and the path to first paint) no longer pay to load icon themes, gdk-pixbuf loaders and thumbnailers.

  • Run the remaining X-independent startup work -- mode data loading (.desktop/$PATH/history scans) and the icon-theme setup -- on a background thread spawned right after the modes are configured, so it overlaps the latency-bound X server setup and the pango/font setup that follow. The worker is joined before the data is consumed (and as a safety net in cleanup(), before the modes are destroyed).

Mode init is only prefetched when verified safe: filesystem and its own private data only, no X and no state the main thread mutates concurrently (drun, run, ssh, filebrowser; they read the already-parsed rofi_configuration, not the still-resolving rofi_theme). Default-deny -- window calls xcb_ewmh* in its _init, and combi initializes its (possibly X-using) sub-modes, so both stay serial.

Measured with rofi -show drun over 800 entries (desktop cache off): first paint drops from ~74ms to ~42ms median (-43%); the win scales with the mode-load cost.

rofi did all of its startup work serially before showing the window, so
time-to-first-paint paid for every step up front. Two changes move the
biggest filesystem/CPU-bound chunks off the critical path:

- Initialize the icon fetcher lazily on the first icon query instead of
  eagerly in main(). Modes that show no icons (and the path to first
  paint) no longer pay to load icon themes, gdk-pixbuf loaders and
  thumbnailers.

- Run the remaining X-independent startup work -- mode data loading
  (.desktop/$PATH/history scans) and the icon-theme setup -- on a
  background thread spawned right after the modes are configured, so it
  overlaps the latency-bound X server setup and the pango/font setup
  that follow. The worker is joined before the data is consumed (and as
  a safety net in cleanup(), before the modes are destroyed).

Mode _init is only prefetched when verified safe: filesystem and its own
private data only, no X and no state the main thread mutates concurrently
(drun, run, ssh, filebrowser; they read the already-parsed
rofi_configuration, not the still-resolving rofi_theme). Default-deny --
window calls xcb_ewmh_* in its _init, and combi initializes its
(possibly X-using) sub-modes, so both stay serial.

Measured with `rofi -show drun` over 800 entries (desktop cache off):
first paint drops from ~74ms to ~42ms median (-43%); the win scales with
the mode-load cost.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@futpib
futpib marked this pull request as ready for review May 29, 2026 23:58

This branch has not been deployed

No deployments
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