J'étais en train de parcourir un document qui parle des techniques d'optimisation du compilateur juste à temps (JIT) pour Java. L'un d'eux était "l'inversion de boucle". Et le document dit:
Vous remplacez une
while
boucle régulière par unedo-while
boucle. Et lado-while
boucle est définie dans uneif
clause. Ce remplacement entraîne deux sauts de moins.
Comment fonctionne l'inversion de boucle et comment optimise-t-elle notre chemin de code?
NB: Ce serait formidable si quelqu'un pouvait expliquer avec un exemple de code Java et comment JIT l'optimise en code natif et pourquoi est-il optimal dans les processeurs modernes.
java
jvm
jit
machine-instruction
En essayant
la source
la source
Réponses:
Flux de travail:
Flux de travail:
En comparant ces deux, vous pouvez facilement voir que ce dernier peut ne pas faire de sauts du tout, à condition qu'il y ait exactement un pas dans la boucle, et généralement le nombre de sauts sera inférieur d'un au nombre d'itérations. Le premier devra revenir en arrière pour vérifier la condition, seulement pour sauter hors de la boucle lorsque la condition est fausse.
Les sauts sur des architectures CPU modernes en pipeline peuvent être assez coûteux: comme le CPU termine l'exécution des vérifications avant le saut, les instructions au-delà de ce saut sont déjà au milieu du pipeline. Tout ce traitement doit être ignoré si la prédiction de branchement échoue. La poursuite de l'exécution est retardée pendant le réamorçage du pipeline.
Explication de la prédiction de branche mentionnée : pour chaque type de saut conditionnel, le CPU a deux instructions, chacune comprenant un pari sur le résultat. Par exemple, vous mettriez une instruction disant " sauter sinon zéro, parier sur pas zéro " à la fin d'une boucle car le saut devra être fait sur toutes les itérations sauf la dernière. De cette façon, le CPU commence à pomper son pipeline avec les instructions suivant la cible de saut au lieu de celles suivant l'instruction de saut elle-même.
Note importante
Veuillez ne pas prendre cela comme un exemple d'optimisation au niveau du code source. Ce serait totalement erroné car, comme cela ressort de votre question, la transformation de la première forme en la seconde est quelque chose que le compilateur JIT fait de façon routinière, complètement de lui-même.
la source
do-while
code source donné n'est pas pertinent, car nous n'écrivons pas réellement cela. Nous écrivons lawhile
boucle et laissons le compilateur et JIT conspirer pour l'améliorer pour nous (via l'inversion de boucle) si / si nécessaire.Cela peut optimiser une boucle qui est toujours exécutée au moins une fois.
Une
while
boucle régulière retournera alors toujours au début au moins une fois et sautera à la fin une fois à la fin. Un exemple de boucle simple exécutée une fois:Une
do-while
boucle en revanche sautera le premier et le dernier saut. Voici une boucle équivalente à celle ci-dessus, qui se déroulera sans sauts:la source
boolean b = true; while(b){ b = maybeTrue();}
àboolean b;do{ b = maybeTrue();}while(b);
devrait suffire.Parcourons-les:
La
while
version:n
et passons àdone();
si la condition n'est pas vraie.n
.done()
.La
do-while
version:(Rappelez-vous que nous ne faisons pas cela dans le code source [qui introduirait des problèmes de maintenance], le compilateur / JIT le fait pour nous.)
n
et passons àdone();
si la condition n'est pas vraie.n
.done()
.Ainsi, par exemple, si au
n
début9
, nous ne sautons jamais du tout dans lado-while
version, alors que dans lawhile
version, nous devons revenir au début, faire le test, puis revenir à la fin quand nous voyons que ce n'est pas vrai .la source
L'inversion de boucle est une technique d'optimisation des performances qui améliore les performances car le processeur peut obtenir le même résultat avec moins d'instructions. Cela devrait surtout améliorer les performances dans des conditions aux limites.
Ce lien fournit un autre exemple d'inversion de boucle. Dans quelques architectures où décrémenter et comparer est implémenté comme un jeu d'instructions unique, il est logique de convertir une boucle for en un moment avec une opération de décrémentation et de comparaison.
Wikipedia a un très bon exemple et je l'explique encore ici.
sera converti par le compilateur en
Comment cela se traduit-il par la performance? Lorsque la valeur de i est 99, le processeur n'a pas besoin d'effectuer un GOTO (ce qui est requis dans le premier cas). Cela améliore les performances.
la source