2016-11-11 71 views
0

嗨我想改善這段代碼的性能,因爲我有一臺能夠處理4個線程的機器。我首先想到了使omp並行,但後來我看到這個函數在for循環中,所以多次創建線程效率不高。所以,我想知道如何使用SSE實現它,這將是更有效的:SSE並行化

unsigned char cubicInterpolate_paralelo(unsigned char p[4], unsigned char x) { 
    unsigned char resultado; 
    unsigned char intermedio; 
    intermedio = + x*(3.0*(p[1] - p[2]) + p[3] - p[0]); 

    resultado = p[1] + 0.5 * x *(p[2] - p[0] + x*(2.0*p[0] - 5.0*p[1] + 4.0*p[2] - p[3] + x*(3.0*(p[1] - p[2]) + p[3] - p[0]))); 
    return resultado; 
} 

unsigned char bicubicInterpolate_paralelo (unsigned char p[4][4], unsigned char x, unsigned char y) { 
    unsigned char arr[4],valorPixelCanal; 
    arr[0] = cubicInterpolate_paralelo(p[0], y); 
    arr[1] = cubicInterpolate_paralelo(p[1], y); 
    arr[2] = cubicInterpolate_paralelo(p[2], y); 
    arr[3] = cubicInterpolate_paralelo(p[3], y); 

    valorPixelCanal = cubicInterpolate_paralelo(arr, x); 
    return valorPixelCanal; 
} 

這裏面的一些嵌套的使用:

for(i=0; i<z_img.width(); i++) { 
     for(j=0; j<z_img.height(); j++) { 
      //For R,G,B 
      for(c=0; c<3; c++) { 

       for(l=0; l<4; l++){ 
        for(k=0; k<4; k++){ 

         arr[l][k] = img(i/zFactor +l, j/zFactor +k, 0, c); 
        } 
       } 

       color[c] = bicubicInterpolate_paralelo(arr, (unsigned char)(i%zFactor)/zFactor, (unsigned char)(j%zFactor)/zFactor); 
      } 
      z_img.draw_point(i,j,color); 
     } 
    } 
+1

只是挑剔,但使用SSE或另一組矢量操作稱爲矢量化而不是並行化。 –

回答

3

我已經採取了一些自由的代碼,所以你可能要顯著改變它,但這裏是一個(未經測試)音譯SSE:

__m128i x = _mm_unpacklo_epi8(_mm_loadl_epi64(x_array), _mm_setzero_si128()); 
__m128i p0 = _mm_unpacklo_epi8(_mm_loadl_epi64(p0_array), _mm_setzero_si128()); 
__m128i p1 = _mm_unpacklo_epi8(_mm_loadl_epi64(p1_array), _mm_setzero_si128()); 
__m128i p2 = _mm_unpacklo_epi8(_mm_loadl_epi64(p2_array), _mm_setzero_si128()); 
__m128i p3 = _mm_unpacklo_epi8(_mm_loadl_epi64(p3_array), _mm_setzero_si128()); 
__m128i t = _mm_sub_epi16(p1, p2); 
t = _mm_add_epi16(_mm_add_epi16(t, t), t); // 3 * (p[1] - p[2]) 
__m128i intermedio = _mm_mullo_epi16(x, _mm_sub_epi16(_mm_add_epi16(t, p3), p0)); 
t = _mm_add_epi16(p1, _mm_slli_epi16(p1, 2)); // 5 * p[1] 
// t2 = 2 * p[0] + 4 * p[2] 
__m128i t2 = _mm_add_epi16(_mm_add_epi16(p0, p0), _mm_slli_epi16(p2, 2)); 
t = _mm_mullo_epi16(x, _mm_sub_epi16(_mm_add_epi16(t2, intermedio), _mm_add_epi16(t, p3))); 
t = _mm_mullo_epi16(x, _mm_add_epi16(_mm_sub_epi16(p2, p0), t)); 
__m128i resultado = _mm_add_epi16(p1, _mm_srli_epi16(t, 1)); 
return resultado; 

,我使用應寬16位中間體足夠的,在這段代碼中,高位信息影響低位的唯一方法是右移1(代碼中的0.5 *),所以實際上我們只需要9位,其餘不會影響結果。字節不夠寬(除非你有一些我不知道的額外保證),但是無論如何它們會很煩人,因爲沒有很好的方法來增加它們。

爲了簡單起見,我假裝輸入的形式是連續數組x's,p[0]'s等,這不是你在這裏需要的,但我沒有時間去處理所有的加載和混洗。

0

使用OpenMP的,你可以嘗試添加#pragma到最外面的循環。這應該可以解決你的問題。

由於對數據有額外的對齊限制,執行SSE路由比較棘手,但最簡單的轉換是擴展cubicInterpolate_paralelo以同時處理多個計算。有了足夠的運氣,告訴編譯器使用SSE會爲你做詭計,但要確保你可以使用內部函數和類型。

1

SSE與主題無關。一個線程一次執行一條指令;對於SSE,單條指令一次可適用於4或8組參數。因此,對於多個線程,您還可以運行多個SSE指令來處理更多數據。

可以使用帶for循環的線程。只是不要在裏面使用它們。相反,採用for(i=0; i<z_img.width(); i++) {外環,並將其拆分爲width/4的4個波段。線程0獲得0..width/4,線程1獲取寬度/4..width2等。

在一個不相關的筆記中,您的代碼也會混合使用浮點數和整數數學。 0.5 * x幾乎沒有x/2那麼高效。