DE version is available. Content is displayed in original English for accuracy.
Advertisement
Advertisement
⚡ Community Insights
Discussion Sentiment
100% Positive
Analyzed from 748 words in the discussion.
Trending Topics
#gcc#compiler#simd#matrix#vectorization#rust#vectorize#operations#better#loop

Discussion (6 Comments)Read Original on HackerNews
Anyway, I'm familiar with optimizing numeric loops in C (and Fortran) rather than Rust. I've rarely seen simply using SIMD intrinsics work where GCC auto-vectorization didn't with the same semantics (like numeric equivalence in reductions). In most cases you can get away with -fassociative-math, of course, and not sacrifice peak performance, e.g. BLIS passes its extensive tests with it on, but you should check, of course. (GCC also documents the option as necessary to get Arm (Neon?) to vectorize at all.) Most of the time when people tell you how much better the Itel compiler is, it's because it incorrectly defaults to something like -funsafe-math.
Regardless, GCC (like other compilers) will tell you about vectorization with the -fopt-info- options without examining assembler, and you can have some surprises. For instance, you use unsigned in C for loop indices that you know are positive, and see failed vectorization due to "loop not affine", because of C's overflow semantics; use signed types instead.
There's another reason for using properly-optimized numerical libraries (typically BLAS), is that, at least for level three (matrix-matrix) operations. Even if you get the blocking right for the memory hierarchy, you typically won't get peak performance just with vectorization because tricky preloading is needed for the inner loops.
I had written a expressions template C++ helper library with sort of the same functionality as Python's itertools before I was familiar with itertools.
This was for my own consumption. I expected very little from g++ and it had me impressed. Would be around 2008 - 2010.
Indeed, GCC optimizes well. Last time I ran a set of Fortran benchmarks, the geometric mean for them was competitive with other compilers on multiple architectures, and some of the benchmarks could have been sped up considerably with specific compiler options or by re-writing a function sacrificing numerical equivalence, which the Intel compiler seemed to do itself.
Kudos to GCC engineers. Competition with Clang certainly helped.
It would identify specific loops and would provide reasons why it could not vectorize it, usually some sort of aliasing that it could not rule out. I would then rewrite the code if the rewrite was simple, to make it obvious that such aliasing wouldn't occur. If it wasn't aliasing it was some sort of a cost benefit model that my loop had not crossed.
What I have found is that getting rust to auto-vectorize is a nightmare. The options available to me have always converged around: 1) use simd-like apis 2) frame it as matrix-vector operations.
(1) is touched on in TFA
(2) is way easier, and allows use of well-tested apis and crates, each of which (sensibly) call out to better-tested C libraries. Each of those can, should, might, or will use your CPU better than you will. If you can frame it as matrix-vector operations, you will go very fast, not least of which, by stacking the operations into a _big_ matrix/vector op, which your CPU will happily tear though.
However the article proposes a third, very cool option: use algebraic ops API! Worth a read.
I will check out your insights regarding matrix-vector ops and C libs!
You can do this at the function level.
In rust, try this: https://github.com/pacak/cargo-show-asm
However, life is much easier now, because an agent knows how to steer through this with you. Have it teach you at first, then you know how to ask.
This is one of those "back in my day we had to ... " stories, btw :D