Отключить функции AVX2 на процессорах, отличных от Haswell
Я написал код AVX2 для запуска на процессоре Haswell i7. Та же самая кодовая база также используется на процессорах не-Haswell, где тот же код должен быть заменен их эквивалентами SSE. Мне было интересно, есть ли способ для компилятора игнорировать инструкции AVX2 на не-Haswell процессорах. Мне нужно что-то вроде:
public void useSSEorAVX(...){
IF (compiler directive detected AVX2)
AVX2 code (this part is ready)
ELSE
SSE code (this part is also ready)
}
}
Прямо сейчас я комментирую связанный код перед компиляцией, но должен быть более эффективный способ сделать это. Я использую Ubuntu и GCC. Спасибо за вашу помощь.
2 ответа
Если вы просто хотите сделать это во время компиляции, вы можете сделать это:
#ifdef __AVX2__
// AVX2 code
#elif __SSE__
// SSE code
#else
// scalar code
#endif
Обратите внимание, что когда вы компилируете с gcc -mavx2 ...
затем __AVX2__
определяется автоматически. Аналогично для __SSE__
, (Обратите также внимание, что вы можете проверить, что предопределено вашим компилятором для любого данного переключения командной строки, используя заклинание gcc -dM -E -mavx2 - < /dev/null
.)
Если вы хотите выполнить диспетчеризацию во время выполнения, тогда это немного сложнее.
Я не думаю, что это хорошая идея сделать отдельный исполняемый файл, если вам не нужно. В вашем случае вы можете сделать диспетчер процессора. Я сделал это недавно для GCC и Visual studio.
Давайте предположим, что у вас есть функция с именем product
для SSE и AVX. Вы помещаете версию SSE в файл product_SSE.cpp, а версию AVX2 - в файл product_AVX2.cpp. Вы компилируете каждый отдельно (например, с -msse2
а также -mavx2
). Затем сделайте такой модуль:
extern "C" void product_SSE(float *a, float *b, float *c, int n);
extern "C" void product_AVX2(float *a, float *b, float *c, int n);
void product_dispatch(float *a, float *b, float *c, int n);
void (*fp)(float* a, float *b, float *c, int n) = product_dispatch;
inline void product_dispatch(float *a, float *b, float *c, int n) {
int iset = instrset_detect();
if(iset==8) {
fp = product_AVX2
}
else {
fp = product_SSE
}
fp(a,b,c,n);
}
inline void product(float *a, float *b, float*c, int bs) {
fp(a,b,c,n);
}
Вы компилируете этот модуль с нижним общим набором команд (например, с SSE2). Теперь, когда вы звоните продукт, он сначала звонит product_dispatch
устанавливает указатель на функцию fp
либо product_AVX2
или же product_SSE
а затем вызывает функцию из указателя функции. Второй раз звонишь product
он прыгает прямо на product_AVX2
или же product_SSE
, Таким образом, вам не нужно иметь отдельный исполняемый файл.