Memory-optimization measurements: full branch vs audited subset

Public edition, 2026-07-20. This is a trimmed copy of an internal report: internal cross-references and the analysis of one unrelated defect (tracked separately) are removed. All measurements, procedure details, and provenance identifiers are unchanged.

What was measured, and why

SoftAtHome's memory-optimization work for prplware was delivered as a set of component branches based on prplOS 4.2.0. In a separate commit audit, every one of the branch set's 1,037 commits was classified twice by independent reviewers, with each disagreement settled against the full diff. The audit's conclusion: 117 component commits (90 memory optimizations plus 27 build and API dependencies) and 9 prplOS-side commits carry the actual memory work, while the other 920 commits are unrelated features, CI changes, and packaging churn.

This report answers the follow-up question: do images built from only those audited commits (the "surgical" subset) deliver the same memory savings as images built from the full branches? The comparison ran on two bases: prplOS 4.2.0, where the optimization branches originated, and current latest-24.10.

Headline results

On 4.2.0, the subset delivers the full branch's savings. Vanilla (M0) runs at 178,514 KiB of userspace memory; the full branch (M1) reduces that by 9,551 KiB, and the subset (M2) by 9,943 KiB, which is 104.1% of the full branch's reduction. The small overshoot is within the per-boot spreads and is not claimed as a win on its own.

On latest-24.10, the subset beats the full branch. The subset (M4) reduces memory by 5,146 KiB against vanilla (M3); the full branch (M5) reduces it by only 1,631 KiB, leaving the full-branch image 3,515 KiB heavier than the subset image. On this base, the commits the audit classified as unrelated cost memory rather than saving it. One caveat applies to M5 and is noted in the process comparison below.

How the measurements were taken

Every image ran in the same QEMU/KVM virtual machine with 512 MiB of RAM, booted three times, with 180 seconds of settle time before capture. Two metrics were recorded:

All figures are medians over the three boots, with the spread between the best and worst boot alongside. The measurement procedure, test list, and virtual-machine shape were identical, byte for byte, at all six points.

One acquisition note: the CI job for M1 (14922716187) failed because a source tag had been deleted upstream, so M1 was rebuilt locally from that job's retained CI configuration, which was verified byte-identical.

Point Description Userspace PSS median KiB Spread MemAvailable median KiB Spread Image bytes SquashFS bytes
M0 vanilla 4.2.0 178,514 1,590 237,872 1,592 174,358,548 31,185,344
M1 full branch (locally built substitute), 4.2.0 168,963 3,905 247,096 5,100 174,358,548 31,285,428
M2 surgical subset, 4.2.0 168,571 1,514 247,912 1,792 174,358,548 31,184,818
M3 vanilla latest-24.10 183,492 2,184 236,428 2,188 174,358,548 33,159,492
M5 full branch, latest-24.10, CI job 15421624536 181,861 294 237,272 796 174,358,548 33,231,680
M4 surgical subset, latest-24.10 178,346 396 240,496 1,264 174,358,548 33,163,708
Comparison PSS delta KiB MemAvailable delta KiB Interpretation
M1 − M0 -9,551 +9,224 full-branch reduction on 4.2.0
M2 − M0 -9,943 +10,040 surgical-subset reduction on 4.2.0
M2 − M1 -392 +816 subset and full branch are effectively at parity
M5 − M3 -1,631 +844 full-branch reduction on latest-24.10
M4 − M3 -5,146 +4,068 surgical-subset reduction on latest-24.10
M4 − M5 -3,515 +3,224 subset vs full branch, directly, on latest-24.10

The other median meminfo values were:

Point MemFree KiB Cached KiB Slab KiB
M0 40,628 198,988 61,268
M1 49,744 198,720 62,028
M2 51,252 198,648 61,380
M3 27,124 207,780 63,008
M5 28,284 207,808 63,620
M4 32,416 207,448 63,108

Per-process comparison on 4.2.0

The totals break down by process as follows, using the subset image's top 20 processes by memory. Deltas are signed KiB; negative means less memory used.

Process M0 M1 M2 M1−M0 M2−M0 M2−M1
unbound 10,431 8,437 10,467 -1,994 +36 +2,030
beerocks_contro 9,114 9,212 8,962 +98 -152 -250
beerocks_agent 8,158 8,164 8,119 +6 -39 -45
obuspa 7,905 7,860 7,821 -45 -84 -39
ubusd 8,040 7,711 7,655 -329 -385 -56
syslog-ng 6,514 6,570 6,510 +56 -4 -60
wld 5,743 5,605 5,568 -138 -175 -37
tr181-firewall 9,137 5,545 5,541 -3,592 -3,596 -4
cthulhu 5,195 5,082 4,983 -113 -212 -99
beerocks_fronth 4,642 4,554 4,578 -88 -64 +24
netmodel 3,476 3,477 3,404 +1 -72 -73
netmodel-client 4,641 3,474 3,353 -1,167 -1,288 -121
beerocks_vendor 2,855 2,862 2,870 +7 +15 +8
ip-manager 2,929 2,601 2,568 -328 -361 -33
deviceinfo-mana 2,477 2,507 2,504 +30 +27 -3
ieee1905_transp 2,399 2,432 2,444 +33 +45 +12
pcm-manager 2,138 2,137 2,147 -1 +9 +10
tr181-upnpdisco 2,032 2,021 2,006 -11 -26 -15
lighttpd 1,977 1,988 1,988 +11 +11 0
tr181-ipdiagnos 1,967 1,874 1,890 -93 -77 +16

The firewall and netmodel-client reductions reproduce or slightly exceed the full branch, and the rest of the subset's top 20 stays close to it. Two larger differences have known causes in how the subset was selected:

Per-process comparison on latest-24.10

The same breakdown for latest-24.10: vanilla M3, full branch M5, subset M4, and all three deltas.

Process M3 KiB M5 KiB M4 KiB M5−M3 KiB M4−M3 KiB M4−M5 KiB
beerocks_contro 9,449 9,521 9,416 +72 -33 -105
obuspa 9,329 9,409 9,264 +80 -65 -145
unbound 8,454 8,432 8,441 -22 -13 +9
ubusd 8,571 8,255 8,223 -316 -348 -32
beerocks_agent 8,120 8,221 8,213 +101 +93 -8
syslog-ng 6,205 6,237 6,207 +32 +2 -30
wld 6,146 6,151 6,155 +5 +9 +4
tr181-firewall 8,149 5,745 5,753 -2,404 -2,396 +8
cthulhu 5,070 5,186 5,159 +116 +89 -27
rlyeh 4,957 4,934 4,848 -23 -109 -86
beerocks_fronth 4,572 4,519 4,536 -53 -36 +17
netmodel 3,459 3,528 3,444 +69 -15 -84
netmodel-client 4,525 3,358 3,389 -1,167 -1,136 +31
tr181-security 3,150 3,163 3,172 +13 +22 +9
beerocks_vendor 2,735 2,754 2,798 +19 +63 +44
deviceinfo-mana 2,673 2,734 2,705 +61 +32 -29
ip-manager 2,673 2,694 2,646 +21 -27 -48
pcm-manager 2,322 2,334 2,354 +12 +32 +20
ieee1905_transp 2,354 2,402 2,350 +48 -4 -52
tr181-upnpdisco 2,079 2,142 2,130 +63 +51 -12

The dominant reductions are shared by the full branch and the subset: firewall (-2,404 and -2,396 KiB), netmodel-client (-1,167 and -1,136 KiB), and ubusd (-316 and -348 KiB). Their direct M4−M5 deltas are only +8, +31, and -32 KiB. M4 is also 139 KiB below M5 in gmap-server and 26 KiB below in hosts-manager, matching the selected gMap and hosts work. tr181-device (-312 KiB) and tr181-dynamicdns (-200 KiB) are the largest other M4−M5 reductions; both have retained accessor-conversion commits in the subset.

Two comparisons need explicit qualification:

Because the full branch reduces latest-24.10 memory by only 1,631 KiB while the subset reduces it by 5,146 KiB, a "share of the reduction recovered" figure computes to 315.5% and is not meaningful on this base; it is recorded as informational only. The direct comparison stands: the subset image is 3,515 KiB lighter in PSS and 3,224 KiB better in MemAvailable than the full-branch image.

Functional test parity

Alongside the memory numbers, every image ran the same seven functional tests from the prplOS cram suite (cram replays a recorded shell session and diffs the output). These runs check parity: an optimized image must not change any test result relative to its own vanilla baseline. Absolute pass rates are a property of the baselines and of the reduced test environment described below, not of the optimization work; both baselines fail several of these tests, and what matters is that the optimized images fail exactly the same ones, in the same way. Empty output or a missing or invalid test-result file counts as a harness error, and the results below come from parsed xUnit files.

Point Run Primary pass/fail Post pass/fail Harness errors Parity result
M0 cram-20260719T175922Z 0 / 6 0 / 1 0 adopted 4.2.0 baseline; determinism proven by two byte-identical runs
M1 cram-20260719T173323Z 0 / 6 0 / 1 0 same test-status set as M0
M2 cram-20260719T213230Z 0 / 6 0 / 1 0 same set as M0/M1; no pass regressed
M3 cram-20260719T181657Z 1 / 5 0 / 1 0 adopted latest-24.10 baseline; obuspa.t passes
M5 cram-20260720T081040Z 1 / 5 0 / 1 0 same test-status set as M3/M4
M4 cram-20260719T232851Z 1 / 5 0 / 1 0 same set as M3; obuspa.t remains passing

One correction was needed along the way: the first M4 test run showed one extra failure because the chosen prplOS test fixture still contained an expectation line produced by a feature commit the audit had dropped. That single line was removed, the rebuilt image came out byte-identical, and the final run above matches M3 exactly. No expectation belonging to selected behavior was weakened.

All accepted runs of the subset images reached steady state with dropbear, ubusd, amxrt, and the Ambiorix plugins running; M4 additionally shows gmap-server running. The captured evidence scans show no oops, kernel panic, out-of-memory kill, or segmentation fault on any accepted subset run. The post-test failure and nine cthulhu assertion messages appear identically in the vanilla baselines; they are pre-existing behavior, not something the subset introduced.

The test environment is QEMU user-mode networking with a single NIC, so the interfaces eth1, br-guest, and br-lcm do not exist in the guest. Firewall, QoS, and the post test therefore run with reduced scope, and their value here is output identity between baseline and optimized images rather than full functional coverage. This limitation applies equally at all six points.

Dependency and adaptation ledger

Building the subset surfaced a handful of commits that the audited picks need but that the audit had not selected, for example an API function a retained commit calls. Every such addition is listed here with its reason, so the subset's exact content stays fully accounted for and the set could not grow quietly.

Base Item Kind Reason and scope
4.2.0 libamxd flag storage 07e50d86e068 exact semantic dependency, adapted supplies the set-backed flags required by retained accessors; folds only the required header half of its companion
4.2.0 libamxo flag serialization 9a0e036679d4 exact dependency serializes the set-backed flags consumed from libamxd
4.2.0 libamxc amxc_var_is_empty 9382ac5d16ee exact dependency supplies the API used by retained router-advertisement code
4.2.0 hosts-manager opaque sync context authored narrow adaptation pointer/new/delete conversion preserves alternative-device synchronization
4.2.0 gmap generated install rule ae42705f9503 exact generated companion installs debug_definition.odl; without it gmap-server crash-looped, so the first image was rejected
latest-24.10 libamxc amxc_var_is_empty 9382ac5d16ee exact dependency pinned v2.7.1 lacks the API required by the retained router-advertisement pick
latest-24.10 hosts-manager opaque sync context authored narrow adaptation pointer/new/delete conversion avoids importing unrelated feature removal
latest-24.10 gmap generated install rule ae42705f9503 exact generated companion keeps generated installation in sync with the selected debug model

Every item has exact commits, build evidence, and rationale in the internal campaign records. Images from the intermediate failed builds were never measured.

Cross-check against the backport inventory

Confluence page 2238382515 (version 9, "2026-07-10: Memory (Backports, Future Enhancements)") lists the intended backport areas. It was fetched read-only after the subset was frozen and used as a completeness cross-check, not as a source of new commits.

Inventory area Surgical coverage
Ambiorix/generic model and accessor work covered across the selected libraries, modules, and plugins
Firewall and QoS covered, including required dependency/fix chains
gMap and hosts covered; generated-file and opaque-context ledger items documented
PCM and UPnP covered by selected component commits
DHCP, WAN, dynamic DNS configuration covered by selected managers/plugins
Unbound, ZRAM not covered; separate future tracks
prplMesh and profile-level reductions not covered by this frozen campaign
syslog-ng, OB-USPA, CPU, data-model profiles not covered; future/separately scoped work

Provenance and limitations