Goose

slot_pool versus reusable

reusable and reusable[] remain deprecated but available. These comparisons keep the builtins as baselines; removal is a separate change. Application measurements and migration decisions are in pool_workloads.md.

The library uses the builtin’s LIFO free-index policy. Both versions allocate initialized slots, retain stable addresses, and check indices. The workload uses two local owners, calls the same exercise helper with each, and checks allocation order and final contents.

Current measurements

Measured 2026-10-28 on Windows, Ryzen 9 9950X3D, CPUs 16–31. Ratios are library / builtin; smaller is better. Clang compiles the generated C at O2. Each cell is the ratio of median process-cycle counts from seven interleaved samples after two warmups, with identical checksums. The six-case means give equal weight to each workload/size pair. These allocation-heavy loops have no application work between operations.

Workload Bytes O1 Clang O1 TinyCC O1 JIT total O2 Clang O2 TinyCC O2 JIT total
append 8 1.029 0.968 1.029 0.981 0.973 1.033
append 128 0.990 0.996 1.012 0.964 0.997 1.004
lifo 8 0.861 0.939 1.001 0.872 0.926 1.009
lifo 128 0.904 0.986 1.095 0.879 0.983 1.066
scattered 8 0.913 0.952 0.990 0.888 0.962 0.988
scattered 128 0.911 1.011 0.936 0.873 1.012 0.920
Geometric mean 0.933 0.975 1.009 0.908 0.975 1.002

Standalone TinyCC measures execution only. JIT total includes Goose compilation, TinyCC compilation and execution at the stated optimization level; it is not an allocation-only measurement. O2 is now the default. Process startup, initialization and final checksumming are included on both sides. Wall times are also retained, but were more sensitive to background activity than process cycles.

Reproduce

python bench/slot_pool.py --exe build-root/Release/goose.exe --levels 1 2 --calls natural --widths 1 16 --compilers clang tcc jit --reps 7 --warmups 2 --cpus 16-31 --out build-root/review-final-slot

The harness saves Goose/C snapshots, logs, checksums, compiler and library fingerprints, sizes and all samples under --out. The checked-in current results contain this matrix. --levels 0 is also supported. --calls natural leaves the emitted C unchanged; boundary adds GS_NOINLINE to the native exercise function, while inline requests inlining. JIT always uses the compiler's unmodified output. TinyCC is discovered beside the Goose build or on PATH. MSVC is available via --compilers msvc; timings here use Clang, standalone TinyCC and the JIT.

Interpretation and remaining work

alloc_ref returns the append result directly. Index builders and reference frees are available as alloc_index_with and free_ref; application results using them are in pool_workloads.md. The library keeps its index checks, and no occupancy tracking or private-field assumption was added.

Native Clang and standalone TinyCC both meet the general microbenchmark goal. TinyCC keeps every C temporary in memory and copies a struct assignment with string moves (movsq), so until 2026-10-28 the library's 8-byte reuse ran 1.14–1.20x the builtin's under it (geometric mean 1.08–1.10). The compiler changes that closed it are general: a pop the preceding length test makes safe drops its emptiness check (bounds-check elimination), pops, pushes and element reads and stores keep no temporaries they do not need, a small struct variable is stored as one integer, and i < 0 || i >= items.len is one unsigned comparison. The index check on a slot popped from the public freelist stays. JIT totals, which include compiling each program, are at parity on average.