3 ms·
The claim that "the Linux scheduler is bad" seems wrong. First of all, a program that calls sched_yield() for synchronization is simply broken, since doing so
by devit 7y ago
The claim that "the Linux scheduler is bad" seems wrong.
First of all, a program that calls sched_yield() for synchronization is simply broken, since doing so can cause 100% CPU usage (if the other thread is stopped at an unfortunate place), so the only correct method among the ones benchmarked is std::mutex.
When using std::mutex (the only correct approach), Linux and Windows both seem to have similar average performance, but Windows has 10x latency, so Linux is better.
- newnewpdro 7y agosched_yield() isn't being used for synchronization, it's to yield the calling thread before its timeslice is exhausted because it's potentially preventing the lock-holder thread from getting scheduled to run and releasing it. Spinlocks assume the critical section is fast and non-blocking, so when the spinning lasts longer than expected, throwing in a yield can help by handing some CPU time to something else. The lock-holder might be getting scheduled on the same CPU and waiting for this thread to yield, or there might just be excessive threads runnable right now and burning cycles pointlessly spinning isn't helping get the lock-holder to run and release the lock any sooner. In a situation where you have exactly as many threads as there are CPUs, and they've been assigned their own respective CPUs, and there's nothing else running on the system, I wouldn't expect the yield to help. But that ideal isn't how things generally look in practice.
- gpderetta 7y agoIf a spin lock ends up in a call to sched_yeld, it means that it is already outside its intended use case (uncontrnded or nearly uncontented), so it is a bit pointless to optimize this path or expect any sane scheduling behaviour. If contention is probable it is better to fall back on a futex after a few[1] busy spins. This is what pthread_mutex (and pretty much every decent OS provided mutex does) on glibc by default. [1] how much is 'few' of course is often application dependent.
- devit 7y agoYou must not use sched_yield() and also must not spin indefinitely. Instead, one should optionally spin for up to a constant number of iterations and then call sys_futex.
- newnewpdro 7y agoThat's how you implement a userspace mutex in linux, not a spinlock.
- gpderetta 7y agoSure, but sched_yield is strictly worse than using a futex (except that you'll need to check for waiters on an unlock which makes it slightly more expensive).
- newnewpdro 7y agoOk, so you're arguing that userspace should use mutexes and not spinlocks. Which I agree with, most of the time userspace spinlocks don't fit well. But TFA is clearly comparing the two, and observing a variety of spinlock implementations with sched_yield() demonstrating an interesting positive effect on the spinlocks as tested.
- gpderetta 7y agoActually no, I wouldn't make that claim; while a futex based adaptive mutex is a very good default, spinlocks can be still approriate for some applications. What I'm saying is that if your use case is such that you expect enough contention to consider using TATAS (which is actually a pessimization in the uncontented case) and look into optimizing sched_yield, probably a spinlock is not appropriate on the first place. Edit: hence a spinlock shouldn't bother with yield and just do a tight xchg spin (I haven't measured it inna while, but heard rumors that pause can severely harm acquire latency on very recent CPUs as it will quickly put them in a deeper power saving mode than in the past)
- carlhjerpe 7y agoMy experience is that prior to Windows 8.1 my computer was completely unusable while compiling C++ on all cores, so bad that I got a tool to limit affinity to all but one core. I've "always" been able to do the same on a Linux system, even filling up HT threads without noticing anything. I've always been impressed by the Linux scheduler both for IO and CPU.