Les meilleures voies d’optimisation
By   |  February 26, 2013

Développer en parallèle – Les meilleures voies d’optimisation

La petite liste qui suit compile les techniques les plus efficaces pour optimiser un code source dans une optique de parallélisation massive. Chacune de ces interventions peut être considérée comme ponctuelle, mais leur addition prouve son efficacité dans quasiment tous les contextes. Notez que ces conseils, présentés ici pour une première prise en mains de Xeon Phi, s’appliquent tout autant aux accélérations GPU…

• Evitez les aller-retours entre mémoire cache et mémoire centrale en ne travaillant que sur des blocs de données dimensionnés à la taille du cache local, soit 512 Ko par cœur (technique dite “cache blocking”).

• Partitionnez vos boucles en sous-blocs pour que les données utilisées à un instant T restent dans le cache jusqu’à leur réutilisation (technique dite “loop tiling”).

• Pour les boucles imbriquées, attention à l’ordre d’imbrication. Il faut savoir que C stocke consécutivement les éléments d’une même rangée de tableau (a[1,1], a[1,2]…), alors qu’en Fortran, ce sont les éléments d’une même colonne de tableau qui sont stockés consécutivement (a[1,1], a[2, 1]…). Ainsi, en fonction du langage utilisé et des instructions à exécuter, l’ordre dans lequel les boucles sont imbriquées détermine le fait qu’on reste en mémoire cache ou non.

• Consommez les données des boucles imbriquées dès qu’elles sont produites. L’alignement des boucles augmente de façon importante la probabilité que les données à consommer soient encore dans les niveaux les plus hauts de la hiérarchie mémoire. Même si elle conduit à un code plus complexe, cette approche est généralement assez rentable.

• Profitez des tampons de prefetch présents dans la GDDR de tous les accélérateurs en accédant aux données en mémoire de façon séquentielle. Pour cela, veillez à ce que les données à lire soient rigoureusement adjacentes et surtout qu’aucun accès mémoire concurrent à une autre adresse ne vienne perturber ce bel ordonnancement.

• Limitez au maximum les instructions de contrôle de boucle (test de fin, arithmétique de pointeurs) car elles s’exécutent à chaque itération. Ainsi, la parallélisation sera généralement native. Pour cela, n’hésitez pas à répéter les instructions en en limitant la portée, même si cela doit augmenter la taille du source (technique dite “loop unwinding”).

• Alignez les vecteurs de telle sorte que l’offset entre éléments de tableaux soit de même taille en bits que celle des éléments eux-mêmes (vecteurs dits “unit-stride”). En d’autres termes, évitez que des données intermédiaires ou des bits de padding correspondant à la largeur des instructions machine ne cassent cette symétrie (c’est souvent le cas avec des langages comme C et C++). En effet, dans leur immense majorité, les moteurs de vectorisation sont plus efficaces sur des vecteurs alignés. Pour cela, n’hésitez pas à restructurer de vos données en utilisant notamment les tableaux de structures et les structures de tableaux.

• Evitez autant que possible les vecteurs partiels. Pour cela, comme indiqué au point précédent, les transformations de données sont précieuses… et efficaces !

© HPC Today 2024 - All rights reserved.

Thank you for reading HPC Today.

Express poll

Do you use multi-screen
visualization technologies?

Industry news

Brands / Products index