Les enjeux du parallélisme

Introduction

Du mono-coeur au multi-cœurs, quels gains ?

Les fondeurs estiment qu’en restant sur l’architecture mono-cœur, la dissipation thermique aurait atteint en 2015-2020 la chaleur dégagée à la surface du soleil, soit 6000° C ! La course au MHz entraîne également une course à la consommation. De source Intel, si on augmente la fréquence du processeur de 20%, on augmente en moyenne les performances de 13%, mais la consommation augmente de 73%. En revanche, si l’on diminue la fréquence de 20%, on diminue la performance de 13% et la consommation diminue de 49%. Partant de ce constat, si l’on garde une fréquence à 80% de la fréquence d’origine et que l’on ajoute un second cœur à la même fréquence, on augmente les performances de 73% et la consommation n’augmente que de 2% !

S’il est un domaine où le logiciel accuse un retard par rapport au matériel, c’est bien le parallélisme. Alors que les machines multi-cœurs et multi-processeurs se généralisent, rares sont les applications capables d’exploiter cette montée en puissance. Pourtant les langages et les outils existent, mais la programmation parallèle reste une affaire de spécialistes.

Depuis l’origine de l’informatique, l’amélioration des performances des ordinateurs s’est faite en augmentant la fréquence des processeurs. Basé sur l’architecture de von Neumann, ce modèle à traitement séquentiel montre aujourd’hui des limites physiques que sont la chaleur dissipée et la consommation. Pour palier à ces limitations, on peut disposer plusieurs cœurs dans un même processeur (mutli-core computing), plusieurs processeurs sur la même carte-mère (symmetric multiprocessing, SMP), plusieurs cartes mères dans le même boîtier ou plusieurs ordinateurs en réseau (distributed computing, massive parallel processing, grid computing). Nous nous intéresserons ici à la première catégorie.

On voit depuis quelques années se généraliser les ordinateurs à processeurs multi-cœurs, du PC de bureau au portable, et bientôt les PDA. Mais les logiciels sont-ils capables d’exploiter automatiquement ce surcroît de puissance ? La réponse, comme vous le savez vous qui lisez nos comparatifs, est clairement non pour une bonne partie d’entre eux. La plupart des programmes sont encore écrit de manière séquentielle. Un algorithme de calcul, s’il n’a pas été conçu pour profiter de plusieurs cœurs,  consommera donc au mieux 50 % du CPU d’un dual-core, 25 % d’un quad-core, 12 % d’un octo-core, etc. Un vrai gâchis !

Une complexité plus grande

Concevoir des programmes exploitant les architectures multi-cœurs, c’est évidemment l’enjeu de la programmation parallèle. Pourtant, c’est un concept qui n’est pas nouveau, il est au cœur des préoccupations scientifiques depuis près de trente ans, mais réservé à des experts et à une minorité d’applications nécessitant des calculs intensifs sur des masses de données très importantes. Sous Windows, le concept de programmation multi-threads a été introduit en 1995 avec Windows 95, mais les concepts inhérents à ce mode de programmation restent encore difficiles à maîtriser, même aujourd’hui avec la plate-forme .NET. Les langages objets classiques tels que Java ou C++ n’ont pas été conçus à la base pour le parallélisme et la moindre problématique parallèle, comme par exemple éclater l’exécution d’un boucle sur plusieurs coeurs, reste un vrai casse-tête à développer et surtout à tester.

Image 1 : Les enjeux du parallélisme

Image 2 : Les enjeux du parallélisme

Jusqu’à présent, même un programme linéaire mal écrit pouvait bénéficier de l’augmentation de fréquence du processeur et tourner plus vite. Demain, un programme parallèle mal conçu ne tournera pas plus vite avec l’augmentation des cœurs, il ne sera pas « scalable ». Dans l’histoire de la programmation, nous sommes à un point d’inflexion, un tournant critique. Les développeurs doivent changer leur manière d’écrire des logiciels pour s’adapter à l’évolution du matériel.

Les défis à relever, Multithreading et parallélisme

Image 3 : Les enjeux du parallélismeAujourd’hui, les conditions sont encore difficiles. La situation économique fait privilégier la rentabilité et la valeur métier des applications avant leur performance ou leur capacité à monter en charge. La programmation parallèle reste une affaire de spécialistes. Les compétences sont rares et les écoles ne forment pas encore à ce genre de programmation. Les écueils et les problèmes potentiels sont nombreux. Par exemple, les situations de compétition (race conditions) surviennent quand le résultat d’un processus est dépendant de la séquence ou du timing des événements de ce processus. L’interblocage (deadlock), appelé encore étreinte fatale est une situation catastrophique où deux threads concurrents s’attendent mutuellement et restent bloqués indéfiniment. Ce sont des erreurs très difficiles à reproduire. Citons également les livelocks (famines), lock convoys, cache coherency overheads… Au final, il n’y a pas de moyen simple pour les développeurs non spécialistes d’écrire et de tester des programmes parallèles.

Selon le cabinet d’analyse Evans Data, une étude sur les habitudes des développeurs mondiaux montre que sur le dernier semestre 2008, seulement 3 % des développeurs auraient introduit dans leur code des instructions capables de gérer le parallélisme des multi-cœurs.  

La programmation parallèle est sans conteste un des grands défis technologiques de l’informatique pour les années à venir. C’est également une formidable opportunité pour se différencier. Des langages et des outils adaptés, des standards commencent à émerger.

Multithreading et parallélisme

Image 4 : Les enjeux du parallélismePour faire du parallélisme, on peut utiliser la technique du multithread. Les threads sont des unités de traitement d’un processus qui peuvent s’exécuter en parallèle et qui partagent au sein d’un processus la même mémoire virtuelle. C’est l’OS qui se charge de répartir les différents threads entre les cœurs. Mais outre qu’il faille mettre en place des mécanismes de synchronisation via des sémaphores, ce n’est pas toujours la solution idéale. Si l’on a à faire à une tâche lourde, une grosse boucle de traitement de morphing d’image par exemple, cela devient tout à fait inefficace de la découper en threads. En règle générale, on déconseille d’utiliser les threads pour faire du parallélisme. Edward A. Lee, professeur à Berkeley avec ses 25 ans de programmation parallèle derrière lui, déclare : « Les logiciels non triviaux écrits avec des threads, des sémaphores et des mutex sont incompréhensibles par les êtres humains et on ne peut ni ne doit leur faire confiance ».

La programmation parallèle nécessite de revoir sa manière de programmer, selon de nouveaux principes : décomposition des tâches, des données et des flux de données. Elle nécessite également de nouveaux patrons de conception : parallélisme au niveau de la tâche, Divide-and-Conquer, décomposition géométrique, pipeline, wavefront… A cela s’ajoutent les contraintes de synchronisation, de communication, de répartition de charge, de « scalabilité ».

Pour programmer parallèle avec les langages courants, il existe de nombreuses bibliothèques et frameworks : POSIX Threads, OpenMP, Message Passing Interface

La prochaine version du langage C++, baptisée provisoirement C++0x améliore la gestion du multitâche et des threads à la fois dans la spécification du langage et dans la bibliothèque standard. C++0x devrait être ratifié cette année (C++09).

On trouvera également des langages dédiés qui prennent en charge nativement le parallélisme tel que Erlang, Occam, voire Scala.

Quelques exemples

Tout cela semble encore très compliqué, mais les éditeurs commencent à proposer des outils et des solutions pour simplifier la programmation parallèle. Ainsi Microsoft proposera dans la future version de Visual Studio 2010 le langage PLINQ (Parallel LINQ) dérivé du langage de requête LINQ.

Une requête LINQ comme :

var result = from c in liste where c.champ==5 orderby c.autreChamp select c; // version simple

devient en PLINQ :

var result = from c in liste.AsParallel() where c.champ==5 orderby c.autreChamp select c; // parallélisée

Et c’est tout ! D’un seul coup la requête devient parallèle et s’exécutera sur tous les cœurs disponibles à la fois, la tâche est découpée, les  threads sont créés ainsi que tout le reste, de façon automatique par PLINQ.

Microsoft intégrera également la bibliothèque TPL (Tasks Parallel Library) permettant d’exprimer du parallélisme directement en C# ou VB.NET, par exemple avec les instructions de boucle For et Foreach. Avec Visual Studio 2010, Microsoft proposera un environnement complet avec un modèle de programmation, une plate-forme et des outils pour développer des applications parallélisées.

Image 5 : Les enjeux du parallélisme

Intel, qui est aussi éditeur de logiciel, fournit une gamme complète d’outils pour la conception, le développement, la vérification et l’optimisation des programmes parallèles (HPC products). Il vient d’annoncer Intel Parallel Studio, un atelier complet pour C/C++ qui s’intègre dans Visual Studio.

Image 6 : Les enjeux du parallélisme

Image 7 : Les enjeux du parallélisme

Grâce à ces nouveaux outils, la programmation parallèle devient accessible à tous et entre peut-être enfin dans une nouvelle ère. Pour tous les logiciels qui nécessitent de la puissance de calcul (graphismes, vidéos, jeux, finances…), le parallélisme est clairement le futur de la programmation et ceux qui auront loupé le coche risquent de rester sur le bord de la route.

Pour les applications en ligne qui nécessitent de fortes montées en charge en termes d’accès simultanés ou de stockage de données, un nouveau paradigme est en train d’émerger avec son extraordinaire extensibilité mais également ses contraintes de programmation : le Cloud Computing.

Références :

Introduction to Parallel Computing

Liste des langages pour la programmation parallèle :

  • http://wotug.kent.ac.uk/parallel/languages/