Live data from Hacker News

The Fastest Mutexes

justine.lol

281–290 of 360 posts

Re: The Fastest Mutexes

#281
post #44

> It's still a new C library and it's a little rough around the edges. But it's getting so good, so fast, that I'm starting to view not using it in production as an abandonment of professional responsibility. What an odd statement. I appreciate the Cosmopolitan project, but these exaggerated claims of superiority are usually a pretty bad red flag.

I'd like to point out that Justine's claims are usually correct. It's just her shtick (or personality?) to use hyperbole and ego-stroking wording. I can see why some might see it as abrasive (it has caused drama before, namely in llamacpp).

The drama in llamacpp was not due to language, it was due to jart making false claims and having absolutely no idea how memory maps work in addition to needlessly changing file headers to contain her name in vanity.

I don’t think anybody can deny that jart is a smart person, but I think there is more to it than just language abbrasiveness which people take issue with.

Re: The Fastest Mutexes

#282
post #168

Earlier quoted context omitted.

> Reason: locks that have the ability to put the thread to sleep on a queue must do compare-and-swap (or at least an atomic RMW) on `unlock`. But spinlocks can get away with just doing a store-release (or just a store with a compiler fence on X86) to `unlock`. This is something I've thinking about a lot over time, that the CAS is only there to atomically determine if there are any sleeping waiters on unlock and you h…

As far as I know it is a fundamental limitation. You need to release the mutex, then check that there were no waiters in this order not to miss wakeups. As the mutex release must be globally visible before the load, release ordering on the mutex is not sufficient as the load could be reordered before the unlock; hence you need a StoreLoad fence which is always the most expensive barrier. Consider the implementation o…

Also this paper might be relevant: Laws of Order: Expensive Synchronization in Concurrent Algorithms Cannot be Eliminated [1]

[1] https://www.cs.bgu.ac.il/~hendlerd/papers/p168-expensiveSync...

Re: The Fastest Mutexes

#283

Earlier quoted context omitted.

> Is there a catch? I am only speaking for myself here. While cosmo and ape do seem very clever, I do not need this type of clever stuff in my work if the ordinary stuff already works fine. Like for example if I can already cross-compile my project to other OSes and platforms or if I've got the infra to build my project for other OSes and platforms, I've no reason to look for a solution that lets me build one binary…

If the executable format changes then it would affect more than just ape/cosmopolitan. All of the old binaries would just stop working.

I am not worried about the scenario where the executable format changes breaks old binaries. That is never going to happen. No OS worth its name is going to do that.

I am worried about the scenario where the executable format changes just enough to break APE binaries. Like I said, APE uses very clever hacks to make itself work on multiple OSes. It is conceivable that executable formats change just enough that it breaks the clever hacks in APE binaries without breaking old ordinary binaries.

Re: The Fastest Mutexes

#284

Earlier quoted context omitted.

APE works through cunning trickery that might get patched out any day now (and in OpenBSD, it has been). Most people producing cross-platform software don't want a single executable that runs on every platform, they want a single codebase that works correctly on each platform they support. With that in mind that respect, languages like go letting you cross compile for all your targets (provided you avoid CGO) is deli…

> Most people producing cross-platform software don't want a single executable that runs on every platform They don't? Having one file to download instead of a maze of "okay so what do you have" is way easier than the current mess. It would be very nice not to have to ask users what platform they're on, they just click a link and get the thing.

Having the browser get the right URL for the download button is by far the most trivial issue when it comes to multi-platform support.

Re: The Fastest Mutexes

#285
post #48

I made a benchmark on this last year when I didn't know how slow pthread mutexes were: https://stackoverflow.com/questions/76965112/why-are-pthread... For my use case, the mutex wait amounted to roughly 40% of the total runtime and spinlocks were way faster. Perhaps nsync or Cosmopolitan would have made my code much faster. I still believe the FUD around spinlocks is overstated. For "normal" hpc code the number of th…

If I'm understanding correctly, you measured pthread_lock as having about twice the overhead of a spin lock. As discussed elsethread, this is expected on x86 as a spinlock only needs an expensive CAS on lock and a cheap store on unlock, while a pthread_lock needs a CAS on both lock and unlock.

Re: The Fastest Mutexes

#286
post #267

Earlier quoted context omitted.

`rep; nop;` is actually the `pause` instruction. On older CPUs it’s a standard nop, but on newer CPUs it’s a more efficient nop. Spinning on the CMPXCHG is also a bad idea. You should spin on the read and only then attempt the CMPXCHG.

Just to clarify: the spinning on CMPXCHG is not also a bad idea, the YieldProcessor is correct (a pause), but inside the CMPXCHG loop it should be spinning on a pure unlocked load. Is that correct?

No you should spin on a read. Once you see the value you want you then try the CMPXCHG. If that succeeds you exit. If it fails you go back to spinning on the read.

Re: The Fastest Mutexes

#287
post #270

Earlier quoted context omitted.

Huh, interesting. TIL. Thanks for that!

Lots of code is 'lock free' and uses the same pattern (more or less). Attempt the change optimistically, if it fails spin it, if it keeps failing (Massive Contention), back off.

A properly lock-free architecture wouldn’t have spin-locks, no?

Re: The Fastest Mutexes

#288

Always cool to see new mutex implementations and shootouts between them, but I don’t like how this one is benchmarked. Looks like a microbenchmark. Most of us who ship fast locks use very large multithreaded programs as our primary way of testing performance. The things that make a mutex fast or slow seem to be different for complex workloads with varied critical section length, varied numbers of threads contending,…

This style of mutex will also power PyMutex in Python 3.13. I have real-world benchmarks showing how much faster PyMutex is than the old PyThread_type_lock that was available before 3.13.

I wonder how much it will help in real code. The no-gil build is still easily 50% slower and the regular build showed a slowdown of 50% for Sphinx, which is why the incremental garbage collector was removed just this week.

Python development is in total chaos on all social and technical fronts due to incompetent and malicious leadership.

Re: The Fastest Mutexes

#289
> It's still a new C library and it's a little rough around the edges. But it's getting so good, so fast, that I'm starting to view not using it in production as an abandonment of professional responsibility.

A bit over the top…

Re: The Fastest Mutexes

#290

" I also managed to make contended nsync mutexes go 30% faster than nsync upstream on AARCH64, by porting it to use C11 atomics." Curious about this -- so what does C11 atomics use to implement? At least in Linux, C++11 atomics use pthreads (not the other way around).

C++ insists on providing a generic std::atomic type wrapper. So despite my type Goose being almost four kilobytes, std::atomic works in C++

Of course your CPU doesn't actually have four kilobyte atomics. So, this feature actually just wraps the type with a mutex. As a result, you're correct in this sense atomics "use pthreads" to get a mutex to wrap the type.

C++ also provides specializations, and indeed it guarantees specializations for the built-in integer types with certain features. On real computers you can buy today, std::atomic is a specialization which will not in fact be a mutex wrapper around an ordinary int, it will use the CPU's atomics to provide an actual atomic integer.

In principle C++ only requires a single type to be an actual bona fide atomic rather than just a mutex wrapper, std::atomic_flag -- all the integers and so on might be locked by a mutex. In practice on real hardware many obvious atomic types are "lock free", just not std::atomic and other ludicrous things.

Post reply on HN