我正在编程一个完美的程序来并行化多媒体扩展。该程序包括转换图像,所以我通过一个矩阵,我修改其中的每个像素。为了加快速度,我使用了多媒体扩展:avx较慢,然后sse多媒体扩展
起初我使用了SSE3扩展并实现了2.5加速。接下来,我编程扩展了使用AVX扩展(双倍大小矢量)的sse算法,但是我没有得到SSE3的收益。用SSE执行程序的时间或多或少与AVX相同。 这里是SSE和AVX,分别代码的总结:
for(i=0; i<lim; i+=12) { //tam vale n*n o n*n-12 dependiendo de si n*n es multiplo de 12. 12 ya que 3componentes*4pixeles(4 tamvector)
vectorR = _mm_set_ps(matrix[i+9], matrix[i+6], matrix[i+3], matrix[i]);
vectorG = _mm_set_ps(matrix[i+10], matrix[i+7], matrix[i+4], matrix[i+1]);
vectorB = _mm_set_ps(matrix[i+11], matrix[i+8], matrix[i+5], matrix[i+2]);
calcular_coeficientes_sse3(Ycoef0, Ycoef1, Ycoef2, Ucoef0, Vcoef0, vectorR, vectorG, vectorB,
values0, values255, values128, &vectorY, &vectorU, &vectorV);
_mm_store_ps(&y_aux[0], vectorY);
_mm_store_ps(&u_aux[0], vectorU);
_mm_store_ps(&v_aux[0], vectorV);
//Colocamos los datos en la matriz
//PIXEL 1
matrix[i] = y_aux[0];
matrix[i+1]=u_aux[0];
matrix[i+2]=v_aux[0];
//PIXEL 2
matrix[i+3]=y_aux[1];
matrix[i+4]=u_aux[1];
matrix[i+5]=v_aux[1];
//PIXEL 3
matrix[i+6] = y_aux[2];;
matrix[i+7]=u_aux[2];
matrix[i+8]=v_aux[2];
//PIXEL 4
matrix[i+9]=y_aux[3];
matrix[i+10]=u_aux[3];
matrix[i+11]=v_aux[3];
}
for(i=0; i<lim; i+=24) { //Vamos de 8 en 8 pixeles
vectorR = _mm256_set_ps(matrix[i+21], matrix[i+18], matrix[i+15] ,matrix[i+12],matrix[i+9], matrix[i+6], matrix[i+3], matrix[i]);
vectorG = _mm256_set_ps(matrix[i+22], matrix[i+19], matrix[i+16], matrix[i+13], matrix[i+10], matrix[i+7], matrix[i+4], matrix[i+1]);
vectorB = _mm256_set_ps(matrix[i+23], matrix[i+20], matrix[i+17], matrix[i+14], matrix[i+11], matrix[i+8], matrix[i+5], matrix[i+2]);
calcular_coeficientes_avx(Ycoef0, Ycoef1, Ycoef2, Ucoef0, Vcoef0, vectorR, vectorG, vectorB,
values0, values255, values128, &vectorY, &vectorU, &vectorV);
_mm256_store_ps(&y_aux[0], vectorY);
_mm256_store_ps(&u_aux[0], vectorU);
_mm256_store_ps(&v_aux[0], vectorV);
//Colocamos los datos en la matriz
//PIXEL 1
matrix[i] = y_aux[0];
matrix[i+1]=u_aux[0];
matrix[i+2]=v_aux[0];
//PIXEL 2
matrix[i+3]=y_aux[1];
matrix[i+4]=u_aux[1];
matrix[i+5]=v_aux[1];
//PIXEL 3
matrix[i+6] = y_aux[2];;
matrix[i+7]=u_aux[2];
matrix[i+8]=v_aux[2];
//PIXEL 4
matrix[i+9]=y_aux[3];
matrix[i+10]=u_aux[3];
matrix[i+11]=v_aux[3];
//PIXEL 5
matrix[i+12]=y_aux[4];
matrix[i+13]=u_aux[4];
matrix[i+14]=v_aux[4];
//PIXEL 6
matrix[i+15]=y_aux[5];
matrix[i+16]=u_aux[5];
matrix[i+17]=v_aux[5];
//PIXEL 7
matrix[i+18]=y_aux[6];
matrix[i+19]=u_aux[6];
matrix[i+20]=v_aux[6];
//PIXEL 8
matrix[i+21]=y_aux[7];
matrix[i+22]=u_aux[7];
matrix[i+23]=v_aux[7];
}
void calcular_coeficientes_sse3(__m128 Ycoef0, __m128 Ycoef1, __m128 Ycoef2, __m128 Ucoef0, __m128 Vcoef0, __m128 vectorR,
__m128 vectorG, __m128 vectorB, __m128 values0, __m128 values255, __m128 values128,
__m128 *vectorY, __m128 *vectorU, __m128 *vectorV) {
//CALCULO DE Y3, Y2, Y1, Y0 (Cuatro píxeles consecutivos)
//PRIMERA VUELta
__m128 valores1 = _mm_mul_ps(Ycoef0, vectorR); // valores1 = (0.299*R[3], 0.299*R[2], 0.299*R[1], 0.299*R[0])
__m128 valores2 = _mm_mul_ps(Ycoef1, vectorG); // valores2 = (0.587*G[3], 0.587*G[2], 0.587*G[1], 0.587*G[0])
__m128 valores3 = _mm_mul_ps(Ycoef2, vectorB); // valores3 = (0.114*B[3], 0.114*B[2], 0.114*B[1], 0.114*B[0]);
valores1 = _mm_add_ps(valores1, valores2); // valores1 = (0.299*R[3] + 0.587*G[3], 0.299*R[2] + 0.587*G[2], 0.299*G[1]+ ..., ...)
*vectorY = _mm_add_ps(valores1, valores3); // vectorY = (Y[3], Y[2], Y[1], Y[0])
*vectorY = _mm_floor_ps(*vectorY);
//Calculo de U3, U2, U1, U0
//B-Y
valores1 = _mm_sub_ps(vectorB, *vectorY); // valores1 = (B[3]-Y[3], B[2]-Y[2], B[1]-Y[1], B[0]-Y[0])
valores1 = _mm_mul_ps(Ucoef0, valores1); // valores1 = (0.492*(B[3]-Y[3]), 0.492*(B[2]-Y[2]), 0.492*(B[1]-Y[1]), 0.492*(...))
*vectorU = _mm_add_ps(valores1, values128); // vectorU = (U[3], U[2], U[1], U[0])
//CALCULO DE V3, V2, V1, V0
// R-Y
valores1 = _mm_sub_ps(vectorR, *vectorY); // valores1 = (R[3]-Y[3], R[2]-Y[2], R[1]-Y[1], R[0]-Y[0])
valores1 = _mm_mul_ps(Vcoef0, valores1); // valores1 = (0.877*(R[3]-Y[3]), 0.877*(R[2]-Y[2]), 0.877*(R[1]-Y[1]), 0.877*(...))
valores1 = _mm_add_ps(valores1, values128); // valores1 = (0.877*(R[3]-Y[3]) + 128, 0.877*(R[2]-Y[2]) + 128, ..., ...)
//valores1 pueden necesitar saturacion.
//SATURACIONES a 0
//Para evitar hacer comparaciones cogemos el mayor entre 0 y el valor V[i]:
// Si V[i] > 0 se queda con V[i] pues es mayor que 0.
// Si V[i] < 0 se queda con 0 pues es mayor que un número negativo.
valores1 = _mm_max_ps(valores1, values0); // valores1 = (max(0.877*(R[3]-Y[3]) + 128,0), ..., ..., ...)
// SATURACIONES a 255
//Para evitar hacer comparacion cogemos el menor entre 255 y el valor V[i]
// Si V[i] < 255 entonces se queda con el menor, V[i]
// Si V[i] > 255 entonces se queda con el menor, 255.
*vectorV = _mm_min_ps(valores1, values255); //vectorV = (V[3], V[2], V[1], V[0])
//NOTA: Al estar las operaciones implementadas en hardware se hacen las operaciones max y min en un 1 ciclo.
//por lo que solo en dos ciclos comprobamos la saturacion de 4 valores V.
return; //El procedimiento termina devolviendo vectorY, vectorU y vectorV
}
void calcular_coeficientes_avx(__m256 Ycoef0, __m256 Ycoef1, __m256 Ycoef2, __m256 Ucoef0, __m256 Vcoef0, __m256 vectorR,
__m256 vectorG, __m256 vectorB, __m256 values0, __m256 values255, __m256 values128,
__m256 *vectorY, __m256 *vectorU, __m256 *vectorV) {
//CALCULO DE Y7, Y6, Y5, Y4, Y3, Y2, Y1, Y0 (Cuatro píxeles consecutivos)
__m256 valores1 = _mm256_mul_ps(Ycoef0, vectorR);
__m256 valores2 = _mm256_mul_ps(Ycoef1, vectorG);
__m256 valores3 = _mm256_mul_ps(Ycoef2, vectorB);
valores1 = _mm256_add_ps(valores1, valores2);
*vectorY = _mm256_add_ps(valores1, valores3);
*vectorY = _mm256_floor_ps(*vectorY);
//Calculo de U7, U6, U5, U4, U3, U2, U1, U0
valores1 = _mm256_sub_ps(vectorB, *vectorY);
valores1 = _mm256_mul_ps(Ucoef0, valores1);
*vectorU = _mm256_add_ps(valores1, values128);
//CALCULO DE V7, V6, V5, V4, V3, V2, V1, V0
// R-Y
valores1 = _mm256_sub_ps(vectorR, *vectorY);
valores1 = _mm256_mul_ps(Vcoef0, valores1);
valores1 = _mm256_add_ps(valores1, values128);
//valores1 pueden necesitar saturacion.
//SATURACIONES a 0
//Para evitar hacer comparaciones cogemos el mayor entre 0 y el valor V[i]:
valores1 = _mm256_max_ps(valores1, values0);
// SATURACIONES a 255
//Para evitar hacer comparacion cogemos el menor entre 255 y el valor V[i]
// Si V[i] < 255 entonces se queda con el menor, V[i]
// Si V[i] > 255 entonces se queda con el menor, 255.
*vectorV = _mm256_min_ps(valores1, values255); //vectorV = (V[3], V[2], V[1], V[0])
//NOTA: Al estar las operaciones implementadas en hardware se hacen las operaciones max y min en un 1 ciclo.
//por lo que solo en dos ciclos comprobamos la saturacion de 4 valores V.
return; //El procedimiento termina devolviendo vectorY, vectorU y vectorV
}
正如你可以看到两个SSE和AVX是相同的,但最后是扩展并使用更长的大小矢量。为什么执行时间相同?
注意:我已经在两台带有AVX支持的计算机上试过(显然),我也有同样的问题。
非常感谢。
除了在商店瓶颈,工作是在'calcular_coeficientes_avx'和'calcular_coeficientes_sse'完成的,但这些功能都没有。另外,AVX512标签可能会引起误解。 –
'_mm256_set_ps(矩阵[i + 21],矩阵[i + 18],...'请不要这样做,也不要在SSE中,每当你写这样的东西时,一只小狗就会死亡。 ,然后洗牌 – harold
*我在两台不同的计算机上试过*:不同的是:它们都是Intel SnB系列,还是AMD?如果*你的代码写得很好,AMD CPU通常不会获得太多好处从使用256b AVX。请参阅http://agner.org/optimize/,和其他链接在[x86标签wiki](http://stackoverflow.com/tags/x86/info)。 –