runtime: count container allocations too, not just strings #135

Merged
will.anderson merged 1 commits from feat/alloc-accounting-containers into dev 2026-08-16 02:37:15 +00:00
Owner

el #131 instrumented the four string allocators, so list- and map-heavy code reported zero allocations. A benchmark over lists would have been fitted against a flat line and passed anything.

Caught during framework work: a "linear" specimen read 0 allocs until rewritten to allocate strings. A signal that silently reads zero is worse than no signal — it produces a confident pass.

Now counted at every container allocation: ElList/ElMap bodies, backing arrays, copy-on-write clones, and the realloc growth path.

Verified on an append loop (n = 100..800):

n allocs bytes
100 7 2,048
200 8 4,096
400 9 8,192
800 10 16,384

allocs +1 per doubling = O(log n) reallocations; bytes exactly 2× per doubling = O(n). Both are what correct amortized growth looks like — and both read zero before this change.

Remaining scope stated explicitly: these cover the runtime's own allocations, not malloc inside engram_*.c or libcurl. That's correct — the gate is for El-level complexity.

el #131 instrumented the four **string** allocators, so list- and map-heavy code reported **zero allocations**. A benchmark over lists would have been fitted against a flat line and passed anything. Caught during framework work: a "linear" specimen read 0 allocs until rewritten to allocate strings. **A signal that silently reads zero is worse than no signal — it produces a confident pass.** Now counted at every container allocation: `ElList`/`ElMap` bodies, backing arrays, copy-on-write clones, and the realloc growth path. **Verified** on an append loop (n = 100..800): | n | allocs | bytes | |---|---|---| | 100 | 7 | 2,048 | | 200 | 8 | 4,096 | | 400 | 9 | 8,192 | | 800 | 10 | 16,384 | allocs +1 per doubling = O(log n) reallocations; bytes exactly 2× per doubling = O(n). Both are what correct amortized growth looks like — and both read **zero** before this change. Remaining scope stated explicitly: these cover the runtime's own allocations, not malloc inside `engram_*.c` or libcurl. That's correct — the gate is for El-level complexity.
will.anderson added 1 commit 2026-08-16 02:36:56 +00:00
runtime: count container allocations too, not just strings
El SDK CI - dev / build-and-test (pull_request) Failing after 12m11s
a8908908df
el #131 instrumented the four string allocators, which meant list- and map-heavy
code reported ZERO allocations — a benchmark over lists would have been fitted
against a flat line and passed anything. Caught during framework work: a
"linear" specimen read 0 allocs until it was rewritten to allocate strings.

A gate is only as good as its blind spots are small, and a signal that silently
reads zero is worse than no signal: it produces a confident pass.

Now counted at every container allocation — ElList and ElMap bodies, their
backing arrays, the copy-on-write clones, and the realloc growth path.

Verified on an append loop (n = 100..800):
    allocs  7, 8, 9, 10          +1 per doubling = O(log n) reallocations
    bytes   2048, 4096, 8192, 16384   exactly 2x per doubling = O(n)

Both curves are what correct amortized growth should look like, and both read
zero before this change.

Known remaining scope, stated rather than left implicit: these counters cover
the runtime's own allocations. They do not see malloc inside engram_*.c or
libcurl, which is correct — the gate is for El-level complexity, not for
third-party memory behaviour.
will.anderson merged commit 9e96d74f6a into dev 2026-08-16 02:37:15 +00:00
Sign in to join this conversation.