Experimento 4 de CSAPP: Experimento de optimización del rendimiento (Perflab)

       Esta serie de artículos es un experimento organizado por el curso básico "Sistema de Computación" de la carrera de computación de la Universidad de Ciencia y Tecnología de China. El libro de texto y contenido utilizado en la clase es el libro negro CSAPP. En ese momento, tomó mucha energía y desvíos. Ahora resumiré cada experimento. Este artículo es el cuarto experimento: experimento de optimización del rendimiento (Perflab).

1. Nombre del experimento: perflab

2. Horas experimentales: 3

3. Contenido y propósito del experimento:

       Este experimento optimiza el código de procesamiento de imágenes. El procesamiento de imágenes proporciona muchas funciones que pueden mejorarse mediante la optimización. En esta práctica de laboratorio, consideraremos dos operaciones de procesamiento de imágenes: rotar , que gira la imagen 90° en el sentido contrario a las agujas del reloj, y suavizar , que "suaviza" o "difumina" la imagen.

       Para este experimento, consideraremos que la imagen está representada por una matriz bidimensional M  , y denotaremos el valor del píxel en la posición (i, j) por M i,j . Un valor de píxel es un triplete de valores rojo, verde y azul (RGB). Solo consideramos imágenes cuadradas. Sea N el  número de filas (y columnas) de la imagen. Las filas y columnas están numeradas en estilo C, de 0 a N-1  .

       Bajo esta representación, la operación de rotación  se puede implementar simplemente combinando las siguientes dos operaciones matriciales:

  • Transponer: para cada (i,j), intercambie M i,j  con M j,i  .
  • Intercambio de filas: Intercambie la fila i con la fila N  - 1 - i.

       Vea la imagen de abajo para más detalles:

        La operación suave  se puede calcular tomando la media de cada píxel y los píxeles circundantes (como máximo una cuadrícula de nueve cuadrados de 3 × 3 centrada en el píxel). Consulte la Figura 2 para obtener detalles, los píxeles M2[1][1] y M2[N - 1][N - 1] están dados por:

 4. Pasos y resultados experimentales:

        Primero copie perflab-handout.tar a una carpeta protegida para este experimento.

        Luego ingrese el comando en la línea de comando: tar xvf perflab-handout.tar Esto extraerá varios archivos al directorio actual.

        El único archivo que puede realizar cambios y finalmente confirmar es el programa kernels.c driver.c es un controlador que puede usar para evaluar el rendimiento de su solución. Use el comando: make driver para generar el código del controlador y use el comando ./driver para ejecutarlo.

        Mirando el archivo kernels.c, encontrará una estructura C: equipo. Deberá completar la información de los miembros de su grupo. Por favor, complételo de inmediato en caso de que lo olvide.

      1. ingenuo_rotar

/*
 *naive_rotate - The naive baseline version of rotate
 */
char naive_rotate_descr[] ="naive_rotate: Naive baseline implementation";
void naive_rotate(int dim, pixel *src,pixel *dst)
{
   int i, j;
 
   for (i = 0; i < dim; i++)
         for(j = 0; j < dim; j++)
             dst[RIDX(dim-1-j, i, dim)] = src[RIDX(i, j,dim)];
}

         La definición de la macro se encuentra en el archivo de cabecera defs.h:

#defineRIDX(i,j,n) ((i)*(n)+(j))

        Luego, este código puede rotar fácilmente una imagen, reposicionará todos los píxeles en filas y columnas, lo que dará como resultado una rotación de 90 grados de toda la imagen.

        Sin embargo, debido a que el tamaño de paso de esta cadena de códigos es demasiado largo, la tasa de aciertos de caché es muy baja, por lo que la eficiencia general de la operación es baja. Por lo tanto, teniendo en cuenta el tamaño de la memoria caché, se deben almacenar 32 píxeles en secuencia (almacenamiento en columna) al almacenar. (Los 32 píxeles están dispuestos para hacer un uso completo de la memoria caché de primer nivel (32 KB), y se adopta la estrategia de bloques, y el tamaño de cada bloque es 32)

        Esto puede ser compatible con caché y puede mejorar en gran medida la eficiencia.

      2.perf_rotar

        Considere el bloque rectangular 32 * 1, el desenrollado de bucle de 32 vías y haga que la dirección de destino sea consecutiva para reducir la cantidad de escrituras en la memoria

//宏定义一个复制函数,方便程序编写
#define COPY(d,s) *(d)=*(s)
char rotate_descr[] = "rotate: Currentworking version";

void rotate( int dim,pixel *src,pixel *dst)
{
   int i,j;
   for(i=0;i<dim;i+=32)//32路循环展开,32个像素依次存储
         for(j=dim-1;j>=0;j-=1)
{       
         pixel*dptr=dst+RIDX(dim-1-j,i,dim);
         pixel*sptr=src+RIDX(i,j,dim);
//进行复制操作
         COPY(dptr,sptr);sptr+=dim;
         COPY(dptr+1,sptr);sptr+=dim;
         COPY(dptr+2,sptr);sptr+=dim;
         COPY(dptr+3,sptr);sptr+=dim;
         COPY(dptr+4,sptr);sptr+=dim;
         COPY(dptr+5,sptr);sptr+=dim;
         COPY(dptr+6,sptr);sptr+=dim;
         COPY(dptr+7,sptr);sptr+=dim;
         COPY(dptr+8,sptr);sptr+=dim;
         COPY(dptr+9,sptr);sptr+=dim;
         COPY(dptr+10,sptr);sptr+=dim;
         COPY(dptr+11,sptr);sptr+=dim;
         COPY(dptr+12,sptr);sptr+=dim;
         COPY(dptr+13,sptr);sptr+=dim;
         COPY(dptr+14,sptr);sptr+=dim;
         COPY(dptr+15,sptr);sptr+=dim;
         COPY(dptr+16,sptr);sptr+=dim;
         COPY(dptr+17,sptr);sptr+=dim;
         COPY(dptr+18,sptr);sptr+=dim;
         COPY(dptr+19,sptr);sptr+=dim;
         COPY(dptr+20,sptr);sptr+=dim;
         COPY(dptr+21,sptr);sptr+=dim;
         COPY(dptr+22,sptr);sptr+=dim;
         COPY(dptr+23,sptr);sptr+=dim;
         COPY(dptr+24,sptr);sptr+=dim;
         COPY(dptr+25,sptr);sptr+=dim;
         COPY(dptr+26,sptr);sptr+=dim;
         COPY(dptr+27,sptr);sptr+=dim;
         COPY(dptr+28,sptr);sptr+=dim;
         COPY(dptr+29,sptr);sptr+=dim;
         COPY(dptr+30,sptr);sptr+=dim;
         COPY(dptr+31,sptr);
}
}

      3 .liso

char naive_smooth_descr[] ="naive_smooth: Naive baseline implementation";
void naive_smooth(int dim, pixel *src,pixel *dst)
{
   int i, j;
 
   for (i = 0; i < dim; i++)
   for (j = 0; j < dim; j++)
       dst[RIDX(i, j, dim)] = avg(dim, i, j, src);
}

        Este código llama con frecuencia a la función avg, y las funciones initialize_pixel_sum, Accumulate_sum, Assign_sum_to_pixel también se llaman con frecuencia en la función avg, y también contiene dos capas de bucles for, y deberíamos reducir el tiempo de sobrecarga de las llamadas a funciones. Por lo tanto, el código debe reescribirse para no llamar a la función avg. 

        Circunstancias especiales, trato especial:

        El procesamiento de la función Smooth se divide en 4 bloques, uno es el interior del cuerpo principal, que tiene un promedio de 9 puntos; el otro es 4 vértices, que tiene un promedio de 4 puntos; el tercero es cuatro límites, que tiene un promedio de 6 puntos. Comience a procesar desde la parte superior de la imagen, luego el límite superior y procéselo secuencialmente. Al procesar el límite izquierdo, el ciclo for procesa la parte principal de una línea, por lo que existe el siguiente código optimizado.

      4 .perf_ suave

charsmooth_descr[] = "smooth: Current working version";
void smooth(intdim, pixel* src, pixel* dst) {
	int i, j;
	int dim0 = dim;
	int dim1 = dim - 1;
	int dim2 = dim - 2;
	pixel* P1, * P2, * P3;
	pixel* dst1;
	P1 = src;
	P2 = P1 + dim0;
	//左上角像素处理      采用移位运算代替avg的某些操作
	dst->red = (P1->red + (P1 + 1)->red + P2->red + (P2 + 1)->red) >> 2;          dst->green = (P1->green + (P1 + 1)->green + P2->green + (P2 + 1)->green) >> 2;          dst->blue = (P1->blue + (P1 + 1)->blue + P2->blue + (P2 + 1)->blue) >> 2;
	dst++;
	//上边界处理 
	for (i = 1; i < dim1; i++) {
		dst->red = (P1->red + (P1 + 1)->red + (P1 + 2)->red + P2->red + (P2 + 1)->red + (P2 + 2)->red) / 6;                     dst->green = (P1->green + (P1 + 1)->green + (P1 + 2)->green + P2->green + (P2 + 1)->green + (P2 + 2)->green) / 6;                      dst->blue = (P1->blue + (P1 + 1)->blue + (P1 + 2)->blue + P2->blue + (P2 + 1)->blue + (P2 + 2)->blue) / 6;
		dst++;
		P1++;
		P2++;
	}
	//右上角像素处理          dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red)>>2; 
	dst->green = (P1->green + (P1 + 1)->green + P2->green + (P2 + 1)->green) >> 2;          dst->blue = (P1->blue + (P1 + 1)->blue + P2->blue + (P2 + 1)->blue) >> 2;
	dst++;
	P1 = src;
	P2 = P1 + dim0;
	P3 = P2 + dim0;
	//左边界处理 
	for (i = 1; i < dim1; i++) {
		dst->red = (P1->red + (P1 + 1)->red + P2->red + (P2 + 1)->red + P3->red + (P3 + 1)->red) / 6;                                dst->green = (P1->green + (P1 + 1)->green + P2->green + (P2 + 1)->green + P3->green + (P3 + 1)->green) / 6;                               dst->blue = (P1->blue + (P1 + 1)->blue + P2->blue + (P2 + 1)->blue + P3->blue + (P3 + 1)->blue) / 6;
		dst++;
		dst1 = dst + 1;
	}
	//主体中间部分处理     
	for (j = 1; j < dim2; j += 2) {
		//同时处理2个像素          
		dst->red = (P1->red + (P1 + 1)->red + (P1 + 2)->red + P2->red + (P2 + 1)->red + (P2 + 2)->red + P3->red + (P3 + 1)->red + (P3 + 2)->red) / 9;
		dst->green = (P1->green + (P1 + 1)->green + (P1 + 2)->green + P2->green + (P2 + 1)->green + (P2 + 2)->green + P3->green + (P3 + 1)->green + (P3 + 2)->green) / 9;
		dst->blue = (P1->blue + (P1 + 1)->blue + (P1 + 2)->blue + P2->blue + (P2 + 1)->blue + (P2 + 2)->blue + P3->blue + (P3 + 1)->blue + (P3 + 2)->blue) / 9;
		dst1->red = ((P1 + 3)->red + (P1 + 1)->red + (P1 + 2)->red + (P2 + 3)->red + (P2 + 1)->red + (P2 + 2)->red + (P3 + 3)->red + (P3 + 1)->red + (P3 + 2)->red) / 9;
		dst1->green = ((P1 + 3)->green + (P1 + 1)->green + (P1 + 2)->green + (P2 + 3)->green + (P2 + 1)->green + (P2 + 2)->green + (P3 + 3)->green + (P3 + 1)->green + (P3 + 2)->green) / 9;
		dst1->blue = ((P1 + 3)->blue + (P1 + 1)->blue + (P1 + 2)->blue + (P2 + 3)->blue + (P2 + 1)->blue + (P2 + 2)->blue + (P3 + 3)->blue + (P3 + 1)->blue + (P3 + 2)->blue) / 9;
		dst += 2; dst1 += 2; P1 += 2; P2 += 2; P3 += 2;
	}
	for (; j < dim1; j++) {
		dst->red = (P1->red + (P1 + 1)->red + (P1 + 2)->red + P2->red + (P2 + 1)->red + (P2 + 2)->red + P3->red + (P3 + 1)->red + (P3 + 2)->red) / 9;
		dst->green = (P1->green + (P1 + 1)->green + (P1 + 2)->green + P2->green + (P2 + 1)->green + (P2 + 2)->green + P3->green + (P3 + 1)->green + (P3 + 2)->green) / 9;
		dst->blue = (P1->blue + (P1 + 1)->blue + (P1 + 2)->blue + P2->blue + (P2 + 1)->blue + (P2 + 2)->blue + P3->blue + (P3 + 1)->blue + (P3 + 2)->blue) / 9;
		dst++;       P1++; P2++; P3++;
	}
	//右侧边界处理                              dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red+P3->red+(P3+1)->red)/6;                                  dst->green=(P1->green+(P1+1)->green+P2->green+(P2+1)->green+P3->green+(P3+1)->green)/6;                                 dst->blue=(P1->blue+(P1+1)->blue+P2->blue+(P2+1)->blue+P3->blue+(P3+1)->blue)/6;     
	dst++;      P1 += 2;      P2 += 2;      P3 += 2;
}
//左下角处理              dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red)>>2;     
dst->green = (P1->green + (P1 + 1)->green + P2->green + (P2 + 1)->green) >> 2;
dst->blue = (P1->blue + (P1 + 1)->blue + P2->blue + (P2 + 1)->blue) >> 2;
dst++;
//下边界处理             
for (i = 1; i < dim1; i++) {
	dst->red = (P1->red + (P1 + 1)->red + (P1 + 2)->red + P2->red + (P2 + 1)->red + (P2 + 2)->red) / 6;                          dst->green = (P1->green + (P1 + 1)->green + (P1 + 2)->green + P2->green + (P2 + 1)->green + (P2 + 2)->green) / 6;                          dst->blue = (P1->blue + (P1 + 1)->blue + (P1 + 2)->blue + P2->blue + (P2 + 1)->blue + (P2 + 2)->blue) / 6;
	dst++;      P1++;     P2++;
}
//右下角像素处理             dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red)>>2;              dst->green=(P1->green+(P1+1)->green+P2->green+(P2+1)->green)>>2;             dst->blue=(P1->blue+(P1+1)->blue+P2->blue+(P2+1)->blue)>>2;
//全部处理完毕
}

      5. Resultados Experimentales

 Aceleración promedio de 13,1 veces para operaciones de rotación

 Aceleración promedio de 48.4x para operaciones fluidas

Supongo que te gusta

Origin blog.csdn.net/qq_35739903/article/details/119653717
Recomendado
Clasificación