2013-12-18 4 views
1

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

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

for (int x = x_start; x < x_end; ++x)  // vertical blur... 
    { 
     float sum = image[x + (y_start - radius - 1)*image_w]; 
     float dif = -sum; 

     for (int y = y_start - 2*radius - 1; y < y_end; ++y) 
     {             // inner vertical Radius loop   
      float p = (float)image[x + (y + radius)*image_w]; // next pixel 
      buffer[y + radius] = p;       // buffer pixel 
      sum += dif + fRadius*p; 
      dif += p;          // accumulate pixel blur 

      if (y >= y_start) 
      { 
       float s = 0, w = 0;       // border blur correction 
       sum -= buffer[y - radius - 1]*fRadius;  // addition for fraction blur 
       dif += buffer[y - radius] - 2*buffer[y]; // sum up differences: +1, -2, +1 

       // cut off accumulated blur area of pixel beyond the border 
       // assume: added pixel values beyond border = value at border 
       p = (float)(radius - y);     // top part to cut off 
       if (p > 0) 
       { 
        p = p*(p-1)/2 + fRadius*p; 
        s += buffer[0]*p; 
        w += p; 
       } 
       p = (float)(y + radius - image_h + 1);    // bottom part to cut off 
       if (p > 0) 
       { 
        p = p*(p-1)/2 + fRadius*p; 
        s += buffer[image_h - 1]*p; 
        w += p; 
       } 
       new_image[x + y*image_w] = (unsigned char)((sum - s)/(weight - w)); // set blurred pixel 
      } 
      else if (y + radius >= y_start) 
      { 
       dif -= 2*buffer[y]; 
      } 
     } // for y 
    } // for x 
+5

Вы узнали о SSE в школе? Это круто. – Simple

+0

да :), его добровольный вопрос о продвинутых ассемблерах, но крайний срок приближается и я застрял на нем в течение очень долгого времени:/ – Smarty77

+4

К сожалению, я думаю, вам придется полностью переустановить это, если вы хотите использовать SSE , Вы должны предварительно вычислить одномерное ядро ​​коэффициентов, а затем использовать SSE для выполнения свертки на каждой оси. –

ответ

1
  1. Еще одна особенность, которую Вы можете использовать это логические операции и маски:

    , например, вместо:

      // process only 1 
         if (p > 0) 
          p = p*(p-1)/2 + fRadius*p; 
    

    вы можете написать

      // processes 4 floats 
         const __m128 &mask = _mm_cmplt_ps(p,0); 
         const __m128 &notMask = _mm_cmplt_ps(0,p); 
         const __m128 &p_tmp = (p*(p-1)/2 + fRadius*p); 
         p = _mm_add_ps(_mm_and_ps(p_tmp, mask), _mm_and_ps(p, notMask)); // = p_tmp & mask + p & !mask 
    
  2. Также я могу порекомендовать вам использовать специальные библиотеки, которые перегружают инструкции. Например: http://code.compeng.uni-frankfurt.de/projects/vc

  3. dif переменная делает итерации внутренней петли зависимыми. Вы должны попытаться распараллелить внешний цикл. Но без инструкций перегрузка кода становится неуправляемой.

  4. Также рассмотрите переосмысление всего алгоритма. Текущий не выглядит параллель. Может быть, вы можете пренебречь точностью или немного увеличить скалярное время?

+0

Надеюсь, я понимаю, что у вас правильно совпало, я уже пробовал это, и он работает, но проблема заключается в таких выражениях, как sum + = dif + fRadius * p; , где мне нужно использовать diff из предыдущего цикла, который я не могу получить, когда я пытаюсь вычислить 4 цикла сразу – Smarty77

+0

@ user2174310, я вижу. Вы должны попытаться распараллелить внешний цикл. Но при отсутствии команд перегрузки код становится неуправляемым тогда. – klm123

+0

4.7x (приблизительно) быстрее, с наружным циклом распараллеливания, спасибо за советы ребята – Smarty77

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