logoalt Hacker News

exDM69today at 9:03 AM1 replyview on HN

I can and I do use this is "actual code" and I've got benchmarks to prove that it's got better throughput (for the particular use case, don't extrapolate from there) and the same applies to AVX2 and AVX512: twice the native vector width has ~20% better throughput (ie. using `f32x32` on AVX-512).

I pass in the vector width as a generic parameter like this:

    fn do_simd_stuff<const N: usize>(x: Simd<f32, N>) { x.mul_add(x+x, x*x); }
With this I can easily benchmark the same code for any vector width. I can also do some compile time heuristics to choose the vector width based on what's available on the compile target CPU.

> you run out of registers and spill all over the place

As usual when optimizing SIMD code, you should keep an eye on the generated disassembly and the benchmark results and watch for register pressure and the other usual things.

I'm definitely NOT saying that you always get the best perf by using 2x SIMD width, but in this particular case it was so.

This is much much easier to do with portable_simd than if you'd write the same with intrinsics, you can change the SIMD width without having to rewrite all your code (e.g. changing from SSE `_mm_add_ps` to AVX `_mm256_add_ps` etc).

It's still a partial solution, you still need to drop down to intrinsics for some special instructions every now and then (which is easy), but in my projects this accounts for much less than 1% of the lines of code. Not applicable everywhere of course.


Replies

camel-cdrtoday at 9:21 AM

> twice the native vector width has ~20% better throughput

Yes, this is what I was saying, but twice the vector width of AVX-512 will perform horrible in SSE, which is why portable SIMD abstractions should make writing code relative to the native vector width simple.

> I pass in the vector width as a generic parameter like this:

> fn do_simd_stuff<const N: usize>(x: Simd<f32, N>) { ... }

My problem is that no portable_simd example code I've seen does this, which causes people to choose one specific N and run with that.

The second part of the problem is how you find the native vector length, so you can instantiate the generic function. IIRC this isn't even exposed in portable_simd and you have to use a seperate crate to get it.

show 1 reply