Компилятор Intel c ++, ICC, похоже, игнорирует настройки SSE / AVX

Недавно я скачал и установил компилятор Intel C ++ Composer XE 2013 для Linux, который можно бесплатно использовать для некоммерческой разработки.
http://software.intel.com/en-us/non-commercial-software-development

Я бегу по системе Ivy Bridge (которая имеет AVX). У меня есть две версии функции, которые делают то же самое. Один не использует SSE / AVX. Другая версия использует AVX. В GCC код AVX примерно в четыре раза быстрее, чем скалярный код. Однако с компилятором Intel C ++ производительность намного хуже. С GCC я компилирую вот так

gcc m6.cpp -o m6_gcc -O3 -mavx -fopenmp -Wall -pedantic

С Intel я так компилирую

icc m6.cpp -o m6_gcc -O3 -mavx -fopenmp -Wall -pedantic

Я использую только OpenMP для синхронизации (с omp_get_wtime()) с этой точки зрения.
Странно то, что если я изменю опцию avx, чтобы сказать msse2 код не компилируется с GCC, но прекрасно компилируется с ICC. На самом деле я могу бросить mavx все вместе и все еще компилируется. Кажется, неважно, какие опции я пробую, он компилирует, но не использует оптимально код AVX. Поэтому мне интересно, делаю ли я что-то не так при включении / отключении SSE / AVX с помощью ICC?

Вот функция с AVX, которую я использую.

inline void prod_block4_unroll2_AVX(double *x, double *M, double *y, double *result) {
__m256d sum4_1 = _mm256_set1_pd(0.0f);
__m256d sum4_2 = _mm256_set1_pd(0.0f);

__m256d yrow[6];
for(int i=0; i<6; i++) {
yrow[i] = _mm256_load_pd(&y[4*i]);
}
for(int i=0; i<6; i++) {
__m256d x4 = _mm256_load_pd(&x[4*i]);
for(int j=0; j<6; j+=2) {
__m256d brod1 = _mm256_set1_pd(M[i*6 + j]);
sum4_1 = _mm256_add_pd(sum4_1, _mm256_mul_pd(_mm256_mul_pd(x4, brod1), yrow[j]));
__m256d brod2 = _mm256_set1_pd(M[i*6 + j+1]);
sum4_2 = _mm256_add_pd(sum4_2, _mm256_mul_pd(_mm256_mul_pd(x4, brod2), yrow[j+1]));
}
}
sum4_1 = _mm256_add_pd(sum4_1, sum4_2);
_mm256_store_pd(result, sum4_1);
}

Здесь информация о времени в секундах. Я использую три диапазона, соответствующие диапазонам кэша L1, L2 и L3. Я получаю только 4x в регионе L1. Обратите внимание, что ICC имеет гораздо более быстрый скалярный код, но более медленный код AVX.

GCC:
nvec 2000, repeat 100000
time scalar 5.847293
time SIMD 1.463820
time scalar/SIMD 3.994543

nvec 32000, repeat 10000
time scalar 9.529597
time SIMD 2.616296
time scalar/SIMD 3.642400
difference 0.000000

nvec 5000000, repeat 100
time scalar 15.105612
time SIMD 4.530891
time scalar/SIMD 3.333917
difference -0.000000

ICC:
nvec 2000, repeat 100000
time scalar 3.715568
time SIMD 2.025883
time scalar/SIMD 1.834049

nvec 32000, repeat 10000
time scalar 6.128615
time SIMD 3.509130
time scalar/SIMD 1.746477

nvec 5000000, repeat 100
time scalar 9.844096
time SIMD 5.782332
time scalar/SIMD 1.702444

4

Решение

Два момента:

(1) Похоже, что вы используете встроенную информацию Intel в своем коде — g ++ и icpc не обязательно реализуют одну и ту же встроенную функцию (но большинство из них перекрываются). Проверьте файлы заголовков, которые необходимо импортировать (g ++ может потребоваться подсказка для определения inartistic для вас). G ++ выдает сообщение об ошибке, когда оно терпит неудачу?

(2) Флаги компилятора не означают, что инструкции будут сгенерированы (из icpc —help):
-msse3 May generate Intel(R) SSE3, SSE2, and SSE instructions

Эти флаги обычно просто подсказки компилятору. Вы можете посмотреть на -xHost и -fast.

Кажется, неважно, какие опции я пробую, он компилирует, но не использует оптимально код AVX.

Как вы это проверили? Вы можете не увидеть 4-кратное ускорение, если есть другие узкие места (например, пропускная способность памяти).

РЕДАКТИРОВАТЬ (на основе редактирования вопроса):

Похоже, что скаляр icc быстрее, чем скаляр gcc — возможно, что icc векторизует скалярный код. В этом случае я бы не ожидал 4-кратного ускорения от ICC при ручном кодировании векторизации.

Что касается разницы между icc в 5.782332s и gcc в 3.509130s (для nvec 5000000); это неожиданно Я не могу сказать, основываясь на имеющейся у меня информации, почему существует разница во времени выполнения между двумя компиляторами. Я бы порекомендовал посмотреть на излучаемый код (http://www.delorie.com/djgpp/v2faq/faq8_20.html) из обоих компиляторов. Кроме того, убедитесь, что ваши измерения воспроизводимы (например, расположение памяти на машинах с несколькими сокетами, горячий / холодный кэш, фоновые процессы и т. Д.).

1

Другие решения

Других решений пока нет …