Qu'est-ce que Déroulage de boucle (loop unrolling) ?
Optimisation qui recopie plusieurs fois le corps d'une boucle pour réduire le nombre d'itérations. Elle diminue le coût des branchements et des tests de compteur et facilite le réordonnancement des instructions, mais augmente la taille du code.
Nom japonais: ループ展開
« Déroulage de boucle (loop unrolling) » apparaît dans 5 questions d'entraînement réparties sur 2 thèmes, dont Compilateurs, Hiérarchie mémoire.
Domaine: Compilateurs
Ce que le déroulage fait à une boucle
Une boucle qui additionne deux tableaux élément par élément effectue normalement, pour chaque élément, une incrémentation de compteur, une comparaison et un branchement conditionnel en plus du travail utile. Dérouler d'un facteur quatre écrit le corps quatre fois, traitant les éléments i à i+3 en un passage et incrémentant i de 4 : la boucle exécute quatre fois moins d'itérations et le surcoût n'est payé qu'une fois pour quatre éléments. Lorsque le nombre d'itérations n'est pas un multiple du facteur de déroulage, une courte boucle de reste traite les éléments restants. Les petites boucles dont le nombre d'itérations est une constante connue peuvent être entièrement déroulées.
Pourquoi il accélère le code
Outre la réduction du surcoût des branchements et du compteur, le déroulage place plusieurs copies indépendantes du travail dans un même bloc de base, ce qui donne à l'ordonnanceur d'instructions du compilateur la liberté de les entrelacer. Un chargement d'une copie peut être lancé pendant que l'arithmétique d'une autre progresse, masquant les latences. Pour les réductions comme les sommes, dérouler avec plusieurs accumulateurs séparés brise une longue chaîne de dépendances unique ; en virgule flottante, cela modifie l'ordre des arrondis, si bien que les compilateurs ne le font que si c'est autorisé. Le déroulage fait aussi apparaître des groupes d'opérations pouvant être combinés en instructions vectorielles SIMD.
Coûts et rendements décroissants
Chaque copie supplémentaire agrandit le code, ce qui peut faire sortir des boucles critiques du cache d'instructions, et un plus grand nombre de valeurs simultanées accroît la pression sur les registres, pouvant forcer des débordements en mémoire (spills) qui annulent le gain. Les processeurs modernes à exécution dans le désordre, dotés d'une prédiction de branchement précise, masquent déjà une grande partie du surcoût de boucle ; un déroulage poussé apporte donc souvent peu. Les compilateurs choisissent par conséquent les facteurs de déroulage de façon heuristique, et les programmeurs peuvent demander un comportement précis par des options de compilation ou des pragmas lorsque les mesures le justifient.
Questions fréquentes
Qu'est-ce que le déroulage de boucle ?
Le déroulage de boucle est une optimisation, réalisée par le compilateur ou à la main, qui recopie plusieurs fois le corps de la boucle et réduit d'autant le nombre d'itérations, diminuant les mises à jour du compteur et les branchements et exposant davantage d'instructions à l'ordonnancement.
Le déroulage de boucle améliore-t-il toujours les performances ?
Non. Il augmente la taille du code et l'utilisation des registres, ce qui peut provoquer des défauts du cache d'instructions ou des débordements de registres ; et sur les CPU modernes, le surcoût de boucle restant est souvent faible : le bénéfice doit donc être mesuré.
Quelle est la différence entre le déroulage de boucle et le pavage de boucle ?
Le déroulage recopie le corps de la boucle pour réduire le surcoût des branchements et augmenter le parallélisme d'instructions. Le pavage découpe l'espace d'itération en blocs de la taille du cache pour améliorer la réutilisation des données et réduire les défauts de cache.