4 ms·
This has to be done at a granularity coarse enough that the function call overhead doesn't kill the performance. It has to be entire loops, for example, not jus
by exDM69 9y ago
This has to be done at a granularity coarse enough that the function call overhead doesn't kill the performance. It has to be entire loops, for example, not just some primitive operation like a dot product (which has at least 3 different implementations on x86).
On my C code, I have a build script that rebuilds a shared library 3-4 times for different CPUs (e.g. with and without -mavx2) and then uses dlopen() to choose the right one at runtime. The actual SIMD code has a bunch of #ifdefs to choose the appropriate implementation for primitive operations.
GCC has function multiversioning [0][1] (__attribute__((target("sse4.2")))) to enable choosing a function implementation based on CPU capabilities at runtime, but that is not suitable for the use case I describe. I want my "high level" code to be the same, but using the right implementation for "primitive" ops like dot product. Using multiversioning would completely kill the optimizer and cause excessive register spilling and other unwanted artifacts.
[0] https://gcc.gnu.org/wiki/FunctionMultiVersioning https://gcc.gnu.org/wiki/FunctionMultiVersioning
[1] https://gcc.gnu.org/onlinedocs/gcc-6.2.0/gcc/Function-Multiversioning.html https://gcc.gnu.org/onlinedocs/gcc-6.2.0/gcc/Function-Multiv...
- ibotty 9y ago> This has to be done at a granularity coarse enough that the function call overhead doesn't kill the performance. It has to be entire loops, for example, not just some primitive operation like a dot product. Yes, You are right! I understood, that they wanted to add the branch to _every_ SIMD instruction. I concur with branching outside of loops. Re Rust: I expect that one could use a macro around the function (or annotate it, if the macro system is good enough) that generates these different functions and branches to the right one.