Действительно базовый SSE

#c #performance #optimization #sse #sse3

#c #Производительность #оптимизация #sse #sse3

Вопрос:

У меня есть очень простая программа, которую я пытаюсь улучшить в производительности. Один из способов, который, как я знаю, поможет, — это использовать SSE3 (поскольку машина, на которой я работаю, поддерживает это), но я абсолютно не представляю, как это сделать. Вот фрагмент кода (c ):

 int sum1, sum2, sum3, sum4;
for (int i=0; i<length; i =4) {
  for (int j=0; j<length; j =4) {
    sum1 = sum1   input->value[i][j];
    sum2 = sum2   input->value[i 1][j 1];
    sum3 = sum3   input->value[i 2][j 3];
    sum4 = sum4   input->value[i 3][j 4];    
  {
}
 

Я немного читал об этом и понимаю идею, но я абсолютно не представляю, как это реализовать. Может кто-нибудь мне помочь, пожалуйста? Я думаю, что это довольно просто, особенно для моей простой программы, но иногда начало работы — самая сложная часть.

Спасибо!

Ответ №1:

На самом деле, в вашем случае это не так просто. В нынешнем виде ваш код НЕ поддается векторизации. (по крайней мере, не без значительных преобразований цикла)

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

Однако у меня такое ощущение, что вы пытаетесь суммировать все элементы в своей матрице, и вы на самом деле предполагали, что ваш цикл будет таким (и у вас тоже было несколько опечаток):

 int sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0;
for (int i=0; i<length; i  ) {
  for (int j=0; j<length; j =4) {
    sum1 = sum1   input->value[i][j];
    sum2 = sum2   input->value[i][j 1];
    sum3 = sum3   input->value[i][j 2];
    sum4 = sum4   input->value[i][j 3];    
  }
}

int total = sum1   sum2   sum3   sum4;
 

Если это то, что вы хотели, то это очень векторизуемо.
В C / C с использованием встроенных функций это можно сделать следующим образом, используя только SSE2:

 __m128i sum = _mm_setzero_si128();
for (int i=0; i<length; i  ) {
  for (int j=0; j<length; j =4) {
    __m128i val = _mm_load_si128(amp;input->value[i][j]);
    sum = _mm_add_epi32(sum,val);
  }
}
 

Обратите внимание, что будут применяться ограничения на выравнивание. И намного большего ускорения можно добиться, продолжая разворачивать цикл.