멀티미디어 확장과 병렬 처리 할 수있는 완벽한 프로그램을 프로그래밍하고 있습니다. 이 프로그램은 이미지를 변환하는 것으로 구성되어 있으므로 매트릭스로 가서 각 픽셀을 수정합니다. 이동 속도가 더 빠르면 멀티미디어 확장을 사용합니다.avx 느린 다음 sse 멀티미디어 확장
처음에는 SSE3 확장을 사용하여 2.5 속도 향상을 얻었습니다. 다음으로 AVX 확장 (Double size vector)을 사용하기 위해 sse 알고리즘을 확장하여 프로그래밍했지만 SSE3에 대한 이득은 얻지 못했습니다. SSE로 프로그램을 실행하는 시간은 AVX와 동일합니다. 여기 는 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
}
확장하고 더 긴 크기의 벡터를 사용하십시오. 왜 같은 실행 시간입니까?
참고 : 나는 AVX 지원 (obviusly)을 사용하는 두 대의 다른 컴퓨터에서 시도했지만 동일한 문제가 있습니다.
대단히 감사합니다.
는 작업 calcular_coeficientes_avx''에서 수행되며,'아직 그 기능이없는 calcular_coeficientes_sse'. 또한 AVX512 태그는 오도 된 것일 수 있습니다. –
'_mm256_set_ps (행렬 [i + 21], 행렬 [i + 18], ...)이 작업을 수행하지 마십시오 SSE에서도 마찬가지입니다 .. 그런 식으로 글을 쓸 때마다 강아지가 죽습니다. – harold
* 두 가지 다른 컴퓨터에서 시도 했었습니다 * : 다른 방법? 인텔 SnB 제품군 또는 두 AMD 모두였습니까? 심지어 * 코드가 잘 작성된 경우 AMD CPU는 많은 이점을 얻지 못하는 경우가 많습니다 256b AVX 사용에서. http://agner.org/optimize/ 및 [x86 태그 위키]의 다른 링크 (http://stackoverflow.com/tags/x86/info)를 참조하십시오. –