4 ms·
> x86 cannot have acquire/release semantics As I said at the time, this is nonsense. All stores on x86 are have release semantics and all loads have acquire se
by gpderetta 2y ago
> x86 cannot have acquire/release semantics
As I said at the time, this is nonsense. All stores on x86 are have release semantics and all loads have acquire semantics.
Atomic RMW are sequentially consistent.
Technically you could implement relaxed stores via non temporal stores but it would be pointless.
- kmeisthax 2y agoFor those watching along at home, we're talking about these two comments from dragontamer: - https://news.ycombinator.com/item?id=27753913 https://news.ycombinator.com/item?id=27753913 - https://news.ycombinator.com/item?id=27762749 https://news.ycombinator.com/item?id=27762749 I interpreted dragontamer's comment to mean "x86 does not have relaxed stores", not "x86 does not have a strong memory model". The (presumed) problem is that you can't actually test acquire/release code on x86, because it won't crash if you get it wrong. There's a second level of this in C++'s memory model: consume/release. I've no idea what the difference between acquire and consume are; when I look it up there's usually some reference to the DEC Alpha, a 30 year old workstation and server chip nobody uses today which was legendary for pushing the boundaries of memory ordering. My assumption is that no hardware provides memory ordering exactly as weak as consume, so I shouldn't bother asking for it, since it'll just get strengthened to acquire on any chip that matters. Also, from you and one other person, it sounds like relaxed memory models aren't actually a performance benefit? Would the opposite - ARM mandating TSO in ARMv9.1-A or whatever - make sense? A lot of ink and code is wasted talking about memory model strengths.
- jcranmer 2y ago> There's a second level of this in C++'s memory model: consume/release. I've no idea what the difference between acquire and consume are; when I look it up there's usually some reference to the DEC Alpha, a 30 year old workstation and server chip nobody uses today which was legendary for pushing the boundaries of memory ordering. My assumption is that no hardware provides memory ordering exactly as weak as consume, so I shouldn't bother asking for it, since it'll just get strengthened to acquire on any chip that matters. You have it wrong here. So the basic idea behind release/consume comes from an observation that, on all hardware not named Alpha [1], there is no hardware fence needed to guarantee that a load happens-before another load that is data-dependent on the first load. So the C++ committee decided to add a memory model that would preserve this guarantee. A consume load is exactly like an acquire load, but only for other loads that are data-dependent on that load as opposed to all loads in general. So whereas an acquire load requires a fence on pretty much every hardware not x86 or SPARC in TSO mode, a consume load would only require a fence on Alpha. For various reasons, data-dependency isn't a property that compilers are in the position of guaranteeing, which means every compiler ended up implementing consume as the stronger acquire instead, defeating its entire design goal of eliminating unnecessary fences. There have been a couple of attempts within the committee to try to find a path that would let something like consume by tweaking the necessary data dependence definitions, but none of them have swayed the implementers, so the current state is that they've given up and let consume die. Of particular note is that release/consume is not designed to support the Alpha memory model; in fact, it's quite the opposite: it's designed to support everybody but Alpha, since for Alpha (and essentially only Alpha), release/consume is not usefully weaker than release/acquire. Instead, the people who benefit are the PPCs and the ARMs of the world, for whom release/consume is a better approximation of their native memory model and would allow many fences to be omitted. [1] Actually, some accelerator hardware might have memory models as weak as Alpha here, but I'm far less familiar with memory models as they apply to accelerators.
- gpderetta 2y agoThank you! I have argued this point so many times on HN :).
- kmeisthax 2y agoSo, just to confirm my own (new) understanding now: Consume is "I want to read data from a pointer, please do not reorder loads that go through the pointer" and Acquire is "I want to read data from a pointer, please do not reorder loads that happen after this one, *whether or not they go through the same pointer" there's no relation to the Alpha aside from it being the only processor that needs a barrier for Consume and for whatever reason compilers don't or can't do the dependency tracking that would let them take advantage of the weaker guarantees of Consume, so in practice it just becomes Acquire?
- gpderetta 2y agoConsume is for data dependency, loading through a pointer is the obvious one, but there are other variants (using the loaded value as an index for example). Acquire is also not about pointers but about independent reads: reading a flag and then reading data protected by that flag for example. Consume exists because it can be implemented cheaply on some platforms with relatively expensive acquire barriers (ARM, POWER). Alpha didn't respect load dependencies, so consume is as expensive as acquire.
- adrian_b 2y agoIt is correct that on x86 all normal stores have release semantics and all normal loads have acquire semantics (only a few instructions behave differently, i.e. the string instructions and the streaming "non-temporal" store instructions). However the ordering properties of the x86 stores and loads are stronger than that. An x86 store is not only a release store, but it has an additional property that could be called of being an "initial store", i.e. a store that is guaranteed to be performed before all subsequent stores. An x86 load is not only an acquire load, but it has an additional property that could be called of being a "final load", i.e. a load that is guaranteed to be performed after all prior loads. The research paper that has introduced the concepts of acquire loads and release stores (in May 1990) was mistaken. They have claimed that these 2 kinds of accesses are enough for the synchronization of accesses to shared resources. While it is true that acquire loads and release stores are sufficient for implementing critical sections, there are other algorithms for accessing shared resources that need the other 2 kinds of ordered loads and stores, i.e. final loads and initial stores. On x86, this does not matter, because the normal loads and stores provide all 4 kinds of ordered loads and stores, so any algorithm can be implemented without using memory barriers or other special instructions. In ISAs that provide only 2 kinds of ordered loads and stores, i.e. acquire loads and release stores, like Arm Aarch64, the other 2 kinds of ordered loads and stores must be synthesized using memory barriers, i.e. an initial store is made by a weakly-ordered store followed by a store barrier, while a final load is made by a weakly-ordered load preceded by a load barrier. Arm Aarch64 does not have load barriers, but it has stronger acquire barriers, which can always be used instead of any load barriers. The Arm Aarch64 acquire barrier has the confusing mnemonic DMB.LD, apparently inspired by the x86 LFENCE, which is also an acquire barrier, not a load barrier, despite its confusing mnemonic. (a load barrier guarantees that all prior loads are performed before all subsequent loads; an acquire barrier guarantees that all prior loads are performed before all subsequent loads and stores; such memory barriers are stronger than necessary; the weaker ordering properties provided by the 4 kinds of ordered loads and stores are sufficient)
- gpderetta 2y agoInteresting. I don't consider myself an expert, but I have written my share of lock free algorithms. For which algorithms you specifically needed an "initial store" or "final read" for? I could see these being useful for seq locks, but usually you represent them with relaxed operations and explicit memory barriers.