Extraños efectos de rendimiento de tiendas dependientes cercanas en un bucle de búsqueda de puntero en IvyBridge. Agregar una carga adicional lo acelera?
Primero tengo la configuración a continuación en un IvyBridge, insertaré el código de carga útil de medición en la ubicación comentada. Los primeros 8 bytes debuf
almacenar la dirección debuf
en sí, lo uso para crear una dependencia transportada en bucle:
section .bss
align 64
buf: resb 64
section .text
global _start
_start:
mov rcx, 1000000000
mov qword [buf], buf
mov rax, buf
loop:
; I will insert payload here
; as is described below
dec rcx
jne loop
xor rdi, rdi
mov rax, 60
syscall
caso 1I inserción en la ubicación de la carga útil:
mov qword [rax+8], 8
mov rax, [rax]
perf
muestra que el bucle es 5.4c / iter. Es algo comprensible, porque la latencia L1d es de 4 ciclos.
I invertir el orden de estas dos instrucciones:
mov rax, [rax]
mov qword [rax+8], 8
El resultado de repente se convierte en 9c / iter. No entiendo por qué. Debido a que la primera instrucción de la siguiente iteración no depende de la segunda instrucción de la iteración actual, esta configuración no debería ser diferente con el caso 1.
También utilicé la herramienta IACA para analizar estos dos casos de forma estática, pero la herramienta no es confiable, ya que predice el mismo resultado 5.71c / iter para ambos casos, lo que contradice el experimento.
case 3:Then un inserto irrelevantemov
instrucción para el caso 2:
mov rax, [rax]
mov qword [rax+8], 8
mov rbx, [rax+16]
Ahora el resultado se convierte en 6.8c / iter. Pero, ¿cómo puede un @ irrelevanmov
insertó aumentar la velocidad de 9c / iter a 6.8c / iter?
a herramienta IACA predice un resultado incorrecto como en el caso anterior, muestra 5.24c / iter.
Ahora estoy totalmente confundido, ¿cómo comprender los resultados anteriores?
Editar para más información: En los casos 1 y 2, hay una direcciónrax+8
. Los mismos resultados se mantienen para los casos 1 y 2 sirax+8
se cambia arax+16
orax+24
. Pero sucede algo sorprendente cuando se cambia arax+32
: El caso 1 se convierte en 5.3c / ITER, el caso 2 se convierte de repente 4.2c / iter
perf
eventos$ perf stat -ecycles,ld_blocks_partial.address_alias,int_misc.recovery_cycles,machine_clears.count,uops_executed.stall_cycles,resource_stalls.any ./a.out
case 1 para[rax+8]
:
5,429,070,287 cycles (66.53%)
6,941 ld_blocks_partial.address_alias (66.75%)
426,528 int_misc.recovery_cycles (66.83%)
17,117 machine_clears.count (66.84%)
2,182,476,446 uops_executed.stall_cycles (66.63%)
4,386,210,668 resource_stalls.any (66.41%)
case 2 para[rax+8]
:
9,018,343,290 cycles (66.59%)
8,266 ld_blocks_partial.address_alias (66.73%)
377,824 int_misc.recovery_cycles (66.76%)
10,159 machine_clears.count (66.76%)
7,010,861,225 uops_executed.stall_cycles (66.65%)
7,993,995,420 resource_stalls.any (66.51%)
case 3 para[rax+8]
:
6,810,946,768 cycles (66.69%)
1,641 ld_blocks_partial.address_alias (66.73%)
223,062 int_misc.recovery_cycles (66.73%)
7,349 machine_clears.count (66.74%)
3,618,236,557 uops_executed.stall_cycles (66.58%)
5,777,653,144 resource_stalls.any (66.53%)
case 2 para[rax+32]
:
4,202,233,246 cycles (66.68%)
2,969 ld_blocks_partial.address_alias (66.68%)
149,308 int_misc.recovery_cycles (66.68%)
4,522 machine_clears.count (66.68%)
1,202,497,606 uops_executed.stall_cycles (66.64%)
3,179,044,737 resource_stalls.any (66.64%)