> Sachant que la majorité du code se résume à l'exécution de LOAD & STORE 
> (mesure sur des millions de lignes de code ayant permit de définir 
> l'architecture HP-PA, ~80% !!!), je demande à voir l'effet sur un serveur WEB 
> ou de base de données... Le monde se focalise essentiellement sur des 
> micro-benchmarks débiles qui n'ont quasi aucun impact dans le monde réel. 
> Soyons sérieux, si les techniques de limitation du "branch misprediction" 
> sont utiles dans certain cas, sont impact est souvent largement surévalué. 
> Qui plus est, la plupart du temps ces "techniques" se résument à faire une 
> moyenne sur les trois derniers branchements à cette adresse... et encore ne 
> faut-il pas en avoir trop... car les registres de "misprediction" sont très 
> limités... La taille, et surtout l'architecture, de la cache et du TLB ont 
> beaucoup plus d'impact que cette fameuse technique de "misprediction".

Je ne sais pas ce que c’est que la technique de « misprediction". Je connais, 
pour ma part, ce qu’est l’exécution spéculative et celle-ci est _fondamentale_ 
dans les performances actuelles des processeurs à long pipeline et exécution en 
parallèle dans le désordre.

Le pipeline du Cortex-M15 de l’ARM, par exemple, compte 15 étages et permet 
d’exécuter 3 instructions en parallèle par cycle au maximum. Il peut en théorie 
traiter simultanément jusqu’à 59 instructions à différentes étapes de leur 
exécution. Voici un morceau de code que je viens d’extraire d’un de mes 
programmes en ligne de commande que j’utilise régulièrement (ce n’est _pas_ du 
benchmark):

3e958: sub     sp, #16
3e95a: str.w   lr, [sp, #12]
3e95e: ldr     r4, [r1, #20]
3e960: cmp     r0, r4
3e962: bne.n   3e96e
3e964: ldr.w   lr, [sp, #12]
3e968: movs    r0, #1
3e96a: add     sp, #16
3e96c: bx      lr
3e96e: ldr     r2, [r1, #12]
3e970: movs    r7, #1
3e972: ldr.w   r5, [r2, #-4]
3e976: asrs    r3, r0, #1
3e978: lsrs    r6, r5, #10
3e97a: rsb     ip, r7, r6, lsl #2
3e97e: adds.w  r4, r2, ip
3e982: ldrb    r4, [r4, #0]
3e984: movs    r5, #1
3e986: subs.w  r4, ip, r4
3e98a: cmp     r4, r3
3e98c: bls.n   3e9c0

Il y a trois branchements (adresses 3e962, 3e96c et 3e98c) sur les 21 lignes de 
code (14% de branchements). Si l’on ne fait aucune prédiction de branchement, 
on peut faire passer en moyenne 6 instructions dans le pipeline avant de 
bloquer pendant 14 cycles (5 étages fetch, 7 dispatch, 1 issue et 2 execution) 
avant de savoir si le saut est pris ou pas ou d’avoir la valeur du link 
register. C’est donc 14 cycles d’attente pour 2 à 6 cycles d’exécution (en 
fonction du parallélisme possible des unité d’exécution). Cela veut dire que le 
processeur ne fait rien entre 14/20 et 14/16 de son temps soit, respectivement, 
entre 70% et 87% de son temps !

En n’utilisant aucune prédiction intelligente (sans BTB, BHB, etc.) et en se 
contentant de faire de l’exécution spéculative avec du pris systématique ou du 
pas pris systématique, on va considérablement augmenter la performance rien 
qu’en se basant sur les boucles qui sont présentes dans le code (for, do, 
while, etc): plusieurs tours avec une prédiction correcte et une sortie sur une 
prédiction fausse. C’était le principe utilisé dans le premier Pentium. Rien 
qu’en faisant juste 50% de son temps sur le code ci-dessus (on a bien entendu 
pas de solution pour le branchement indirect au link register de l’adresse 
3e96c), on passe à 50% et, respectivement, 63% de slots de traitements du 
processeurs non utilisés ou à jeter en raison de la mauvaise prédiction. 
Imaginez l’ajout d'un BHT (branch history buffer) et d'un BTB (branch target 
buffer) donnant plus de 90% de prédictions correctes, ce que montrent la 
plupart des articles sur du code standard, et vous comprendrez pourquoi ne pas 
faire de prédiction c’est diviser par 3 ou 4 les performances d’un CPU. 

C’est simple, les pipelines sont tellement longs et larges que les sauts, même 
en petites quantités, viennent tout le temps bloquer le pipeline en forçant le 
passage de bulles (instructions qui ne font rien) à faire progresser dans le 
pipeline dans l’attente d’un résultat de comparaison ou de calcul. Si l’on a 5% 
de sauts dans du code, c’est 3 instructions de saut en moyenne dans le pipeline 
d'un Cortex-M15. Si l’on en a 14%, comme dans mon exemple ci-dessus, c’est 8 
instructions de saut en moyenne. Sans spéculation, vous pouvez enlever la boîte 
6 vitesses de votre Ferrari et la remplacer par une vitesse unique (la 
première) et ne jamais pousser l’accélérateur au max.


Dom


_______________________________________________
gull mailing list
[email protected]
http://forum.linux-gull.ch/mailman/listinfo/gull

Répondre à