Bonjour,
Merci pour cette petite expérience. Je travaille pas mal sur l'optimisation de codes/parallélisation et je me méfie toujours de ce que fait le compilateur suite à de nombreuses déconvenues. Mes conclusions (en partie suite aux résultats dans ce papier https://hal.archives-ouvertes.fr/hal-01915529, je recommande le tableau page 8!) :
le compilateur n'apporte aucune garantie sur les optimisations : parfois avec -O2 c'est plus rapide qu'avec -O3, parfois c'est avec -Ofast, parfois avec un -march qui ne correspond pas à l'archi de la machine sur laquelle tourne le code, ...
le compilateur casse parfois les optimisations qu'on essaie de mettre en place -> assembleur...
l'autovectorisation ne vectorise pas des cas triviaux mais vectorise des cas complexes sans doute par identification de motifs et remplacement par du code optimisé (un peu comme la boucle for pour copier qui est remplacée par un memcpy), mais dès qu'on modifie un peu le motif, plus personne...
l'autovectorisation quand elle produit du code vectorisé ne garantit pas que le code vectorisé soit plus efficace, par exemple sur un traitement d'image, le code "vectorisé" va passer son temps à faire des instructions shuffle/unpack/permute pour réorganiser les données avant de faire quelques calculs puis refaire tout le chemin inverse et parfois c'est plus lent que du code scalaire... mais si on le fait correctement à la main avec des intrinsics on va 3x plus vite ! C'est ce qui a motivé la désactivation de la vecto pour AVX-512, le gain de perf dans de nombreux cas n'était pas suffisant pour contrecarrer la baisse de fréquence.
l'autovectorisation n'est pas portable entre architectures (je sais que ce ne sont pas les mêmes instructions mais le processus devrait être un peu indépendant de l'archi), le même compilo va arriver à vectoriser sur x86 en SSE, mais pas en NEON sur Arm, sans utiliser des instructions spécifiques.
sur Arm 32-bit j'ai eu une surprise avec une ancienne version de GCC : mes intrinsics étaient convertis en code scalaire mais ça allait 20-30% plus vite que le code scalaire parce que du coup la boucle était déroulée de 4 !
parfois l'ajout d'une directive #pragma omp simd bloque l'autovectorisation qui est pourtant faite avec juste -O3.
il y a des optimisations qui cassent si on ajoute une petite couche de templates, même juste en utilisant std::vector à la place d'un tableau à la C.
j'ai vu des personnes passer énormément de temps à modifier leur code et à espérer que le compilo daigne enfin vectoriser tout seul. Le code ne ressemble plus à rien, on peut espérer gagner 20%, alors qu'en passant par des intrinsics et avec la surcharge des opérateurs on peut vectoriser sans modifier la structure du code et on a un x2 à x5 suivant les archis.
# Les compilateurs et l'optimisation
Posté par sjub . En réponse au journal Recherche de valeur dans un tableau et l'écosystème des compilateurs C++. Évalué à 10.
Bonjour,
Merci pour cette petite expérience. Je travaille pas mal sur l'optimisation de codes/parallélisation et je me méfie toujours de ce que fait le compilateur suite à de nombreuses déconvenues. Mes conclusions (en partie suite aux résultats dans ce papier https://hal.archives-ouvertes.fr/hal-01915529, je recommande le tableau page 8!) :
Vivement que Facebook vienne révolutionner tout ça... ou pas ! https://ai.facebook.com/blog/compilergym-making-compiler-optimizations-accessible-to-all/