build: reduce WASM initial memory 128β24 MiB to cut Node load footprint#158
Closed
benasher44 wants to merge 1 commit into
Closed
build: reduce WASM initial memory 128β24 MiB to cut Node load footprint#158benasher44 wants to merge 1 commit into
benasher44 wants to merge 1 commit into
Conversation
0b06fe7 to
fd36006
Compare
The WASM module reserves its full initial linear memory the instant it is instantiated, before any query is parsed. The binaries declared 128 MiB initial (2048 pages), which Node reports as ~129 MB of `external` memory on load regardless of workload β the bulk of the ~200 MB footprint users hit. Since the build already sets ALLOW_MEMORY_GROWTH=1 (max 1 GiB), a large initial value buys nothing: it only inflates the load-time footprint. Static data in the binary is <1 MiB. Two changes: - INITIAL_MEMORY 128 -> 24 MiB. - STACK_SIZE 32 -> 16 MiB (this was the floor on INITIAL_MEMORY). Profiling shows the parser fails cleanly (catchable "memory exhausted" SqlError) under deep nesting rather than overflowing the C stack, and practical nesting depth is bounded well within 16 MiB. Net: `external` at load drops ~129 MB -> ~24 MB. Regression guards (per-package, run by CI which rebuilds the WASM from source): - memory.test.js asserts HEAPU8.buffer.byteLength (the live initial allocation) stays within budget. - deep-nesting.test.js asserts deeply nested input always parses or throws a clean error, never a hard WebAssembly trap β so a too-small stack fails CI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fd36006 to
c83b198
Compare
Contributor
Author
|
I think we're going to just maintain our own native build. Closing for now, but will link here the final direction we take |
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.
Problem
Loading the parser on Node pulls in ~200 MB of memory. The bulk of it is a fixed reservation in the WASM binary itself: the module declared an initial linear memory of 128 MiB (2048 pages), which is allocated when the module is instantiated (before a query is parsed). Node reports this as ~129 MB of
externalmemory immediately on load.The build already sets
-sALLOW_MEMORY_GROWTH=1. I'm not sure what a large initial value buys us. Static data in the binary looks to be <1 MiB.Change
Two build flags, applied to
templates/Makefile.template(regeneratedversions/13β18/Makefile) andfull/Makefile:-sINITIAL_MEMORY134217728)25165824)-sSTACK_SIZE33554432)16777216)ALLOW_MEMORY_GROWTHandMAXIMUM_MEMORY(1 GiB) are unchanged, so the heap still grows on demand. The 32 MiB stack was what pinned INITIAL_MEMORY so high; profiling confirmed deep nesting fails cleanly (a catchableSqlError)well within 16 MiB.Measured impact (Node)
externalat loadRegression guard
memory.test.js: instantiates the module and assertsHEAPU8.buffer.byteLength(the live initial allocation, read before any parse) stays within budgetdeep-nesting.test.js: asserts deeply nested input (up to 10k-deep function-call trees) always parses or throws a clean error, never aWebAssembly.RuntimeError. A stack that's too small would surface as a hard trap and fail CI, so the stack cut is validated by its own test on every rebuild.Notes / scoping
@libpg-query/v13, still 128 MiB), so adding the guard there would fail CI. Its Makefile is updated, so the next real v13 rebuild picks up 24 MiB.copy:templatescopied over v15's forked-repo pin (constructive-io/libpg_query @ fix/negative-int-pg15), which the template doesn't model. I restored it by hand so v15's diff is the memory line only.