Add a compressed swap (zram) toggle and status row to the settings UI - #873
Add a compressed swap (zram) toggle and status row to the settings UI#873yuzi-co wants to merge 1 commit into
Conversation
zram works on this board, but only as a manual install: build the kernel modules, then copy an init script to /etc/init.d by hand. The web UI reports nothing about it, so an operator cannot tell whether compressed swap runs, or how close it is to its memory cap. This adds one row to Settings > Device > Advanced that reports the state and switches it on or off. The row reports three independent booleans rather than one flag. Available is whether the kernel modules are present, enabled is whether the init script is installed, and active is whether /dev/zram0 is in /proc/swaps. "Enabled but not active" is the state that matters most, and a single flag would render it as plain "off" -- inviting the operator to toggle it on and watch nothing happen. The row shows it in amber instead. The modules stay a manual step. zram and zsmalloc are built out of tree against the stock kernel and pinned to its vermagic, so shipping them in the install package would mean reshipping them whenever the kernel moves. tools/zram/build-modules.sh builds both. Without them the toggle is disabled and says so. S01zram lives in kvmapp/system/init.d so the package carries it and the server has a source to copy from. It is deliberately not added to the copy list in system_init.cpp: that list is hard-coded C++, and a name added there needs a MaixCDK rebuild plus a kvm_system redeploy on every device. The server owns the copy, the way S98tailscaled already treats presence in /etc/init.d as the installed marker. A start that produces no device rolls the install back, so enabled never claims a reboot will help. Three defects surfaced while wiring this up, and all three are fixed here. disableSwap ran `swapoff -a`, which stops every swap device. Any change to the swap file control therefore stopped zram as a side effect, which is not what a control labelled "swap file size" should do. It now names the file, and skips the call entirely when that file is not swapped on -- swapoff fails on an inactive file, and the -a form used to hide that by succeeding on some other device. S01zram did not reset a device that was already initialised. The script only ever ran at boot, where a freshly inserted module reports disksize 0. A toggle introduces a stop-then-start on a live device, the kernel rejects the second disksize write with EBUSY, and the start returns 1: + echo 96M sh: write error: Resource busy + echo 'FAIL (disksize)' start now resets a device that reports a non-zero disksize. The caller has already established the device is not in /proc/swaps, so the reset cannot take swap away from anything. S01zram did not set a swap priority. Both swaps are enabled during boot and the order between them is undefined. It now asks for -p 100 and falls back to a plain swapon, because a busybox applet built without FEATURE_SWAPON_PRI rejects the option. This image's BusyBox 1.36.1 is such a build: swapon offers only -a and -e, so neither -p nor a pri= in fstab can set a priority. The -p attempt stays, because it is correct elsewhere and the fallback costs the priority rather than the swap. Boot order does not compensate for that. The swap file is enabled from a si11::sysinit line and S01zram runs from the rcS wait entry, and BusyBox init runs every sysinit entry before any wait entry. So the swap file is always swapped on first and always takes the better priority. Enabling both on this board means the kernel writes to the SD card before compressed RAM. The two controls stay independent, and tools/zram/README.md says why you should still pick one. Verified on hardware: the stale-device start reproduced the EBUSY failure and now reports OK. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015uHXYqo7YSPMWy76LhjHfR
|
SG2002 cpu is so weak, add zram only turn whole system into unusable. |
|
Fair concern, so I measured it on the board rather than argue it. SG2002, hardware revision beta, The premise is right: there is almost no headroom during a session. With one MJPEG viewer What zram costs on top of that, measured on a second device added with
At rest it costs nothing: the codec runs on swap I/O and nothing else, and a 20 s idle sample moved Under load. One viewer at a time, with zram compressing 8 MB every 2 s without pause. Every
MJPEG loses frames, and it starts from a board already at 92% before zram runs at all. The session The difference is delivery, not capture. All three paths capture the same frames through the same Two notes on method. An earlier version of this comment quoted an MJPEG run with the viewer on the The alternative is not free either. zram sits beside a swap-file control, and root here is a One caveat I won't leave out: a memory-pressure test left the board unable to start any process The feature is off unless an operator turns it on, and it cannot be turned on at all until someone |
The SG2002 board has ~158MB of usable RAM after the 75MB ION carveout, and the only swap the UI offers is a file on the boot SD card — the card that
Settings > Swapwarns will wear out. zram gives the same relief in compressed RAM, with no card wear at all.zram already works on this hardware today, but only as a manual install: build the modules, copy an init script to
/etc/init.dby hand. Nothing in the web UI reports it, so an operator cannot tell whether compressed swap is running or how close it is to its memory cap.This adds one row to
Settings > Device > Advanced.Three booleans, not one flag
The row reports
available,enabledandactiveseparately:availableenabled/etc/init.d/S01zramis installed, so the setting survives a rebootactive/dev/zram0is in/proc/swapsright now"Enabled but not active" is the state that matters most. A single flag renders it as plain "off", which invites the operator to toggle it on and watch nothing happen. The row shows it in amber and says so.
When zram is running the row also reports the algorithm, the compression ratio, memory used against the memory cap, and the system-wide
pswpin/pswpoutcounters.The kernel modules stay a manual step
zramandzsmallocare not in the stock image —CONFIG_ZSMALLOCis unset, so zram needs both. They are built out of tree against the stock kernel and pinned to its vermagic, so shipping them inside the install package would mean reshipping them whenever the kernel moves.tools/zram/build-modules.shbuilds them;tools/zram/README.mddocuments it.Without the modules the toggle is disabled and states why. No dead control, no silent failure.
Why the server installs the init script
S01zramships inkvmapp/system/init.d/so the package carries it and the server has a source to copy from. It is deliberately not added to the copy list insystem_init.cpp: that list is hard-coded C++, and adding a name there needs a MaixCDK rebuild plus akvm_systemredeploy on every device. The server owns the copy instead, the wayS98tailscaledalready treats presence in/etc/init.das the installed marker.A start that produces no device rolls the install back, so
enablednever claims that a reboot will help.Three defects fixed on the way
disableSwapranswapoff -a. That stops every swap device, so any change to the swap file size stopped zram as a side effect — not what a control labelled "swap file size" should do. It now names the file, and skips the call entirely when that file is not swapped on. (swapofffails on an inactive file; the-aform used to hide that by succeeding on some other device.)S01zramdid not reset a device that was already initialised. The script had only ever run at boot, where a freshly inserted module reportsdisksize 0. A toggle introduces a stop-then-start on a live device, and the kernel rejects the seconddisksizewrite:startnow resets a device reporting a non-zero disksize. The caller has already established the device is not in/proc/swaps, so the reset cannot take swap away from anything.S01zramset no swap priority. It now asks for-p 100and falls back to a plainswapon, because a BusyBox applet built withoutFEATURE_SWAPON_PRIrejects the option — and this image's BusyBox 1.36.1 is such a build. Boot order does not compensate: the swap file is enabled from asi11::sysinitline andS01zramruns from thercSwait entry, and BusyBox init runs every sysinit entry before any wait entry. So on this board the swap file always wins the better priority. The two controls stay independent, andtools/zram/README.mdsays why you should still pick one rather than enabling both.API
Both sit behind the same auth middleware as the rest of
/api/vm.Testing
server/service/vm/zram_test.goandswap_test.go— the service reads and writes through injectable paths and a command seam, so the whole state machine is covered off-device, including the rollback path and every parse failure.tools/zram/test-zram-swapon.shandtest-zram-reset.sh— on-device checks for the priority fallback and the stale-device reset.EBUSYfailure and now reports OK.Only
en.tscarries the new strings; the other locales fall back to English until translated.