SPSC ring buffer
A fixed array, two ever-growing indices and a mask. The producer core owns head, the consumer core owns tail, and every time one side reads the other's index a cache line crosses the interconnect. Run it, then switch on cached indices and batching and watch the transfers per item fall.
| Line | Holds | Producer | Consumer |
|---|
| Design | Index lines / item | Slot lines / item | vs week 1 |
|---|
Indices never wrap. head and tail count up forever; the slot is index & (CAP − 1), which is what index % CAP compiles to when CAP is a power of two. Empty is head == tail, full is head − tail == CAP, so no slot is wasted. Model: two cores with MESI-style states; head, tail and the slots sit on separate 64-byte lines (16-byte slots, four per line). A read of a line the other core modified, or a write to a line the other core holds, is one cross-core transfer, tens of nanoseconds each (week 4). Arrivals are a seeded Poisson stream at the producer rate; the consumer spends an exponential service time per item at its rate; one tick is 10 ns. Cached indices reload the remote index only when the local copy says full (producer) or empty (consumer). Batching publishes once per batch of whatever is already available, never waiting for a batch to fill. Cached indices pay off when the ring is neither nearly full nor nearly empty; batching pays off when items arrive faster than one at a time.