4 ms·
ARM’s memory model is stronger than Alpha’s especially on ARM64. It’s not about just whether it’s possible to write a mutex but also whether you can write a re
by pizlonator 7y ago
ARM’s memory model is stronger than Alpha’s especially on ARM64.
It’s not about just whether it’s possible to write a mutex but also whether you can write a really good one. The best concurrent algorithms - whether mutexes or lock-free data structures - benefit from a careful mix of strength and weakness in the memory model. I think Alpha is too weak. X86 may be too strong - so say smart people - but it still manages to be fast as fuck.
No idea what you’re talking about wrt alignment. On x86, you can load/store misaligned. On Alpha, you can’t. On ARM, you can on some but not on others. The CPUs where you can are easier to program.
No idea what you’re talking about wrt memory barriers. It’s not a solved problem. Memory barriers slow things down so it’s better not to have to use them. X86 and ARM64 give you tricks to avoid using barriers, or to use cheap barriers, in many important racy algorithms. Alpha gives you fewer tricks. (Specifically x86 gives you lots of ordering “for free” while arm64 let’s you use the self-xor dependency trick to cheaply order loads and has a generous buffet of half fences.) The memory model matters a lot - the weaker it is, the fewer tricks programmers have to avoid doing expensive things to request specific orderings.
- dragontamer 7y ago> On x86, you can load/store misaligned. At a performance penalty. Read or write across a 64-byte cacheline, and your CPU will be forced to perform 2x loads to implement your singular unaligned load. An unaligned load across a cacheline is literally 1/2 the speed of an aligned load, and is something the modern programmer (and compiler) is designed to avoid. The compiler basically avoids all misaligned loads/stores, even on x86. (Aside from when the programmer really forces it: like reinterpret_cast<int>(0x800003f) or something) ------- > The best concurrent algorithms - whether mutexes or lock-free data structures - benefit from a careful mix of strength and weakness in the memory model. And all of those algorithms would run CORRECTLY, if those half-barriers were replaced with full barriers. Maybe slower, but they'd be correct. That "generous buffet of half fences" can only exist on a weak memory-model system (like ARM), because x86 AUTOMATICALLY performs those half-fences after every load / before every store instruction. That's the thing about strong memory models: once you're "too strong", it doesn't even make sense to have those half-barrier instructions. ARM and PowerPC were too weak 10-years ago. They've "strengthened" their memory model by adding new half-barriers to their instruction set. That's the real secret: to change your CPU over time to match programmer's preferences. ARM / PowerPC started off too weak, but are now approaching "just right", with the addition of new instructions. DEC Alpha can't do that, because the DEC company died decades ago. Its only fair to consider the programming environment and expectations of the time period that the DEC Alpha existed in.
- pizlonator 7y agoThe perf penalty of misaligned loads and stores is incredibly low. JavaScriptCore uses them quite a bit. The penalty is way lower than handling the misalignment by way of a trap, which is what you’d do on Alpha if you had to run some code that was designed to use misalignment. That’s just a fact - the original comment was about how this fact made Alpha a worse target. I think you’re glossing over a lot of details about the memory model. What the model says about the ordering of dependent loads isn’t a matter of just adding fences later - it’s more fundamental than that. Of Alpha achieved it’s perf advantage thanks to speculating loads then it would have to lose that advantage when it was modernized to current standards. Also, the original comment was about Alpha back then versus Intel—and-others back then, so it’s not interesting to say that Alpha could have just improved - that’s not really responding to the original comment about how hard Alpha was to program.
- BeeOnRope 7y ago> The perf penalty of misaligned loads and stores is incredibly low. Yeah, this. You might as well think of them as free in most scenarios involving small reads and writes. If there is some small advantage to misalignment (often, reduced memory use through better packing), do it! The cross-line penalty would occur only for 3 out of 64 alignments for a 4-byte load: less than 5% of the time, and then the penalty is small. That % is more or less worst case in well designed code [1]. Sometimes you can do misaligned loads that you guarantee will never cross. A common example is a misaligned LUT where the values overlap. E.g., given n, you want to load 8 bytes with: [n, n+1, n+2, ..., n+7] Let's say n ranges from 0 to 15. A traditional aligned LUT would have 16x 8-byte values, one for each n (128 bytes). You could also do it with a single 23 byte LUT, running from 0 to 22, and a misaligned load into that LUT at byte position n. As long as you align the LUT itself (e.g., to 32 bytes), you will never cross a line. For large accesses, things become less clear. After all, a 512-bit AVX-512 access is guaranteed to cross if it is misaligned, and 256-bit access randomly distributed cross half the time, etc. Vectorized code is also the type of code that may be written to approach the 2/1 load/store per cycle limit, so it really pays to try to get alignment for any type of non trivial loop. --- [1] Specifically, this is the crossing % you would get if you could assume nothing about the distribution of the accesses, i.e., they are uniformly randomly distributed. If you know something about the expected alignment, then you can shift everything to make crossing less likely.