我正在编写一个完美的程序来与多媒体扩展并行。该程序包括转换图像,因此我遍历一个矩阵并修改其中的每个像素。为了更快地浏览,我使用多媒体扩展:
起初我使用 SSE3 扩展并实现了 2.5 的加速。接下来,我对它进行了编程,扩展了 sse 算法以使用 AVX 扩展(双尺寸向量),但我没有获得相对于 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 的不同计算机上进行了尝试(显然),我也遇到了同样的问题。
非常感谢。