В дополнение к SSE-copy, AVX-copy и std :: copy производительность. Предположим, что нам нужно векторизовать некоторый цикл следующим образом: 1) векторизовать первый цикл цикла (который кратен 8) через AVX. 2) разделить остаток цикла на две партии. Векторизовать партию, кратную 4, через SSE. 3) Обработка остаточной партии всего цикла с помощью последовательной процедуры. Рассмотрим пример копирования массивов:
#include <immintrin.h>
template<int length,
int unroll_bound_avx = length & (~7),
int unroll_tail_avx = length - unroll_bound_avx,
int unroll_bound_sse = unroll_tail_avx & (~3),
int unroll_tail_last = unroll_tail_avx - unroll_bound_sse>
void simd_copy(float *src, float *dest)
{
auto src_ = src;
auto dest_ = dest;
//Vectorize first part of loop via AVX
for(; src_!=src+unroll_bound_avx; src_+=8, dest_+=8)
{
__m256 buffer = _mm256_load_ps(src_);
_mm256_store_ps(dest_, buffer);
}
//Vectorize remainder part of loop via SSE
for(; src_!=src+unroll_bound_sse+unroll_bound_avx; src_+=4, dest_+=4)
{
__m128 buffer = _mm_load_ps(src_);
_mm_store_ps(dest_, buffer);
}
//Process residual elements
for(; src_!=src+length; ++src_, ++dest_)
*dest_ = *src_;
}
int main()
{
const int sz = 15;
float *src = (float *)_mm_malloc(sz*sizeof(float), 16);
float *dest = (float *)_mm_malloc(sz*sizeof(float), 16);
float a=0;
std::generate(src, src+sz, [&](){return ++a;});
simd_copy<sz>(src, dest);
_mm_free(src);
_mm_free(dest);
}
Правильно ли использовать SSE и AVX? Нужно ли избегать переходов AVX-SSE?
Вы можете смешивать встроенные функции SSE и AVX сколько хотите.
Единственное, что вы хотите убедиться, это указать правильный флаг компилятора для включения AVX.
-mavx
/arch:AVX
Невыполнение этого условия приведет либо к тому, что код не скомпилируется (GCC), либо в случае Visual Studio,
этот вид дерьма:
Этот флаг заставляет все команды SIMD использовать кодирование VEX, чтобы избежать штрафов за переключение состояний, описанных в приведенном выше вопросе.
Я смиренно прошу отличаться — я бы посоветовал попробовать не смешать SSE и AVX,
пожалуйста, прочитайте ссылку Mystical, она предупреждает против такой смеси (хотя не подчеркивая это достаточно сильно). Возникает вопрос о разных путях кода для разных машин в соответствии с поддержкой AVX, так что нет никакой смеси — в вашем случае микшер очень мелкозернистый и будет разрушительным (вызывать внутренние задержки из-за реализации микроархитектуры).
Чтобы уточнить — Mystical прав насчет префикса vex при компиляции, без него вы бы были в очень плохой форме, поскольку вы получаете поддержку SSE2AVX каждый раз, поскольку верхние части ваших регистров YMM не могут быть проигнорированы (если явно не используется vzeroupper). Тем не менее, есть более тонкие эффекты даже при использовании 128-битного AVX, смешанного с 256-битным AVX.
Я также не вижу преимущества использования SSE, поскольку у вас есть длинный цикл (скажем, N> 100), вы можете получить преимущество от AVX для большей части его, а остаток сделать в скалярном коде до 7 итераций. (ваш код, возможно, все еще должен делать 3 из них). Потеря производительности ничто по сравнению с микшированием AVX / SSE
Еще немного информации о смеси —
http://software.intel.com/sites/default/files/m/d/4/1/d/8/11MC12_Avoiding_2BAVX-SSE_2BTransition_2BPenalties_2Brh_2Bfinal.pdf