News for hackers. Stuff that matters.
Re:Measuring mutexes, spinlocks and how bad the Linux schedu... by amluto on Wednesday January 01, 2020 @01:20AM (#21926917)
I’m not convinced the measurements are really meaningful in this article. The author seems to be running a bunch of threads, measuring the time from when one thread starts unlocking the lock to when another thread gets it and calling this “idle”. I can’t find any mention of how many threads there are, how many CPUs, or what else the system is doing.

So this is measuring a mess of a few things:

For mutexes (assuming all the implementations actually make syscalls for unlocking), this has something to do with how long it takes for the scheduler to activate the waiter and run it, plus how long the scheduler waits because the system is doing something else or it wants to try to avoid bouncing a task between CPUs.

For anything that does not involve the kernel in unlocking, this is really just a measurement of the pauses in execution of long-running threads that continuously hog the CPU. If the thread is also calling sched_yield(), the results are erratic, since sched_yield() more or less means “I don’t want to run now, but I’m not actually waiting for anything visible to the scheduler and, um, run me again soon maybe?” This is almost always the wrong solution. Other than that, this test has essentially nothing to do with which spinlock is in use, unless the spinlock itself wastes time failing to figure out that it’s ready.

From old memory, the Windows scheduler is (was?) mostly based on per-thread priorities, highest priority wins, where the priorities are occasionally automatically adjusted. So, if you set a high-ish priority, you get to hog the CPU. In contrast, Linux tries quite hard not to let normal (non-RT) threads hog the CPU, so a thread that effectively runs continuously measuring pauses will detect significant pauses in which Linux decides that the rest of the system deserves to run too.

Re:Measuring mutexes, spinlocks and how bad the Linux schedu... by RossBencina on Wednesday January 01, 2020 @09:29AM (#21928139)
I agree that the post needs to clarify the number of threads, what thread priorities were assigned, and what measures were taken to associate the threads with logical CPUs (affinities).

I think your characterization of sched_yield() is a bit off. The man page is clear:

"sched_yield() causes the calling thread to relinquish the CPU. The thread is moved to the end of the queue for its static priority and a new thread gets to run."

and

"If the calling thread is the only thread in the highest priority list at that time, it will continue to run after a call to sched_yield()."

In particular, it does not say "I’m not actually waiting for anything visible to the scheduler and, um, run me again soon maybe?".

So assuming that the threads are running at some relatively high priority, I'm struggling to see how delays on the order of 60ms could arise.

EDIT: reading further:

"sched_yield() is intended for use with real-time scheduling policies (i.e., SCHED_FIFO or SCHED_RR). Use of sched_yield() with nondeterministic scheduling policies such as SCHED_OTHER is unspecified and very likely means your application design is broken."

So maybe that's it.

[1] http://man7.org/linux/man-pages/man2/sched_yield.2.html

Re:Measuring mutexes, spinlocks and how bad the Linux schedu... by amluto on Wednesday January 01, 2020 @09:43PM (#21932553)
Indeed. Linux’s SCHED_OTHER doesn’t have static priorities.

There was a half-baked design for locking that kind of worked 20 years ago: try to acquire the spinlock and, if it’s contended, yield. On a single CPU, that probably means that the lock holder gets to run, and if they drop the lock quickly, then the yielding thread will (on an otherwise mostly idle system) get to run soon.

This was a dubious design 20 years ago, although, admittedly, OS lockout primitives were worse back then. But now, with multiple CPUs on a system, the whole scheme falls apart — the lock holder might be on a different CPU and yield() has no effect on how quickly the lock is released.

So, in most cases, yield() really does mean “I don’t know what I’m doing, but I don’t want to run right now.” Anything the kernel does in response is, at best, a wild guess.

Re:Measuring mutexes, spinlocks and how bad the Linux schedu... by zlynx on Wednesday January 01, 2020 @08:29PM (#21932200)
With the current Linux scheduler, yield() means "I don't need to run and won't need to in the future either." and Linux places it at the very END of ALL SCHED_OTHER processes. Even if they are at Nice 20.

So it is no surprise that latencies are high, because a yielded thread has to wait for absolutely every other thread in the system before it gets a chance to run.