A market data handler receives 400,000 packets per second. Interrupt coalescing fires at 16 packets or 50 microseconds, whichever comes first. How long does the first packet of a batch wait, and what changes when the rate drops to 4,000 packets per second?

A market data handler receives 400,000 packets per second. Interrupt coalescing fires at 16 packets or 50 microseconds, whichever comes first. How long does the first packet of a batch wait, and what changes when the rate drops to 4,000 packets per second?

Approach: Compute the interpacket gap at each rate, work out which of the two coalescing thresholds binds, and take the delay of the earliest packet in the batch.

37.5 microseconds at the high rate and the full 50 microseconds at the low rate, and the low rate is the worse case because the batch holds one packet. The head packet's wait is min(15 * gap, 50 us), since the batch ends when the sixteenth packet arrives or the timer expires. At 400,000 pps the interpacket gap is 2.5 microseconds, so 15 gaps is 37.5 microseconds and the count threshold binds; the delay is amortised over 16 packets, which is the tradeoff coalescing exists to make. At 4,000 pps the gap is 250 microseconds, 15 gaps is 3.75 milliseconds, so the timer binds and a lone packet is held for 50 microseconds with no batching benefit at all. The added latency is therefore worst exactly when the market is quiet, which is when a single message is most likely to be the one that matters. Note also that the delay is not constant across the batch: the sixteenth packet waits nothing while the first waits 37.5 microseconds, so coalescing adds jitter as well as latency. Trading systems disable it and busy poll instead, which bounds the added delay by the poll loop period, tens of nanoseconds, at the cost of a dedicated core.

Follow-up: Busy polling one core per feed does not scale to forty feeds. What is the design that keeps polling latency while sharing cores?

Key concepts: interrupt coalescing, busy polling, interpacket gap, tail latency.