TP-OpenMP Page 1 of 2 Objectifs du TP : Les processeurs d'aujourd'hui sont tous "multi-coeurs", et certaines architectures possèdent plusieurs centaines de processeurs coopérant à travers une mémoire partagée. La programmation "multithreads" est une bonne façon d'exploiter le parallélisme de ces architectures, et OpenMP est un formalisme simple et souvent efficace pour mettre en oeuvre le "multithreading" (bien qu'il existe maintenant des bibliothèques de multithreading optimisées pour les architectures multi-coeurs). Ce TP a pour objectif d'apréhender par la pratique les principaux aspects d'openmp, notamment la parallélisation des boucles de calculs, qui constitue sont attrait principal. Les développements et expérimentations se feront sur des machines quadri-coeurs. Plates-formes de développement et de test : A partir de la version 2005 de VisualStudio et du compilateur C/C++ de Microsoft, VisualStudio intègre la norme OpenMP. La version 4.1.2 de gcc en Fedora 5 ou plus, supporte OpenMP. Les développements pourront donc se faire en Windows/VisualStudio 2005 ou plus, et en Linux/gcc 4.1.2 ou plus sur des PC multi-coeurs. Les squelettes de programmes à compléter accompagnant les énoncés sont compilables autant sous Windows que sous Linux. Vous pouvez donc choisir votre environnement de développement favori. Documents à rendre (selon la formation) : Vous rendrez un SEUL document par personne ou par binôme : un fichier Word (.doc) ou PDF : il sera nommé avec vos noms précédés de "TP-OpenMP". Ex : "TP-OpenMP- Martin-Dupont.pdf" il comportera sur la première page : vos nom et prénoms, et le nom de votre option de 3A, la date de remise du rapport, le titre (""). il comportera ensuite : pour chaque étape : une description de la parallélisation réalisée (pourquoi? comment?), vos mesures de performances (Texec, MegaFlops, SpeedUp) sur PC quadri-coeurs, des graphiques de synthèse représentant les performances fonction du nombre de
TP-OpenMP Page 2 of 2 threads créés et éventuellement de la taille du problème, votre analyse/synthèse des performances obtenues, en annexe : les codes sources des parties importantes du code à chaque étape (ex : les portions parallélisées). Date limite de remise de vos rapports : xxxxx.. Remise par e-mail à S. Vialle (Stephane.Vialle@supelec.fr) Travail à effectuer : Remarques préliminaires : OpenMP permet de réaliser une parallélisation incrémentale d'un code séquentiel. Afin de cumuler toutes les sources de performance on partira toujours d'un code séquentiel optimisé au maximum". Les codes de calcul de ce TP seront évalués par leurs temps d'exécution des principales boucles de calculs, dont on déduira les MegaFlops (performances absolues), puis par leurs accélérations vis-à-vis de la version séquentielle optimisée (performances relatives). Exercices : 1. Parallélisation d'une relaxation de Jacobi : Enoncé. 2. Parallélisation d'un produit matriciel : Enoncé. 3. Si le temps le permet traitez la parallélisation d'une suite de calculs matricels : Enoncé. 4. Synthèse et analyse globales des résultats : quelles leçons tirez-vous de l'exploitation d'un PC multi-coeurs?
TP-OpenMP-RelaxationJacobi Page 1 of 3 Exercice 1 : Parallélisation d'une relaxation de jacobi L'utilisation d'openmp dans un code C nécessite en général d'inclure le fichier omp.h : #include <omp.h>, puis d'utiliser la bibliothèque OpenMP lors de l'édition de liens, et d'utiliser un compilateur OpenMP. Dans le cas d'un projet VisualStudio en mode "Console-Win32" il est nécessaire de préciser de prendre en compte les directives de compilation OpenMP et de générer du code "Release" et "Multithread", par une modification des "propriétés du projet Visualstudio". Dans le cas de gcc sous Linux, il est nécessaire de compiler avec l'option "-fopenmp". Dans tous les cas on veille aussi à préciser au compilateur d'optimiser la génération de code en vitesse! Dans cet exercice : Un squelette de programme C est fourni. C'est un répertoire contenant un projet VisualStudio "Console-Win32" où tous les propriétés du projet ont été positionnées correctement, et où un "Makefile" permet aussi une compilation OpenMP sous Linux avec gcc 1.4.2. Il ne vous reste plus qu'à développer le code C en insérant des directives et fonctions OpenMP avec votre environnement préféré.. Utilisez le squelette de programme C-OpenMP pour Windows ou Linux fourni pour ce TP : Enonce-omp-src-jacobi.zip 1 - Prise en main et affichage du numéro de thread et du nombre de threads Le programme de l'énoncé contient plusieurs affichages d'un message avec le numéro du thread et le nombre de threads lancés, par appel aux routines omp_get_thread_num() et omp_get_num_threads(). Ce programme permet aussi de préciser sur la ligne de commande le nombre de threads à utiliser (par l'option "-nt #value"). Ce nombre de threads est alors imposé à OpenMP par la fonction omp_set_num_threads() (voir le code). Faites varier le nombre de threads sur la ligne de commande et observez l'évolution de l'affichage. En l'absence de régions parallèles observez-vous un ou plusieurs threads? 2 - Parallélisation de la boucle de relaxation, recherche de la solution la plus rapide. Plusieurs solutions permettent de paralléliser le code séquentiel fourni, avec des efficacités différentes. 1. Quelle boucle for est-elle la plus intéressante à paralléliser?
TP-OpenMP-RelaxationJacobi Page 2 of 3 2. Réalisez une parallélisation d'une grille de 256x256 points utiles pendant 50000 cycles, à partir d'une directive orpheline. Exécuter votre code en imposant différents nombres de threads et vérifiez l'exactitude du résultat obtenu (potentiel affiché du centre de la grille de relaxation). Les résultats corrects sont récapitulés au bas de cette page. 3. Réalisez une parallélisation à partir d'une région parallèle définissant une variable OI et une variable NI propre à chaque thread et intialisées dans la région parallèle. Insérez l'instruction d'affichage du message "c" au début de la région parallèle. Vérifiez que le message "c" s'affiche plusieurs fois et vérifiez l'exactitude du résultat. 4. Réalisez une parallélisation à partir d'une région parallèle définissant une variable OI et une variable NI propre à chaque thread, mais initialisées avant le début de la région parallèle. Vérifiez l'exactitude du résultat. 5. Réalisez une parallélisation à partir d'une région parallèle évitant toujours de créer et détruire des threads à chaque cycle, mais laissant les variables OI et NI "shared". Vérifiez l'exactitude du résultat. Quelle parallélisation vous semble la plus intéressante? Remarque : Vous pouvez tester vos parallélisations avec d'autres couples taille/nombre-decyles dont les résultats sont donnés dans le tableau au bas de cette page. 3 - Mesures de performances calculatoires et énergétiques sur PC quadri-coeurs Cette question a pour but de réaliser une rapide étude de performances en fonction du nombre de threads créés et de la taille du problème. 1. Calculez la taille totale du tableau des potentiels en fonction de la taille de la variable "SIZE" du code source. Quelles tailles de la grille de Jacobi mènent à une implantation qui tient dans le cache? 2. Mesurez les performances de votre parallélisation pour 1, 2, 3, 4 et 8 threads sur un des PC quadri-coeurs, pour des grilles de 256x256, 384x384, 512x512 et 1024x1024 points utiles (soit 20 mesures à effectuer au total), et pour la meilleure parallélisation identifiée à la question précédente. Diminuer le nombre de cycles quand vous augmentez la taille du problème, afin de conserver des temps d'exécution proche de 1 minute. Dans chaque cas : mesurez les performances obtenues (MFlops), mesurez le temps d'exécution du programme et déduisez le temps d'exécution d'un cycle de calcul, mesurez le nombre de Watts consommés par l'exécution du programme, et déduisez l'énergie absorbée (nbr de Joules) par l'exécution d'un cycle de calcul. 3. Pour chaque taille de problème, quelles performances et accélérations maximales obtenez vous, et pour quel nombre de threads? Expliquez les différences de performances observées en fonction de la taille du problème. 4. Calculez et tracez les accélérations obtenues en fonction du nombre de threads déployés et leurs efficacités vis-à-vis du nombre de coeurs utilisés. On prendra comme référence séquentielle l'exécution du même code avec un seul thread. 5. Calculez et tracez également les gains d'énergie obtenus en déployant de plus en plus de threads. 6. Tracez le produit de l'accélération par le gain d'énergie (sorte d'intérêt global du multithreading sur multi-coeurs), en fonction du nombre de threads déployés et pour
TP-OpenMP-RelaxationJacobi Page 3 of 3 chaque taille de problème. Analysez ces résultats, et concluez sur l'utilisation de ces PC multi-coeurs. 4 - Résultats corrects attendus. Taille "utile" de la grille de relaxation (SIZExSIZE) Nombre de cycles de relaxation Potentiel au centre de la Grille 64x64 500000 6,315464 96x96 50000 6,351585 128x128 50000 6,369809 256x256 50000 6,158332 384x384 5000 0,004151 512x512 5000 0,000011 1024x1024 500 0,000000
TP-OpenMP-ProduitMatriciel Page 1 of 1 Exercice 2 : Parallélisation d'un produit matriciel On considère deux matrices carrées A et B de SIZExSIZE éléments de type double, et on souhaite calculer leur produit : C = AxB. 1. Utilisez le squelette de programme fourni pour cet exercice, dont le projet a été configuré pour une compilation optimisée en vitesse et prenant en compte les directives OpenMP sous Windows et sous Linux : Enonce-omp-src-matrix.zip 2. Observez le code source de la routine de produit de matrices : il a été optimisé séquentiellement pour tirer partie de l'architecture des coeurs d'aujorud'hui. 3. Parallélisez ce code avec OpenMP, selon la stratégie qui vous semble la plus efficace. Mesurez les performances calculatoires et énergétiques pour des matrices de 1536x1536 (vérifiez l'exactitude des résultats) sur un PC quadri-coeurs, et pour des matrices de 4032x4032 si le temps le permet. 4. Tracez les courbes de performances et d'accélération en fonction du nombre de threads déployés, d'efficacité vis à vis du nombe de coeurs utilisés. 5. Tracez les courbes d'énergie consommée par l'ensemble du produit matriciel en fonction du nombre de threads déployés, et les courbes de gain énergétique (obtenez-vous des gains ou des pertes?). 6. Identifiez les meilleures solutions calculatoires et énergétiques pour chaque taille de problème. La solution la plus économique est-elle aussi la solution la plus rapide? Quelle allure a le produit de l'accélération par le gain énergétique? 7. Si vous travaillez sous Linux, vous pouvez recommencer l'étude sous icc (Intel C Compiler) : éditez le Makefile et changez le nom du compilateur (icc) et l'option d'utilisation d'openmp (en icc il faut utiliser -openmp). exécutez la commande 'source /opt/intel/cce/10.1.018/bin/iccvars.sh' pour être prêt à utiliser le compilateur icc, lancez vos tests à partir du terminal dans lequel vous avez exécuter la commande 'source'. Comparez alors les performances obtenues sous icc et sous gcc.
TP-OpenMP-CalculMatriciel Page 1 of 1 Exercice 3 : Parallélisation d'une suite de calculs matriciels On considère une matrice "A" carrée de SIZExSIZE éléments de type double, et une autre matrice "F" carrée de la même taille. "A" est une matrice de données et "F" est un "filtre" matriciel. 1. Implantez un programme réalisant une boucle de NbIter itérations, réalisant à chaque itération : A n+1 = A n xf (on applique le filtre récursivement à chaque itération). A la fin de chaque itération implantez le calcul de la valeur moyenne des éléments de la matrice A n+1. - Utilisez le squelette de programme fourni pour cet exercice (le même que pour l'exercice précédent), dont le code source à été optimisé séquentiellement et dont le projet a été configuré pour une compilation optimisée en vitesse et prenant en compte les directives OpenMP sous Windows et sous Linux: Enonce-omp-src-matrix.zip 2. Parallélisez ce code avec OpenMP, en utilisant principalement une directive orpheline et une clause de réduction. Tout au long du développement, vérifiez l'exactitude des résultats en prenant comme filtre la matrice identité et en initialisant la matrice A avec : A[i][j] = i*size+j. 3. Mesurez les performances calculatoires et énergétiques de votre code sur un PC quadri-coeurs, pour 1,2, 3, 4 et 8 threads, pour une valeur de SIZE susceptible de produire une hyper-accélération (justifiez votre choix de la valeur SIZE), puis pour des valeurs menant à un problème de taille inférieure au cache accessible à un seul coeur, et à un problème de taille supérieure à l'ensemble du cache du processeur. Les performances obtenues sont-elles cohérentes avec celles observées lors de la parallélisation de la relaxation de Jacobi? 4. Parallélisez votre code séquentiel avec OpenMP en définissant une région parallèle permettant de ne créer les threads qu'une seule fois. Attention, les clauses de réduction ne fonctionne pas à l'intérieur d'une région parallèle. Observez-vous une amélioration par rapport à la parallélisation par directive orpheline?