4 ms·
> Rust iterators would also be fun to benchmark here I started to write this out, and then thought "you know what given how common this is, I bet I could even
by steveklabnik 3y ago
> Rust iterators would also be fun to benchmark here
I started to write this out, and then thought "you know what given how common this is, I bet I could even just google it" and thought that would be more interesting, as it makes it feel more "real world." The first result I got is what I would have written: https://stackoverflow.com/a/30422958/24817 https://stackoverflow.com/a/30422958/24817
Here's a godbolt with three different outputs: one at -O, one at -O3, and one at -03 and -march=native
https://godbolt.org/z/6xf9M1cf3 https://godbolt.org/z/6xf9M1cf3
Eyeballing it comments:
Looks like 2 and 3 both provide extremely similar if not identical output.
Adding the native flag ends up generating slightly different codegen, I am not at the level to be able to simply look at that and know how meaningful the difference is.
It does appear to have eliminated the bounds check entirely, and it's using xmm registers.
I am pleasantly surprised at this output because zip in particular can sometimes hinder optimizations, but rustc did a great job here.
----------------------
For fun, I figured "why not also try as direct of the original Go as possible." The only trick here is that Rust doesn't really do the c-style for loop the way Go does, so I tried to translate what I saw as the spirit of the example: compare the two lengths and use the minimum for the loop length.
Here it is: https://godbolt.org/z/cTcddc8Gs https://godbolt.org/z/cTcddc8Gs
... literally the same. I am very surprised at this outcome. It makes me wonder if LLVM has some sort of idiom recognition for dot product specifically.
EDIT: looks like it does not currently, see the comment at line 28 and 29: https://llvm.org/doxygen/LoopIdiomRecognize_8cpp_source.html https://llvm.org/doxygen/LoopIdiomRecognize_8cpp_source.html
- camel-cdr 3y agoThose aren't vectorized at all, just unrolled. vmulss/vaddss just multiply/add the single-precision floating-point in the vector register. With clang you get basically the same codegen, although it uses fused multiply adds. The problem is that you need to enable -ffast-math, otherwise the compiler can't change the order of floating point operations, and thus not vectorize. With clang that works wonderfully and it gives us a lovely four times unrolled AVX2 fused multiply add loop, but enabling it in rust doesn't seem to work: https://godbolt.org/z/G4Enf59Kb https://godbolt.org/z/G4Enf59Kb Edit: from what I can tell this is still an open issue??? https://github.com/rust-lang/rust/issues/21690 https://github.com/rust-lang/rust/issues/21690 Edit: relevant SO post: https://stackoverflow.com/questions/76055058/why-cant-the-rust-compiler-auto-vectorize-this-fp-dot-product-implementation https://stackoverflow.com/questions/76055058/why-cant-the-ru... Apparently you need to use `#![feature(core_intrinsics)]`, `std::intrinsics::fadd_fast` and `std::intrinsics::fmul_fast`.
- sroussey 3y agofast-math changes even libraries not compiled with it, so buyer beware.
- steveklabnik 3y agoAhh yes, thank you. Rust doesn't have a -ffast-math flag, though it is interesting that you passed it directly to llvm. I am kinda glad that escape hatch doesn't work, to be honest. There are currently unstable intrinsics that let you do this, and you seemingly get close to clang codegen with them: https://godbolt.org/z/EEW79Gbxv https://godbolt.org/z/EEW79Gbxv The thread tracking this discusses another attempt at a flag to enable this by turning on the CPU feature directly, but that doesn't seem to affect codegen in this case. https://github.com/rust-lang/rust/issues/21690 https://github.com/rust-lang/rust/issues/21690 It would be nice to get these intrinsics stabilized, at least. EDIT: oops you figured this out while I was writing it, haha.
- cbm-vic-20 3y agoEven without a -ffast-math flag, the current stable Rust compiler will vectorize loops on integer types. https://godbolt.org/z/KjErzacfv https://godbolt.org/z/KjErzacfv Edit: ...and I now realize who I responded to, I'm sure you already know this. :)
- galangalalgol 3y agoLoops on floats are fine, its just reduction operations that hit the issue with the associativity assumption for floats leading to UB. You can trick it by making f32x16 types like the wide crate does or if you use nightly simba can do it with const generic expressions.
- nemothekid 3y agoIt was just last week I was reading a comment that made it seem like you shouldn't really use -ffast-math[0], but here looks like a non-rare reason why you would want to enable it. What is correct idiom here? It feels if this sort of thing really matters to you, you should have the know how to handroll a couple lines of ASM. I want to say this is rare, but I had a project a couple years ago where I needed to handroll some vectorized instructions on a raspberry pi. [0] https://news.ycombinator.com/item?id=39013277 https://news.ycombinator.com/item?id=39013277
- Measter 3y agoI had a go at writing this, both the initial float version and the later integer-based version. Note that I haven't actually tested these to make sure that output is correct, so, I might have messed up somewhere, and that I targeted Rocketlake for the CPU. For the float-based version[0] I had to break out the unstable portable_simd to get it to vectorize. Most of the function ends up being setting up everything, but then actually doing the calculation is simple, and basically the same as non-SIMD section. I've never used the portable SIMD stuff before, and it was quite pleasant to use. For the integer-based version, I started with the simple naive approach[1], and that vectorized to a pretty good degree on stable. However, it doesn't use the dot-product instruction. For that, I think we need to use nightly and go a bit manual[2]. Unsurprisingly, it mostly ends up looking like the float version as a fair chunk is just setup. I didn't bother here, but it should probably be using feature detection to make sure the instruction exists. [0] https://godbolt.org/z/Gdv8azorW https://godbolt.org/z/Gdv8azorW [1] https://godbolt.org/z/d8jv3ofYo https://godbolt.org/z/d8jv3ofYo [2] https://godbolt.org/z/4oYEnKTbf https://godbolt.org/z/4oYEnKTbf