c - SSE 并行化

标签 c parallel-processing openmp sse

您好,我正在尝试提高这段代码的性能,假设我有一台能够处理 4 个线程的机器。我首先考虑使 omp 并行化,但后来我发现这个函数在 for 循环中,因此多次创建线程效率不高。所以我想知道如何使用更高效的 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);
        }
    }

最佳答案

我对代码进行了一些改动,因此您可能需要对其进行重大更改,但这是对 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 位,其余的不会影响结果。字节不够宽(除非你有一些我不知道的额外保证),但无论如何它们都会很烦人,因为没有很好的方法来乘以它们。

为简单起见,我假装输入采用 xp[0] 等连续数组的形式,这不是您在这里需要的,但是我没有时间计算所有的加载和改组。

关于c - SSE 并行化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40547731/

相关文章:

c - 二维字符数组

c - 画一条线: Problems with the mouse cursor on C Vga graphics

python - 快速重新排列文本文件

java - Aparapi GPU 执行速度比 CPU 慢

c - OpenMP 自定义缩减变量

c - 强制编译器/链接器按定义对变量进行分组(物理上位于连续的 RAM 位置)

c - 通过过程将格式字符串传递给 fprintf

python - 为什么 numba parallel=True 比 parallel=False 慢

openmp - cython:prange 中的私有(private)变量

C pragma omp 并行