¿Hay alguna penalización cuando base + offset está en una página diferente a la base?
Los tiempos de ejecución de estos tres fragmentos:
pageboundary: dq (pageboundary + 8)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx - 8]
sub ecx, 1
jnz .loop
Y esto
pageboundary: dq (pageboundary - 8)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx + 8]
sub ecx, 1
jnz .loop
Y esto
pageboundary: dq (pageboundary - 4096)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx + 4096]
sub ecx, 1
jnz .loop
Are, en un 4770K, aproximadamente 5 ciclos por iteración para el primer fragmento y aproximadamente 9 ciclos por iteración para el segundo fragmento, luego 5 ciclos para el tercer fragmento. Ambos acceden exactamente a la misma dirección, que está alineada en 4K. En el segundo fragmento, solo la direccióncálcul cruza el límite de la página:rdx
yrdx + 8
no pertenece a la misma página, la carga sigue alineada. Con un gran desplazamiento, vuelve a 5 ciclos nuevamente.
¿Cómo funciona este efecto en general?
Enrutar el resultado de la carga a través de una instrucción ALU como esta:
.loop:
mov rdx, [rdx + 8]
or rdx, 0
sub ecx, 1
jnz .loop
Hace que tome 6 ciclos por iteración, lo que tiene sentido como 5 + 1. Reg + 8 debería ser una carga rápida especial y AFAIK toma 4 ciclos, por lo que incluso en este caso parece haber alguna penalización, pero solo 1 ciclo.
Se utilizó una prueba como esta en respuesta a algunos de los comentarios:
.loop:
lfence
; or rdx, 0
mov rdx, [rdx + 8]
; or rdx, 0
; uncomment one of the ORs
lfence
sub ecx, 1
jnz .loop
Poner elor
antes demov
hace que el bucle sea más rápido que sin ningunaor
, poniendo elor
después de lamov
hace que el ciclo sea más lento.