¿Por qué la velocidad de memcpy () cae dramáticamente cada 4KB?

He probado la velocidad dememcpy() notando la velocidad cae dramáticamente en i * 4KB. El resultado es el siguiente: el eje Y es la velocidad (MB / segundo) y el eje X es el tamaño del búfer paramemcpy(), aumentando de 1KB a 2MB. La subfigure 2 y la subfigure 3 detallan la parte de 1KB-150KB y 1KB-32KB.

Ambiente:

CPU: Intel (R) Xeon (R) CPU E5620 a 2.40GHz

OS: 2.6.35-22-generic # 33-Ubuntu

Banderas del compilador GCC: -O3 -msse4 -DINTEL_SSE4 -Wall -std = c99

Supongo que debe estar relacionado con los cachés, pero no puedo encontrar una razón de los siguientes casos hostiles al caché:

¿Por qué mi programa es lento cuando realiza un bucle sobre exactamente 8192 elementos?

¿Por qué la transposición de una matriz de 512x512 es mucho más lenta que la de una matriz de 513x513?

Dado que la degradación del rendimiento de estos dos casos es causada por bucles hostiles que leen bytes dispersos en el caché, desperdiciando el resto del espacio de una línea de caché.

Aquí está mi código:

void memcpy_speed(unsigned long buf_size, unsigned long iters){
    struct timeval start,  end;
    unsigned char * pbuff_1;
    unsigned char * pbuff_2;

    pbuff_1 = malloc(buf_size);
    pbuff_2 = malloc(buf_size);

    gettimeofday(&start, NULL);
    for(int i = 0; i < iters; ++i){
        memcpy(pbuff_2, pbuff_1, buf_size);
    }   
    gettimeofday(&end, NULL);
    printf("%5.3f\n", ((buf_size*iters)/(1.024*1.024))/((end.tv_sec - \
    start.tv_sec)*1000*1000+(end.tv_usec - start.tv_usec)));
    free(pbuff_1);
    free(pbuff_2);
}
ACTUALIZAR

Teniendo en cuenta las sugerencias de @usr, @ChrisW y @Leeor, volví a hacer la prueba con mayor precisión y el gráfico a continuación muestra los resultados. El tamaño del búfer es de 26KB a 38KB, y lo probé todos los demás 64B (26KB, 26KB + 64B, 26KB + 128B, ......, 38KB). Cada prueba recorre 100.000 veces en aproximadamente 0.15 segundos. Lo interesante es que la caída no solo ocurre exactamente en el límite de 4 KB, sino que también aparece en 4 * i + 2 KB, con una amplitud de caída mucho menor.

PD

@Leeor ofreció una forma de llenar la gota, agregando un búfer dummy de 2KB entrepbuff_1 ypbuff_2. Funciona, pero no estoy seguro de la explicación de Leeor.

Respuestas a la pregunta(3)

Su respuesta a la pregunta