SSE оптимизация SIMD для цикла

У меня есть некоторый код в цикле

for(int i = 0; i < n; i++)
{
  u[i] = c * u[i] + s * b[i];
}

Так, u и b являются векторами той же длины, и c и s являются скалярами. Действительно ли этот код является хорошим кандидатом на векторизацию для использования с SSE для получения ускорения?

ОБНОВЛЕНИЕ

Я учился, векторизация (оказывается, что не настолько трудно, если Вы используете intrinsics), и реализовал мой цикл в SSE. Однако при установке флага SSE2 в VC ++ компилятор, я добираюсь о том же представлении в качестве с моим собственным кодом SSE. Компилятор Intel, с другой стороны, был намного быстрее, чем мой код SSE или VC ++ компилятор.

Вот код, который я написал для ссылки

double *u = (double*) _aligned_malloc(n * sizeof(double), 16);
for(int i = 0; i < n; i++)
{
   u[i] = 0;
}

int j = 0;
__m128d *uSSE = (__m128d*) u;
__m128d cStore = _mm_set1_pd(c);
__m128d sStore = _mm_set1_pd(s);
for (j = 0; j <= i - 2; j+=2)
{
  __m128d uStore = _mm_set_pd(u[j+1], u[j]);

  __m128d cu = _mm_mul_pd(cStore, uStore);
  __m128d so = _mm_mul_pd(sStore, omegaStore);

  uSSE[j/2] = _mm_add_pd(cu, so);
}
for(; j <= i; ++j)
{
  u[j] = c * u[j] + s * omegaCache[j];
}
6
задан Projectile Fish 27 May 2010 в 12:36
поделиться

4 ответа

Да, это отличный кандидат на векторизацию. Но прежде чем это сделать, убедитесь, что вы профилировали свой код, чтобы убедиться, что это действительно стоит оптимизировать. Итак, векторизация будет выглядеть примерно так:

int i;
for(i = 0; i < n - 3; i += 4)
{
  load elements u[i,i+1,i+2,i+3]
  load elements b[i,i+1,i+2,i+3]
  vector multiply u * c
  vector multiply s * b
  add partial results
  store back to u[i,i+1,i+2,i+3]
}

// Finish up the uneven edge cases (or skip if you know n is a multiple of 4)
for( ; i < n; i++)
  u[i] = c * u[i] + s * b[i];

Для еще большей производительности вы можете рассмотреть возможность предварительной выборки последующих элементов массива, и/или развернуть цикл и использовать программную конвейеризацию для чередования вычислений в одном цикле с обращениями к памяти из другой итерации.

5
ответ дан 17 December 2019 в 00:04
поделиться

это зависит от того, как вы поместили u и b в память. если оба блока памяти находятся далеко друг от друга, SSE не будет сильно увеличиваться в этом сценарии.

предлагается, чтобы массивы u и b были AOE (массив структур) вместо SOA (структура массива), потому что вы можете загрузить их оба в регистр в одной инструкции.

-2
ответ дан 17 December 2019 в 00:04
поделиться

Возможно, да, но вы должны помочь компилятору некоторыми подсказками. __ restrict __ , помещенное в указатели, сообщает компилятору, что между двумя указателями нет псевдонима. если вы знаете выравнивание ваших векторов, сообщите об этом компилятору (Visual C ++ может иметь некоторую возможность).

Я сам не знаком с Visual C ++, но слышал, что он не годится для векторизации. Вместо этого рассмотрите возможность использования компилятора Intel. Intel позволяет довольно детально управлять созданной сборкой: http://www.intel.com/software/products/compilers/docs/clin/main_cls/cref_cls/common/cppref_pragma_vector.htm

1
ответ дан 17 December 2019 в 00:04
поделиться

_mm_set_pd не векторизован. Если воспринимать ее буквально, она считывает два дубля, используя скалярные операции, затем объединяет два скалярных дубля и копирует их в регистр SSE. Вместо этого используйте _mm_load_pd.

2
ответ дан 17 December 2019 в 00:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: