2017-03-28 2 views
2

J'ai exécuté le code d'assemblage suivant: (qui itère 1000 fois dans un tableau de 10 000 000 éléments de 4 octets chacun) sur un processeur Intel Core i7 (avec cache de données 32 Ko L1 et 64B L1 taille de ligne de cache)Comportement du processeur et du cache Intel Core i7

main: 
.LFB0: 
    .cfi_startproc 
    mov edx, 1000 
    jmp .L2 
.L3: 
    mov ecx, DWORD PTR v[0+eax*4] 
    add eax, 1 

    cmp eax, 10000000 
    jl .L3 
    sub edx, 1 
    je .L4 
.L2: 
    mov eax, 0 
    jmp .L3 
.L4: 
    mov eax, 0 
    ret 
    .cfi_endproc 

Perf donne les statistiques suivantes:

10,135,716,950  L1-dcache-loads 
601,544,266  L1-dcache-load-misses  # 5.93% of all L1-dcache hits 
4.747253821 seconds time elapsed 

Cela rend tout à fait sens parce que j'accède 1 000 * 10 000 000 = 10 000 000 000 éléments en mémoire, et ligne de cache étant 64B (avec un élément dans le vecteur de 4 B) cela signifie un cache cache L1 à e très 16 éléments (donc environ 625 000 000 cache manquants).

Maintenant, j'ai "déroula" une partie de la boucle et le code est:

.cfi_startproc 
    mov  edx, 1000 
    jmp  .L2 
.L3: 
    mov  ecx, DWORD PTR v[0+eax*4] 
    mov  ecx, DWORD PTR v[0+eax*4 + 4] 
    mov  ecx, DWORD PTR v[0+eax*4 + 8] 
    mov  ecx, DWORD PTR v[0+eax*4 + 12] 

    add  eax, 4 

    cmp  eax, 2500000 
    jl  .L3 
    sub  edx, 1 
    je  .L4 
.L2: 
    mov  eax, 0 
    jmp  .L3 
.L4: 
    mov  eax, 0 
    ret 
    .cfi_endproc 

comment Perf donne les statistiques suivantes:

2,503,436,639  L1-dcache-loads 
123,835,666  L1-dcache-load-misses  # 4.95% of all L1-dcache hits 
0.629926637 seconds time elapsed 

Je ne peux pas comprendre pourquoi?

1) Il y a moins de charges de cache L1, puisque j'accède à la même quantité de données?

2) Le code est 6 fois plus rapide que la première version? Je sais qu'il a à faire avec l'exécution hors de l'ordre et l'exécution superscalaire, mais je ne peux pas expliquer cela en détail (je veux comprendre exactement ce qui provoque cette accélération).

Répondre

4

Mauvaises nouvelles - vous avez un bogue dans un second;)

Code d'origine

.L3: 
    mov ecx, DWORD PTR v[0+eax*4] 
    add eax, 1 
    cmp eax, 10000000 
    jl .L3 

Deuxième version

.L3: 
    mov  ecx, DWORD PTR v[0+eax*4] 
    mov  ecx, DWORD PTR v[0+eax*4 + 4] 
    mov  ecx, DWORD PTR v[0+eax*4 + 8] 
    mov  ecx, DWORD PTR v[0+eax*4 + 12] 
    add  eax, 4 
    cmp  eax, 2500000 <- here 
    jl  .L3 

Dans les deux cas, vous devez charger 10 millions d'éléments. L'adresse de l'élément Max accessible dans les deux cas doit être la même, n'est-ce pas?

Ainsi, en première adresse cas max est:

(10.000.000-1)*4 = 39.999.996 

et seconde:

(2.500.000-4)*4+12 = 9.999.996 

exactement 4 fois moins.

Juste fixer le second exemple à cmp eax, 10000000 aussi. .

+0

Ok :(Je fixe ce maintenant les coups de cache et les charges sont ok Mais il y a encore exécuté plus rapidement..? 2.617806762 secondes pourquoi il est seulement parce qu'il doit faire moins d'instructions de saut – SebiSebi

+0

déroulage apporte généralement des gains Second?. Vérifiez également ce qui se passe si vous ne chargez pas toujours sur ecx mais sur des registres différents (les 3 premières charges sont "non efficaces" car la dernière écrase toujours ecx pour que CPU puisse voir cela et fasse un peu de magie ici) .Vérifiez également ce qui se passe si vous vous déroulez 8 ou 16 fois. – Anty