songziming wrote: ↑Wed Apr 15, 2026 8:32 am
My question is why not reduce lock contention by affinitising threads to CPUs? Each CPU can have its own dedicated queue, which is lock free. Then a shared task to balance the load.
Also, lock free algorithms exist, which wouldn't be too contended between a scheduler invocation and one dedicatted balancing task.
There's always shared data / code, like a global ready-queue, lowest priority CPU, load balancer, etc.
The point is, with local mostly per CPU run queues, busy CPUs can remain scheduling process on their local run queue without interacting with other CPU and their run queues, and with no locks, and only periodically do you need to run code that does need to touch all the run queues across all the CPUs to re-balance the load. The period could be as short as a 1 second or even less, something that barely registers on a human perception scale (in terms of noticing imbalances in CPU load) but would make a massive difference in locking and cache behaviour on each CPU.
If CPUs are not busy, then casting around for a process to run from a global run queue is no big deal, we're not bust anyway.
So in the average case (not busy) you're no worse off, and in the worst case (all CPUs busy) you're considerably better off, exactly when you ned it.
songziming wrote: ↑Wed Apr 15, 2026 8:32 am
And lock-free algorithms also use atomic instructions, also causes cache-bouncing.
But see above. If run queues are not shared, the atomic ops will not impact other CPUs as much anyway. And in fact, if the run queue is local to a CPU, it can be modified just by disabling interrupts and making the change. Also, a process on CPU0's run queue is unlikely to be in the cache of CPU1, so an atomic instruction will have little to no impact on CPU1 even if it is needed (such as balancing from a global run queue.)
The other benefit of lock free algorithms is that they're inherently fast for the subset of cases they make sense. To update a data structure without lock free algorithms, you have to lock the structure (which will necessarily include atomic ops anyway), make the structure update, then unlock the structure. More instructions, more memory references.