2013-08-19 3 views
4

В дополнение к SSE-copy, AVX-copy and std::copy performance. Предположим, что нам нужно векторизовать некоторый цикл следующим образом: 1) векторизовать первый цикл-пакет (который является кратным 8) через AVX. 2) остаток отрезного цикла в две партии. Векторизация партии, которая кратно 4 через SSE. 3) Обработать остаточную партию всего цикла через последовательную процедуру. Рассмотрим пример копирования массивов:Сопротивление окружающей среды SSE и AVX

#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?

+4

Вы можете смешать все, что вы хотите. Просто убедитесь, что у вас есть правильный флаг компилятора, чтобы заставить все SIMD-инструкции кодировать VEX. – Mysticial

+0

@Mystical, компилятор - gcc 4.7., Flags -O2 -msse -msse2 -msse4.2 -mavx -mfpmath = sse. Это верно? – gorill

+2

Да, это нормально. Хотя '-mavx' - это все, что вам нужно. При указании любой SIMD-опции автоматически включаются все под ним. – Mysticial

ответ

6

Вы можете смешивать встроенные SSE и AVX все, что хотите.

Единственное, что вы хотите убедиться, это указать правильный флаг компилятора для включения AVX.

  • GCC: -mavx
  • Visual Studio: /arch:AVX

Неспособность сделать это будет либо в результате код не компиляции (GCC), или в случае Visual Studio,
этот вид хрень:

Что делает флаг, так это то, что он вынуждает все инструкции SIMD использовать кодировку VEX, чтобы избежать штрафных санкций, описанных в вопросе выше.

+0

Как насчет выравнивания?AVX 256 требует, чтобы данные были выровнены по границе 32 байтов, а SSE - 16 байт. Если вы их смешиваете, вам необходимо выровнять данные до 32 байтов или выровнять до 16 байтов и использовать неуравновешенные нагрузки/хранилища AVX, что хуже, чем в последнем случае, я думаю. – plasmacel

+0

@plasmacel Alignment - совершенно другая тема, которая не имеет отношения к смешению инструкций SSE и AVX. Смешение здесь касается только самих инструкций, а не операндов, которые они могут принять. – Mysticial

0

я смиренно прошу отличаться - я бы посоветовал попробовать не смешивать SSE и AVX, пожалуйста, прочитайте в ссылке Мистический писал, он предостерегает от такой смеси (хотя и не подчеркивая, что достаточно сложно). Вопрос в том, что разные пути кода для разных машин поддерживаются в соответствии с поддержкой AVX, поэтому нет никакой смеси - в вашем случае смесь очень мелкозернистая и будет разрушительной (за счет внедрения микроархитектуры могут возникнуть внутренние задержки).

Чтобы уточнить - мистическое право на префикс vex в компиляции, без него вы оказались бы в довольно плохом состоянии, поскольку вы несете SSE2AVX каждый раз, поскольку верхние части ваших регистров YMM нельзя игнорировать (если явно не указано используя vzeroupper). Тем не менее, есть более тонкие эффекты даже при использовании 128b 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

+2

Вы должны уточнить. Не смешивайте * устаревшие кодировки * SSE и VEX-кодированные AVX. Если вы используете SSE * intrinsics * с флагов компилятора AVX, тогда встроенные функции SSE будут скомпилированы в VES-кодированный SSE. Прекрасно сочетать VES-кодированный SSE с VEX-кодированным AVX. – Mysticial

+0

@Mystical: цитирование руководства по оптимизации Intel - «За исключением инструкций MMX, почти все устаревшие 128-разрядные инструкции SSE имеют эквиваленты AVX, которые поддерживают три синтаксиса операнда». Акцент на почти. Вы правы в том, что не стоит ничего стоить, чтобы смешивать AVX256 с AVX128, поскольку он обнуляет верхнюю часть, но я все равно буду предельно осторожен и проверю, что все мои устаревшие коды SSE действительно правильно преобразованы, и будьте осторожны утверждает, что «вы можете комбинировать SSE и AVX-intrinsics все, что хотите». Имея это, я также не вижу причин смешать код 128b в приведенном выше случае. – Leeor

+1

Можете ли вы привести пример 128-разрядной инструкции SSE, которая не имеет 128-битного эквивалента AVX в формате VEX? Я был бы удивлен, если бы кто-то из них был критичными по производительности инструкциями или был затронут изменениями состояния. – Mysticial

Смежные вопросы