Files
sovereign_browser/plans/debug-responsiveness.md
T

5.5 KiB
Raw Blame History

Debugging Responsiveness — sovereign_browser

Symptoms (from user)

  1. Hover lag: a page that highlights buttons on mouseover responds ~2× slower than in Brave.
  2. Load progress invisible until complete: page loads "take a while" and show no progress until the download finishes.

Confirmed root-cause candidates (from code review)

A. Hover/scroll lag — WebKitGTK rendering pipeline

src/tab_manager.c:2912 configures WebKitSettings but only sets:

  • enable_developer_extras, enable_javascript, javascript_can_open_windows_automatically
  • allow_file_access_from_file_urls, allow_universal_access_from_file_urls, allow_modal_dialogs

Not set (left at WebKitGTK defaults):

  • enable_accelerated_2d_canvas (default FALSE on many builds)
  • enable_smooth_scrolling (default FALSE)
  • compositing mode — controlled by env var WEBKIT_DISABLE_COMPOSITING_MODE=1, which if set forces non-accelerated compositing

WebKitGTK ships software-rendered by default on many distros; Chromium/Brave use GPU compositing + Skia by default. This alone explains ~2× paint lag on hover effects (each :hover triggers a repaint; software repaint is much slower).

B. No load-progress UI

on_load_changed handles LOAD_STARTED (→ stop icon), LOAD_COMMITTED (→ URL bar/title), LOAD_FINISHED/LOAD_FAILED (→ reload icon). There is no notify::estimated-load-progress signal handler and no progress bar/spinner in the tab strip. So between STARTED and FINISHED the user sees only a static stop icon — "nothing happens until done."

Debugging plan (ordered: cheap → invasive)

Step 1 — Confirm the rendering hypothesis with env vars (no code change)

Run the browser with GPU compositing forced on and compare hover responsiveness:

WEBKIT_DISABLE_COMPOSITING_MODE=0 ./browser.sh start --login-method generate --url <hover-test-page>
# vs
WEBKIT_DISABLE_COMPOSITING_MODE=1 ./browser.sh start --login-method generate --url <hover-test-page>

Also try WEBKIT_FORCE_SANDBOX=0 only if the above is inconclusive (rules out sandbox-overhead noise). If forcing compositing on closes the gap with Brave, the fix is enabling accelerated settings + ensuring the compositor is active.

Step 2 — Use the existing perf-probe to quantify

The browser already ships www/js/perf-probe.js (long-task observer, rAF FPS, heartbeat main-thread-blockage fallback for WebKitGTK). Enable it (Settings → perf_probe_enabled, or it's gated by settings_get()->perf_probe_enabled at tab_manager.c:1337) and load the hover-test page. Compare:

  • cpu_busy_percent (heartbeat blockage) — high = main thread is being starved
  • fps — low fps during hover = paint-bound, points at rendering pipeline
  • active_timer_count — high = page is timer-heavy (not our bug)

Call the MCP processes.tabs tool (agent_mcp.c:583) to read the probe values per tab while hovering.

Step 3 — System-level profiling to rule out the C/GTK main thread

Even if rendering is the cause, confirm the GTK main thread isn't also blocked. Two cheap checks:

# a) Is the UI process CPU-bound during hover?
top -p $(pgrep -f sovereign_browser) -H -d 0.5

# b) perf record the UI process for 10s while hovering, then look at hotspots
sudo perf record -p $(pgrep -f sovereign_browser) -g -- sleep 10
sudo perf report --no-children

Look for time in webkit*/WebCore*/cairo/GLib dispatchers. If time is dominated by g_main_context_* or our own handlers, the C layer is implicated; if it's WebCore::paint/cairo, it's the renderer.

Step 4 — Check for main-thread blocking from sync JS eval

agent_js_eval_sync runs a nested g_main_loop on the default context. The agent loop (agent_loop.c:333) calls this from a background thread while pumping the main loop. If an agent/MCP tool is running during normal browsing, this can re-dispatch unrelated sources and cause UI hitches. Verify by checking whether sluggishness only occurs while an agent loop is active (watch [agent-loop] iter log lines). If correlated, the fix is to route sync JS eval through a dedicated GMainContext instead of the default one.

Step 5 — Fix candidates (after diagnosis confirms which)

Rendering (likely):

  • In src/tab_manager.c:2912 add:
    webkit_settings_set_enable_accelerated_2d_canvas(settings, TRUE);
    webkit_settings_set_enable_smooth_scrolling(settings, TRUE);
    
    and ensure WEBKIT_DISABLE_COMPOSITING_MODE is not set in the launch environment (check browser.sh).
  • Verify GPU is actually being used: WEBKIT_DEBUG=compositing or check glxinfo/EGL logs.

Load progress (confirmed gap):

  • Add a notify::estimated-load-progress handler on each webview that drives a thin progress bar (or the tab label background) between LOAD_STARTED and LOAD_FINISHED. WebKitGTK emits this continuously during fetch; wiring it gives the missing "loading" feedback. Add the handler next to the load-changed connect at src/tab_manager.c:3136.
  1. Step 1 (env-var A/B test) — fastest signal, no rebuild.
  2. Step 2 (perf-probe) — quantifies, uses existing infra.
  3. Step 3 (perf/top) — rules out C-layer blocking.
  4. Step 4 — only if sluggishness correlates with agent activity.
  5. Step 5 — implement the fix(es) confirmed by 14.