ReviewOS

zig-utils/zig-gc

Perf: avoid alloc-lock CAS storms under many mutators

#26
Closed chris opened this 9 days ago ·
9 days ago

Downstream zig-js shared-realm object churn spent its dominant mutator time contending on Heap.alloc_lock while publishing fixed-size batches. A 20-second macOS sample at zig-js 5cd13df3 / zig-gc 9d4af0d placed 24,746 collapsed top-of-stack samples in gc.allocObjectBatch; the hottest instruction was the failed CAS loop in lockAlloc, while libc allocation and backing chunk growth were negligible.

The previous test-and-set loop issued a write-intent CAS on every losing pass. With eight mutators this created a cache-line write storm and could starve the thread holding the short publication critical section.

The shipped test-and-test-and-set policy read-spins while the lock is visibly owned and periodically yields under sustained contention. Seven-sample exact downstream probes (shared object_churn, 100 jobs) measured:

  • parent 1 lane: 143.290 ms median
  • parent 8 lanes: 1,319.888 ms median
  • TTAS + yield every 64 read-spins, 8 lanes: 1,164.047 ms median (11.8% lower)

Pure read-spin and a more aggressive 16-spin yield were both rejected because they regressed the eight-lane median. A 256-spin yield also improved the parent but was slower than the 64-spin policy.

Acceptance

  • Avoid repeated failing CAS writes while a peer owns the allocation metadata lock.
  • Preserve the uncontended path and all allocation/collection ordering.
  • Pass zig-gc unit tests and downstream focused allocation/GC tests.
  • Confirm the downstream eight-lane improvement with an exact-parent A/B and TSan/full CI.

Implemented by decff85; final downstream normal/TSan verification: https://github.com/zig-utils/zig-js/actions/runs/29466730465

9 days ago

Implemented and pushed as decff85. Validation so far: zig-gc full unit suite passes; zig-js focused shared fixed-shape allocation test passes (2/2, zero leaks). Exact downstream seven-sample control improved from 1,319.888 ms to 1,164.047 ms at eight lanes (11.8% lower), while rejected pure-read-spin and 16-spin policies are recorded in the issue body. Leaving open until a fresh downstream full/TSan run covers decff85.

9 days ago

Implemented by decff85 and verified downstream through zig-js CI run 29466730465.

  • The allocation metadata lock now read-spins while visibly owned, avoiding repeated failing write-intent CAS operations while preserving the uncontended path.
  • The selected 64-spin yield policy improved the exact downstream shared eight-lane object-churn median by 11.8% versus its parent; rejected variants were documented rather than shipped.
  • zig-gc heap tests and downstream focused allocation/GC tests passed.
  • The complete downstream normal and TSan gates passed, including parallel JS, lifecycle fuzzing, mid-GC fuzzing, all unit shards, and all suppression-free corpus shards.

Acceptance is complete.

Sign in to comment on this issue.