Epiphany on YouTube is a memory ceiling, and the GPU buffers are charged to its cgroup
scope: device:google-taimen · severity: finding · confidence: proven · subsystem: graphics
The question — Epiphany on YouTube is unusable: very slow scrolling, visual artifacts across the whole phosh session, and eventually a hang. Is that the GPU?
The answer — no. It is a memory ceiling, and the decisive number is PSI:
cpu some avg10=2.77 full avg10=0.00 <- CPU 58-81% idle throughoutmemory some avg10=7.16 full avg10=7.04 <- everything stalled, 7% of wall timeio some avg10=0.61 full avg10=0.31memory full means every runnable task was blocked in reclaim. some and
full being nearly equal is reclaim thrash: when anything stalls, everything
stalls – which is why the artifacts hit the whole session and not just
Epiphany’s window.
The memory is GPU buffers, and cgroup v2 charges them to the app. msm GEM
objects are shmem-backed, so they appear as shmem in the cgroup and as
shared in free:
app-gnome-org.gnome.Epiphany-*.scope memory.current 1925 MiB peak 2055 MiB memory.high max shmem 1576 MiB/sys/kernel/debug/dri/0/gem Resident 2476 objects, 1,541,099,520 B1.9 GiB of a 3.6 GiB phone, in one app scope, unbounded. Per-process DRM
fdinfo puts nearly all of it in a single WebKitWebProcess (the YouTube tab).
Closing Epiphany dropped GEM to 57 objects / 187 MB on the same boot, which is
the control: ~1.35 GB was its working set.
It is a working set, not a leak – sampled over 60 s it sat flat at 1.50-1.55 GB and drifted down.
Why nothing appears in dmesg — nothing went wrong in the kernel. Zero GPU
faults, zero hangchecks, zero DRM *ERROR*. The kernel ran out of room and did
exactly what it should. An empty log is the expected observation here, not a
failed search.
What this rules out
- “The NFC interrupt storm was the cause.” It was real and it was fixed (26M interrupts to zero, see a-level-irq-with-a-pull-up-storms-when-its-chip-is-off) and the symptom did not move. Two live defects at once; the loud one was not the reported one.
- “It is a GPU fault or the a5xx hang.” No fault, no hangcheck, in dmesg or in a netconsole capture spanning the failure.
- “
sharedin free(1) is tmpfs.”/tmp,/runand/dev/shmtogether held 8 MB. All 1.58 GB ofShmemwas GEM. - “Hardware decode alone would fix it.” It removes the software VP9/AV1 cost and some buffer churn, which is worth having, but the tile/layer working set of a QHD+ browser is the bulk of this and venus does not touch it.
Untested mitigation — MemoryHigh=1500M on the app scope, via
~/.config/systemd/user/app-gnome-org.gnome.Epiphany-.scope.d/50-memory.conf,
so reclaim is throttled inside the browser’s cgroup instead of freezing the
session, and so WebKit’s MemoryPressureHandler finally has a bound to react
against (with memory.high unset it never sheds anything). This is applied but
not verified: reproducing the load needs a real session, and Epiphany
launched from ssh dies with SIGABRT in GTK4/libepoxy. Measure it with
memory full avg10 before and after on the same page.
ADDENDUM 2026-08-30 — the mitigation is VERIFIED, and one claim above is CORRECTED
Section: ADDENDUM 2026-08-30 — the mitigation is VERIFIED, and one claim above is CORRECTEDCORRECTION. This note said “It is a GPU fault or the a5xx hang” was ruled out, on “no fault, no hangcheck, in dmesg or in a netconsole capture spanning the failure.” That reading was too strong. Under a heavier session the memory ceiling does reset the GPU — three times in one boot on 2026-08-30:
01:44:48 a5xx_irq gpu fault, status EE0011C1, ib1/ib2 BUFSZ=0000 recover_worker: hangcheck recover! offending task: WebKitWebProces01:53:30 two more, offending task: SkiaGPUWorker01:44:48.549 phoc: [gles2/pass.c:315] GPU reset (innocent) phoc: Re-creating renderer after GPU resetThe correct statement is narrower and more useful: the memory ceiling is the cause and the GPU fault is a downstream effect of it. IB1/IB2 BUFSZ=0 with no SMMU fault line means the GPU was busy and not retiring — it choked on the working set, it did not chase a bad pointer. The original session simply never drove it hard enough to see one.
This matters because the fault is what makes the corruption session-wide. An
a5xx recovery resets the GPU for every client, so phoc — ruled innocent by
GL_KHR_robustness, the guilty context being WebKit’s — rebuilds its renderer and
re-uploads every texture. That is why the artifacts land in phosh’s panel and in
other apps, not only in the browser window.
The mitigation is now measured, and it works. MemoryHigh=1500M on the
scope, applied at launch:
| metric | unbounded | MemoryHigh=1500M ||---------------|-----------|------------------|| scope | 2097 M | ~1400 M || scope swap | 527 M | **0 M** || GEM resident | 1764 M | ~670 M || MemAvailable | 353 M | ~1300 M || GPU faults | 3 / boot | **0** |It now ships in device-google-taimen r35 as
usr/lib/systemd/user/app-gnome-org.gnome.Epiphany-.scope.d/50-memory.conf.
The ~/.config copy this note originally described was erased by the fresh
install hours after it was written, which is why the symptom came back —
package it, or it does not survive.
Confirmed mechanism, not assumed: libwebkitgtk-6.0.so.4 contains
/sys/fs/cgroup/%s/%s/%s, memory.current, memory.high and memory.max, and
one second after the limit was applied three WebKitWebProcesses logged
Memory pressure relief: ... for the first time in 23 minutes of runtime.
WebKit sheds only when the cgroup gives it a ceiling to read.
NEW HAZARD — do not apply this limit to a running browser. See memory-high-arms-systemd-oomd-against-the-browser. Setting it on a scope already above the limit forces a reclaim storm that systemd-oomd kills the process tree for. Set it at launch.
Still open after this fix: transient corruption of small icons and glyphs
inside WebKit only (phosh’s own panel stays clean), visible in a grim capture
and therefore rendered that way rather than damaged on the way to the panel. It
survives with zero GPU faults, so it is NOT this bug. Suspect is WebKit 2.48’s
multithreaded Skia GPU painting on a5xx — note SkiaGPUWorker was the task
blamed for two of the three faults above. Test knob:
WEBKIT_SKIA_GPU_PAINTING_THREADS=0.
