| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| README.md | 2026-08-03 | 6.5 kB | |
| v0.6.3 source code.tar.gz | 2026-08-03 | 1.2 MB | |
| v0.6.3 source code.zip | 2026-08-03 | 1.3 MB | |
| Totals: 3 Items | 2.5 MB | 0 | |
Fixed
- The automatic budget sized against the host's RAM inside a container
(#14).
waste_physical_ram()issysconf(_SC_PHYS_PAGES)on Linux, which reports the host'sMemTotalfrom inside a cgroup that is allowed a fraction of it, so a--budget-less open resolvedfloor + 3xagainst memory the kernel would never hand over: K3 in a 32 GiB cgroup on a large host asks for ~80 GB and is killed. Unlike the paging cliff of LEARNED.md §16 this has no gradual form and no cache policy softens it. The ceiling is nowmin(physical, cgroup limit)— the smallest finitememory.maxormemory.highacross the cgroup and its ancestors, since the limit is hierarchical — and the rest of the resolver is unchanged. See §40.
Current pressure (MemAvailable, memory.current) was considered and
deliberately left out: a budget is resolved once and held for a whole run,
so bounding it by an instantaneous sample would make the same command on
the same machine two different runs. Whether it should trim the working-set
multiplier instead is [#14], still open.
-
tools/convert.pyspawned--jobs× cores threads (#13, contributed by @andrewwhitecdw). torch sizes its intra-op pool fromos.cpu_count(), and the native VQ encoder readsnthreads=0as "every core" (capped at 64), so N worker processes meant N×cpus threads competing for the machine: on a 224-core box--jobs 8spawned ~1792 threads and the codebook phase ran ~20x slower than the measured baseline. Each worker is now capped at its fair share,cpu_count // jobs, for both pools — set in the parent before the workers spawn, since that is the only point torch reads it, and withsetdefault, so an explicitOMP_NUM_THREADSstays the caller's. -
The trace simulator modelled a different cache than the engine.
tools/routing_stats.py simulatekept a frequency count across evictions thatec_claimresets and sampled 32 victims whereEC_SAMPLEis 16: against the same trace it read 36.6% where the engine measured 30.4% — optimistic, plausible and wrong. Both constants now come fromecache.c, which brings it within 1.5 points across a 0–30% range, andtests/run.shasserts the agreement rather than remembering it. Two smaller things went with it: the route dump writes the absolute position of the token each row belongs to, so readers stop re-deriving token boundaries from where the layer index wraps (a heuristic that is simply wrong on the chunked path, where rows group by layer), andsimulate --datatakes a container, whose manifest states the record size the engine actuallypreads. See §37, The simulator was modelling a different cache.
Added
-
waste_usable_ram(): physical RAM, or a smaller cgroup-v2 limit when one applies — what a budget of 0 sizes against, and what an embedding host should size its own ceiling from.waste plan --jsonreports it besidephysical_ram_bytes, which stays what it always was. -
tests/sweep.c, a one-process measurement harness. It loads a container once and runs the arms back to back, interleaved, resetting the session and clearing the expert cache between each — a warm cache would hand the second arm the first one's work and measure the order instead of the setting. Kimi-Linear, two arms, three repeats: spreads of 2.6% and 0.5%, where nine paired runs of the same comparison across processes spanned 0.79x to 1.79x. The variance was the harness, not the feature. On K3 the deterministic columns come out exact and the clock still drifts, which is the machine's memory system rather than the process — what the harness buys there is that the noise is visible as noise. §38. -
docs/TECHNICAL.mdandexamples/. The measurement tables move out ofREADME.mdinto TECHNICAL.md, andexamples/carries three compilable programs against the public header —api_plan.c(budget arithmetic without loading),api_text.c,api_vision.c— with a README that walks through them.
Changed
- §4's cache floor still reproduces exactly, and has stopped binding. The oldest load-bearing measurement here — below one token's working set the hit rate is zero, not low — was re-measured across four cache sizes in one process, two repeats, hit rate and bytes read identical to the digit across both:
| budget | expert cache | slots | hit | decode |
|---|---|---|---|---|
| 32 GB | 3.32 GB | 287 | 29.1% | 0.56–0.58 tok/s |
| 46 GB | 17.32 GB | 1498 | 36.2% | 0.63 tok/s |
| 52 GB | 23.32 GB | 2018 | 38.4% | 0.07–0.09 tok/s |
| 58 GB | 29.32 GB | 2537 | 41.3% | 0.07–0.08 tok/s |
The 29.1% at 287 slots is not a refutation of §4: with the lookahead off the same 287 slots give 0.0%, exactly §4's zero. What breaks it is that a speculative record has to survive one attention rather than one token, so a cache far too small for a token's working set is ample to hold six experts. A 3.32 GB cache is now within 10% of a 17.32 GB one, which means the premise the default resolver is built on — that cache is only worth buying in whole multiples of a working set — no longer holds. The resolver is unchanged: that is a decision, not a measurement, and it is GATES.md Gate 7, open. The cliff is exactly where it was, and the last two rows say what it is — throughput falls eightfold while the hit rate rises and the bytes read fall, because the engine is inside its budget and the machine is not. §39.
- 0.6.2's "total bytes read unchanged" for the router lookahead was the harness. Measured with both arms starting from an identically cleared cache, the byte economics depend on the cache size: 6.6% fewer bytes at 1498 slots, 8% more at 287, where speculative records are evicted before use often enough to be re-read. It is a prefetch at small caches and a scheduling change at large ones, and 0.6.2 measured only the large end. The feature and its default are unchanged. §38, §39.
Section numbers refer to docs/LEARNED.md, which carries the reasoning and the full measurements behind each entry. The two §37s and two §33s there are noted in that file's preamble and cited by title where it matters.
Full Changelog: https://github.com/sqliteai/waste/compare/v0.6.2...v0.6.3