Ce répertoire présente une étude approfondie en calcul haute performance (HPC) portant sur l'optimisation incrémentale d'un noyau mathématique en langage C intensif en fonctions trigonométriques.
Les mesures de performances ont été réalisées dans l'environnement suivant :
- Processeur : AMD Ryzen 7 3700U (Zen+, Famille 23, Modèle 24, x86_64)
- Fréquence / Gouverneur : 2.30 GHz (acpi-cpufreq, performance)
- Système : Ubuntu (Linux noyau 6.17.0-14-generic, exécution native)
- Compilateur : gcc 13.3.0
- Analyseur de Performance : MAQAO 2026.0.0.b
Pour isoler les performances matérielles au niveau des différents niveaux de cache, la taille de la matrice a[n][n] et b[n], l'empreinte mémoire totale est de
Les tailles
-
Cache L1d (32 KiB) :
$n = 85$ -
Cache L2 (512 KiB) :
$n = 350$ -
Cache L3 (4096 KiB) :
$n = 800$
Les métriques soulignent que l'exécution se stabilise à partir de la 4ème itération d'échauffement cache. Par mesure de fiabilité, l'échauffement a été fixé à 15 répétitions.
Le code d'origine (NOOPT) passe l'immense majorité de son temps d'exécution limité par la vitesse des fonctions trigonométriques, avec un score de vectorisation MAQAO s'élevant à un modeste 37.5 % avec le flag -O2. Voici l'évolution algorithmique pour contrecarrer ces goulots :
Dans la version originale, la boucle interne faisait varier i, causant des défauts de cache (memory misses) dus au fait que l'accès à un tableau a[i][j] n'est pas contigu.
- Transformation : La boucle
ja été déplacée en interne pour y effectuer des accès séquentiels. - Résultat : L'efficacité d'accès aux cases de tableaux a bondi de 87,7 % à 100 %.
Les calculs à base de b[i] étaient redondants pour chaque itération de la boucle interne j.
- Transformation : Précalcul des fonctions trigonométriques sur
b[i]hors de la boucle interne. Remplacement des calculs de précision doublesin/cos/tanpar leurs équivalents en 32 bitssinf/cosf/tanf. - Résultat : Le temps perdu dans l'appel à la bibliothèque
math.ha été diminué de 4 %. Par ailleurs, la manipulation du 32 bits peut optimiser l'utilisation des registres vectoriels (8 floats par registre 256-bits).
Le modulo (i % 4) utilisé pour les règles trigonométriques ne dépend pas de j. Il bloquait les optimisations de branchement depuis l'intérieur du noyau.
- Transformation : Séparation des conditions hors de la boucle, puis déroulage explicite de la boucle interne
jpar des pas de 4 pour offrir plus de granularité au pipeline. - Résultat : Les tests de fin de boucle et les incréments de
jayant dramatiquement diminué, le temps accumulé dans les boucles externes fut réduit de moitié !
Même avec de l'Unrolling, la boucle j nécessitait encore de recalculer b[j] localement.
- Transformation : Allocation dynamique globale (
malloc) de tableaux retenant préventivementsinf(b),tanf(b),1/cosf(b)et1/tanf(b). La boucle imbriquée ne réalise alors strictement plus aucun appel de trigonométrie, uniquement des multiplications et affectations mémoire rapides. - Résultat flag
-O3: L'efficience est foudroyante. Combinée aux flags puissants (-ffast-math -O3 -march=native -funroll-loops), la boucle interne a atteint un ratio de vectorisation exclusif de 100 %. Le ratio de temps passé dans les appels lents demath.hdevient désormais complètement négligeable dans les rapports MAQAO Profiler.
Une version OPT5 (théorisée) est incluse pouvant inclure des directives <omp.h> : #pragma omp parallel for private(i, j). Sur des grandes matrices (exemple
Le passage de NOOPT à des structures avancées a débloqué tout le potentiel sous-jacent de gcc :
- Stabilisation du flux mémoire (OPT1).
- Allégement des registres (OPT2).
- Restructuration algorithmique radicale de la charge de calcul (OPT4).
Couplé à MAQAO, ce projet illustre finement comment compiler intelligemment (de
-O2à-O3 -march=native) pour sublimer du code et exploiter formellement le multicoeur.
Note : La documentation détaillée du compilateur n'est pas l'objectif. Le Makefile est auto-porteur.
Pour compiler la version visée :
# Remplacer OPT4 par l'optimisation souhaitée (NOOPT, OPT1, OPT2, OPT3, OPT4)
make OPT=OPT4Analyses :
./calibrate <val_n> <repetitions_max> # Calcule le warmup
./measure <val_n> <warmups> <run_count>
maqao oneview -R1 -- ./measure <val_n> <warmups> <run_count> # Trace MAQAOLes drivers sont codés par Emmanuel Oseret, qui a également encadré le projet avec Kévin Camus.