perf(agent): ship the release binary uncompressed — UPX cost 19 MB RSS and 300 ms per exec#30
Merged
Merged
Conversation
…S and 300 ms per exec `upx --best --lzma` self-extracts the entire image into anonymous memory at exec, which defeats demand paging. The text segment stops being a clean, shared, file-backed mapping and becomes private dirty anon: unevictable (swap-only) and unshareable between processes. It also has to inflate all ~24 MB before `main` runs — an LZMA stream is sequential, so there is no paging in only the code a given invocation actually calls. Measured on the release binary: idle RSS 12.1 MB → 28.8 MB (+19 MB; 26.6 MB of it private dirty anon vs 2.6 MB before) `--version` 4.5 ms → 305 ms (~68x, 30 runs each, warm cache) And the payoff was smaller than it looked: the asset is already gzipped by `tar -czf`, so dropping UPX takes it from 6.8 MB to 9.8 MB — a 3 MB one-time download, not the ~18 MB the raw binary sizes suggest. 3 MB off a download does not justify 19 MB of RAM in a session-multiplexing daemon (~2.5% of a 754 MB node, permanently, before it serves a single session), nor 300 ms on every invocation of a binary that also ships one-shot CLI subcommands (`run`, `tools`, `login`). The old step's comment — "a trivial one-time self-extract at exec" — was true about CPU only in the sense that nobody had timed it, and said nothing about memory. Left a note in its place so the step doesn't get re-added to shave the asset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Drops the
upx --best --lzmastep from the agent's release workflow. The publishedbeyond-ai-agenttarball now contains a plain static-musl binary.Why
UPX makes a self-extracting binary: at exec it decompresses the whole image into anonymous memory and jumps in. That defeats demand paging. Normally the text segment is a clean, shared, file-backed mapping — the kernel pages in only the code you actually execute, drops those pages for free under pressure, and shares one copy across processes. After UPX it's private dirty anon: unevictable (swap-only), unshareable, and fully resident, because an LZMA stream is sequential so there's no way to inflate only the parts a given invocation calls.
Measured on the release binary (
smaps_rollup, idleserve; 30 warm runs for startup):--best --lzma--version(median)Of the 24.5 MB binary, only 7.4 MB was ever resident under demand paging — ~17 MB is code (OAuth flows, MCP transports, unused provider dialects) that never ran and never cost RAM. UPX materializes all of it.
And the payoff was smaller than the raw binary sizes suggest. The asset is already gzipped by
tar -czf, so gzip was doing most of UPX's job for free:tar -czftar -czfSo UPX bought 3 MB of one-time download in exchange for ~19 MB of RSS and ~300 ms per exec.
Neither cost is worth it for how this binary is actually deployed. As a session-multiplexing daemon, that 19 MB is ~2.5% of a 754 MB node, held permanently, before it serves a single session — spending the RAM budget on compressed-binary overhead is backwards when the whole point of the architecture is packing sessions into one process. And the same binary ships one-shot CLI subcommands (
run,tools,login), which would eat 300 ms of LZMA before doing anything at all — including on--help.The step's comment claimed "a trivial one-time self-extract at exec." It's trivial in neither dimension; it was true about CPU only in the sense that nobody had timed it, and it said nothing about memory. Replaced with a note recording the measurements, so the step doesn't get re-added later to shave 3 MB off the asset.
Notes
🤖 Generated with Claude Code