您好我正在尝试提高此代码的性能,假设我有一台能够处理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);
}
}
答案 0 :(得分: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
,p[0]
等连续数组的形式,这不是你需要的,但我没有时间去研究所有的装载和洗牌。
答案 1 :(得分:1)
SSE与线程完全无关。单个线程一次执行一条指令;使用SSE,单个指令可以一次应用于4或8组参数。因此,对于多个线程,您还可以运行多个SSE指令来处理更多数据。
你可以使用带有for循环的线程。只是不要在里面使用它们。相反,取for(i=0; i<z_img.width(); i++) {
外循环并将其拆分为width/4
的4个波段。线程0获得0..width / 4,线程1获得宽度/ 4..width / 2等。
在一个不相关的注释中,您的代码也会混淆浮点数和整数数学。 0.5 * x
效率不如x/2
。
答案 2 :(得分:0)
使用OpenMP,您可以尝试将#pragma
添加到最外层的for循环中。这应该可以解决你的问题。
由于对数据的额外对齐限制,使用SSE路由比较棘手,但最简单的转换是扩展cubicInterpolate_paralelo
以一次处理多个计算。运气不错,告诉编译器使用SSE会为你做到这一点,但为了确保,你可以使用内在函数和类型。