A thread waits for work handed over by another thread on the same box. Say when you spin and when you block, with the wait durations that separate the two, and state what a busy polling thread pinned to an isolated core costs the machine.
A thread waits for work handed over by another thread on the same box. Say when you spin and when you block, with the wait durations that separate the two, and state what a busy polling thread pinned to an isolated core costs the machine.
Approach: Compare the cost of a sleep and a wakeup against the cost of holding a core doing nothing, then ask who else on the box needs that core.
Spin when the expected wait is below roughly 1 to 10 microseconds and a core is available to burn, and block otherwise, because a futex sleep plus the wakeup and the context switch costs 1 to 5 microseconds plus the cache the thread lost while descheduled, so spinning is strictly faster below that and wastes a core above it. A busy polling thread pinned with thread affinity to an isolated core costs one full core of power and heat, removes that core from everything else, and interferes with its sibling hyperthread, which is why the sibling is normally left idle or disabled. Isolate the core with isolcpus or cpusets, move interrupts and the kernel timer off it, and only then raise the thread priority, since a spinning real time thread on a shared core can starve the kernel. Spin then block, spinning a bounded number of iterations with a pause instruction before sleeping, is the right default when the wait distribution has a long tail.
Follow-up: What does the pause instruction actually do on the spin path, and what does it change on a core whose sibling hyperthread is also running?
Key concepts: spinning, context switch, thread affinity, busy polling.