mem: HG_MALLOC - a hugepage slab allocator with elastic, auto-scaling arenas - #4216
Open
Lt-Flash wants to merge 1 commit into
Open
mem: HG_MALLOC - a hugepage slab allocator with elastic, auto-scaling arenas#4216Lt-Flash wants to merge 1 commit into
Lt-Flash wants to merge 1 commit into
Conversation
…renas Combines the v1 allocator (OpenSIPS#4126: size-class slabs over a self-made hugepage reservation, per-process lock-free free caches, the CPU affinity subsystem that keeps them warm) with the v2 rewrite (in-page buddy grid, class-dedicated blocks, ownership checks on every header read, event-driven GC, corruption counters) and extends them with v3: arenas that grow and shrink at runtime between -m/-M INIT and a pre-fork reserved CAP. Growth commits whole 16 MB granules by mlock, bounded by three independent limits (profile target, backing-tier capacity, host-RAM floor with pkg deltas charged per worker); shrink releases whole-free top granules back to the kernel (MADV_REMOVE returns hugetlb pages to the pool). Policy reuses the auto_scaling_profile grammar via shm_auto_scaling_profile / pkg_auto_scaling_profile; a latched GROW-BLOCKED state raises E_CORE_SHM_GROW_BLOCKED; a dry-run mode narrates decisions without acting. With no cap configured the arena is fixed and behaviour is unchanged. Includes modules/hgstress (multi-process stamp/verify soak driver) and the full operator/design documentation under mem/.
Lt-Flash
force-pushed
the
feature/hg-malloc-v3-master
branch
from
August 15, 2026 04:12
b5f1c50 to
939ad31
Compare
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.
Summary
HG_MALLOCis a core memory allocator: size-class slabs carved from a huge-page-backed reservation the allocator makes itself, with per-process lock-free free caches — and, new in this submission, elastic arenas that grow and shrink at runtime between a starting size and a reserved cap.This supersedes #4126. It combines all features of the v1 and v2 allocator generations and extends them, making it a production-ready allocator:
MAP_HUGETLB→MADV_HUGEPAGE→MADV_COLLAPSE→ plain 4K), every tier verified via/proc, never inferred; and the CPU-affinity subsystem (pin_workers, per-process-type CPU lists, per-UDP-listenerpin_cpus) that keeps the per-process caches warm.class_mismatch,double_free,nfree_underflow,bad_class,foreign_ptr).-m INIT:CAP/-M INIT:CAPreserve the cap as address space pre-fork (free) and commit physical pages only as demand arrives.Why elastic
-mand-Mare fixed at boot, and both are a bet. Bet low and shared memory exhausts in the best traffic hour — allocations fail and the fix is a restart, during the incident. Bet high and pinned memory idles: a production load balancer we measured peaks at 11.9 MB of shm over 15 h of full traffic inside a 128 MB arena, and-Mmultiplies by the worker count — with a fixed-Mevery worker is sized for the busiest worker's worst minute.v3 replaces both bets with a range. Growth commits whole 16 MB granules by
mlock()(populates exactly, clean errno, no fork-window SIGBUS), bounded by three independent limits enforced where each is real: the profile's scale-up target, the backing tier (a hugetlb pool reserves the mapping at map time), and the host's actual free RAM — pkg deltas charged × the worker count. Shrink releases whole-free top granules back to the kernel —MADV_REMOVEon the shm object returns hugetlb pages to the pool for all mappers; private pkg usesMADV_DONTNEED— and never relocates live data. Policy is the existingauto_scaling_profilegrammar:The pkg profile governs every worker's private arena individually, so its numbers are per-worker scale — an order of magnitude below the shared arena's.
A resource refusal (not an admin ceiling doing its job) arms a latched
GROW-BLOCKEDstate: one WARN, a gauge statistic, and anE_CORE_SHM_GROW_BLOCKEDevent re-raised while held — one alertable signal instead of a log flood. A dry-run mode (hg_autoscale_dry_run = 1) narrates every decision without acting. With no cap configured, nothing changes: the arena is fixed at-m/-M, byte-for-byte the fixed-size behaviour. The allocator remains runtime-selected via-a HG_MALLOC; the default allocator is untouched, and without-DHG_MALLOCthe tree builds exactly as before.Measured
hg_adviseMI) replaces multiplier folklore.xychart-beta title "LB: committed MB (top line shm, flat line pkg)" x-axis ["23:49 boot", "23:59", "00:09", "08:19", "10:09", "14:00"] y-axis "committed MB" 0 --> 70 line [64, 48, 32, 48, 34, 34] line [16, 16, 16, 16, 16, 16]xychart-beta title "GW re-cut to -m 8:512 -M 2:32 mid-soak: shm; pkg typical; pkg 3 grown workers" x-axis ["23:50 boot", "00:10", "00:30", "00:57 restart", "01:17 re-cut", "01:19", "14:00"] y-axis "committed MB" 0 --> 70 line [64, 48, 32, 64, 8, 24, 24] line [16, 16, 16, 16, 2, 2, 2] line [16, 16, 16, 16, 2, 18, 18]The LB shrinks an idle 64 to its 32 floor in 20 minutes, grows to 48 under morning traffic, and the after-peak shrink releases only what is genuinely empty (committed lands on 34: 2 MB of the growth still holds a live allocation — by design, nothing is relocated). The gateway was deliberately re-cut mid-soak to a near-empty
-m 8:512 -M 2:32: demand pulled shm from 8 to 24 within two minutes, and exactly 3 of 54 workers grew their private arenas — the other 51 idle at 2 MB. Whole window, both nodes: 0 grow refusals, 0GROW-BLOCKED, all corruption counters 0.Testing
modules/hgstressmulti-process stamp/verify soak (pid-stamped words, re-verified)-WerrorKey kernel behaviours the design rests on were measured, not assumed (and two earlier candidate designs were proven memory-corrupting on rigs before any allocator code was written): post-fork
MAP_FIXEDremapping corrupts pre-forked siblings — hence the pre-fork whole-cap mapping;mlockcommit vs fault-in;MADV_REMOVEreturning hugetlb pages under foreign mlock; map-time hugetlb pool reservation; the fork-window COW margin a hugetlb pool needs.Documentation
Full operator + design documentation ships in-tree:
mem/README.hg_malloc_v3.md(quickstart, concepts, the three-limit ceiling, GROW-BLOCKED, shrink safety argument, profile reference, deployment cookbook with the soak charts, monitoring/alerting, sizing rules, troubleshooting, measured kernel facts, internals map), plusmem/README.hg_mallocandmem/README.hg_arena_v2for the v1/v2 layers.