Files
Anthias/tests
Viktor Petersson de2f6e591c fix(viewer): force Chromium's low-memory profile on ~1 GB boards (#3178)
* fix(viewer): force Chromium's low-memory profile on ~1 GB boards

A ~1 GB board with no swap head-room (Raspberry Pi 3, and 1 GB Pi 4 /
Pi 5 SKUs) slowly grows past its RAM under a web-page asset that stays
up or cycles for hours, ending in a black screen / swap thrash (forum
report: a Pi 3B+ rendered unusable, load ~9, after long uptime).

QtWebEngine ships Chromium's desktop-tuned, multi-process memory model
and only auto-enables its low-memory profile below ~512 MB, so a ~1 GB
board never gets it. Force it on and bound the per-renderer footprint by
prepending to QTWEBENGINE_CHROMIUM_FLAGS in _build_webview_env:

  --enable-low-end-device-mode
  --js-flags=--max-old-space-size=64
  --renderer-process-limit=1
  --process-per-site
  --disable-dev-shm-usage

Gate on measured RAM (MemTotal from /proc/meminfo, shared with the host)
rather than a board/DEVICE_TYPE allowlist, so every low-memory SKU is
covered — including the 1 GB Qt5 armhf boards — and 2 GB+ boards keep the
faster default process model. The switches are prepended so a
device-supplied QTWEBENGINE_CHROMIUM_FLAGS and the dark-mode
--blink-settings switch main.cpp appends still apply, and guarded on the
flag string so an inherited value on a respawn can't stack duplicates.

Hardware-validated on a real Pi 3B+ (806 MB RAM, no swap), 10-min A/B
soak with two web pages cycling every 20 s: steady-state viewer-container
RSS dropped from ~225 MB to ~147 MB (-78 MB / -35 %), the AnthiasViewer
process from ~78 MB to ~59 MB, with ~20 MB more MemAvailable and no
crashes. On a 787 MB no-swap board that margin is the difference between
staying alive and OOM under the same workload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(viewer): gate the low-memory profile on the shared is_low_ram_device

Reuse anthias_common.board.is_low_ram_device / LOW_RAM_THRESHOLD_KB — the
canonical ~1 GB gate that already drives the video 1080p upload cap and
the system-info Low-RAM badge — instead of a second /proc/meminfo reader
with its own threshold. One source of truth: the viewer, asset processor
and UI now agree on which boards are constrained, and the gate reads the
host_agent-published MemTotal from Redis so server and viewer can't drift.

Also correct the system-info Low-RAM badge: single-QWebEngineView is
unconditional now (the preloaded dual-buffer was removed for issue #2954),
so the badge described a mode every board runs. It now lists the actual
RAM-gated behaviours — the Chromium low-memory profile for web pages and
the 1080p video upload cap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(viewer): inject each low-memory flag only when its switch is absent

Copilot review: the previous guard keyed only on
--enable-low-end-device-mode, so a device that pre-set just that switch
(without the renderer/V8 caps) would skip the rest, and a device that
set a different --js-flags value would be silently overridden. Add each
flag independently, matching a valued switch by its "--name=" prefix and
a bare switch by the whole token, so an inherited value on a respawn
isn't duplicated and a switch the operator set on purpose is preserved.
Prepend order is unchanged.

Also assert the prepend order in the test (injected flags precede the
device-supplied one — an accidental append would otherwise still pass)
and add a case for a device that pre-set some switches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 06:50:42 +01:00
..