Skip to content

A stall catcher on the browser must pick the WebKitWebProcess with the most threads, and thread names are truncated from the front

scope: generic · severity: trap · confidence: proven · subsystem: browser

Symptom – a process- or thread-level instrument on the browser (a stall catcher, threadcpu.py, eu-stack -p, a per-thread sampler) runs for the whole window and reports a clean null: 0 captures, an idle main thread, no GStreamer threads, or no thread matching 'ThreadedCompo'. Meanwhile the frame log shows two-second holes. The null reads as “the web process is not the problem”.

Cause – two independent things, either enough for the null:

  1. Epiphany runs SEVERAL WebKitWebProcess (one per site isolation group plus prewarmed and idle ones – five with a single YouTube tab). A scan of /proc that takes the first match by comm gets an idle one. The page with the media pipeline is the one with by far the most threads (73 vs 14-27 here).
  2. Linux keeps 15 characters of a thread name, and WTF’s thread names are truncated from the FRONT: ThreadedCompositor is eadedCompositor, InterruptDispatcher is rruptDispatcher. A prefix match on the WebKit name finds nothing; a substring match (Compositor) does.

What to do – choose the target WebKitWebProcess by thread count (max(len(os.listdir(f"/proc/{pid}/task")))), and match thread names by substring against the last 15 characters. tools/ph-stallcatch.py does both; threadcpu.py matches by cmdline substring and is safe. Before believing any null from such an instrument, print which pid and which tid it attached to – the run that finally caught the blur printed pid=59014 tid=59043 (eadedCompositor) threads=52 first. Related: uprobes-do-not-attach-to-an-already-mapped-library, youtube-video-freezes-are-a-software-css-blur-on-the-main-thread.