Le projet DawnCC a pour objectif d’ajouter les instructions OpenACC ou OpenMP nécessaires pour que cette parallélisation soit effectuée. Le code source original est ainsi conservé, mais annoté aux endroits où cela est possible. DawnCC ne se focalise pas sur la performance du code ainsi produit, mais bien sur sa correction. Pour ce faire, l’outil se base sur LLVM, qui propose une représentation du code en cours de compilation (une représentation intermédiaire, IR) et différentes passes d’analyse, notamment pour détecter les dépendances en mémoire pour une série de lignes de code.
En visant OpenACC et OpenMP, le projet permet d’aller encore plus loin qu’une “simple” parallélisation sur les différents cœurs d’un processeur : ces normes définissent aussi des structures pour décharger l’exécution du code sur des accélérateurs, notamment des processeurs graphiques (GPU). Elles facilitent énormément le travail par rapport à l’implémentation manuelle avec CUDA ou OpenCL, mais ce processus reste fastidieux et le risque d’erreur est élevé. Par rapport à des annotations pour plusieurs cœurs, il faut indiquer explicitement les parties de la mémoire à transférer sur l’accélérateur, ce qui n’est pas trivial. DawnCC s’occupe de calculer précisément les parties nécessaires, à l’aide d’analyse statique du code source.
Sur le site officiel du projet, il est possible d’exécuter DawnCC sur des fonctions en C ou en C++, voire des fichiers complets. Par exemple, cette fonction incrémente le contenu d’un tableau, mais jusqu’à un indice qui dépend de l’argument passé à la fonction.
Code c : | Sélectionner tout |
1 2 3 4 5 6 7 | void func(int a) { int n[100]; int i; for (i = 0; i < a; i++) { n[i+1] = n[i+1] + 1; } } |
La version OpenMP possède une annotation au niveau de la boucle for pour en demander la parallélisation au compilateur, mais aussi une autre annotation pour indiquer quelles parties de la mémoire doivent être transférées sur l’accélérateur — en fonction de la valeur du paramètre.
Code c : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void func(int a) { int n[100]; int i; long long int AI1[8]; AI1[0] = a + -1; AI1[1] = 4 * AI1[0]; AI1[2] = 4 + AI1[1]; AI1[3] = AI1[2] + 4; AI1[4] = AI1[3] / 4; AI1[5] = (AI1[4] > 0); AI1[6] = (AI1[5] ? AI1[4] : 0); AI1[7] = AI1[6] - 1; #pragma omp target data map(tofrom: n[1:AI1[7]]) #pragma omp target for (i = 0; i < a; i++) { n[i + 1] = n[i + 1] + 1; } } |
Source : [llvm-dev] Automatic Insertion of OpenACC/OpenMP directives.
Voir aussi : le dépôt GitHub du projet, Automatic Insertion of Copy Annotation in Data-Parallel Programs, DawnCC: a Source-to-Source Automatic Parallelizer of C and C++ Programs.