1 / 46

Les Modèles de Développement Parallèle pour développer efficacement

Les Modèles de Développement Parallèle pour développer efficacement. Code Session : TCP301. Bruno BOUCARD Architecte SGCIB Programmation Parallèle http://msmvps.com/blogs/brunoboucard Développement Parallèle http://blogs.msdn.com/devpara/default.aspx. Agenda. Introduction Modélisation

Download Presentation

Les Modèles de Développement Parallèle pour développer efficacement

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Les Modèles de Développement Parallèle pour développer efficacement • Code Session : TCP301 Bruno BOUCARD Architecte SGCIB Programmation Parallèle http://msmvps.com/blogs/brunoboucard Développement Parallèle http://blogs.msdn.com/devpara/default.aspx

  2. Agenda • Introduction • Modélisation • Conclusion

  3. IntroductionLes lois de la physique changent les règles ! • Pourquoi les fondeurs ont-ils changé de paradigme ? • Les systèmes d'exploitation sont-ils disponibles ? 256 Cœurs • « The Free Lunch Is Over » (2005) HerbSutter - Architecte Microsoft

  4. IntroductionQue faut-il pour retrouver le « Free Lunch » ? • Offres parallèles plus simples • Par exemple Visual Studio 2010  • Méthode et Patterns sans équivoque • 30 ans d’expérience dans le parallélisme • Penser Parallèle • Nous devons pratiquer le parallélisme dans notre quotidien

  5. IntroductionLa concurrence est parmi nous : à table ! Piler l'ail Découper en dés la tomate Faire bouillir de l'eau Mélanger avec du gros Sel Hacher le basilic Recouvrir d'huile d'olive Cuire les pâtes Mélanger Laisser reposer Egoutter les pâtes Mélanger et servir

  6. Agenda • Introduction • Modélisation • Conclusion

  7. Choisir une stratégie et un algorithme adaptés • Trouver la concurrence ModéliserMéthode itérative

  8. Mesurer les performances de la solution ModéliserEtape 1

  9. ModéliserAnalyser les performances • Analyser les coûts une fois la solution parallèle implémentée • Analyser les coûts de la solution séquentielle

  10. Trouver la concurrence ModéliserEtape 2

  11. ModéliserTrouver la concurrence • Commencer avec un cahier des charges qui décrit le problème • Quel que soit le contexte fonctionnel ou technique, vous serez guidé naturellement par l’une des décompositions  • Terminer avec une décomposition de tâches ordonnées en fonction des dépendances techniques et fonctionnelles, compléter par les données partagées que vous aurez identifiées • Il arrive qu’on passe d’une décomposition orientée tâches à une décomposition orientée données ou bien flux de données en fonction du type de traitement Commencer Analyse des dépendances Décomposition Grouper les tâches Orientée données Ordonner les tâches Evaluer le design Orientée tâches Partager les données • Analyser les dépendances • Visual Studio 2010 : Architecture -> GenerateDependency Graph • NDepend: http://www.ndepend.com/ • CppDepend: http://www.cppdepend.com/

  12. ModéliserDécomposition et granularité • Votre décomposition en tâches doit tenir compte de leur granularité et de leur surcoût Cœur 0 Cœur 3 Cœur 1 Cœur 2 Cœur 0 Cœur 1 Cœur 2 Cœur 3 tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche Configuration 2 Quelle est la meilleure configuration ? Configuration 1 surcoût charge

  13. ModéliserDécomposition et répartition de charge • Votre groupement de tâches doit tenir compte de leur charge Cœur 1 tâche Cœur 0 Cœur 2 Cœur 3 Cœur 0 Cœur 1 Cœur 2 Cœur 3 tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche tâche Configuration 2 Quelle est la meilleure configuration ? Configuration 1 surcoût charge

  14. ModéliserEvaluer votre design • Flexibilité • Préférer l’abstraction pour faciliter l’adaptation à différents scénarios d’exécution • Nombre de cœurs sollicités • Partitionnement des données • Efficacité • Le temps dépensé à gérer le parallélisme vs le temps gagné à tirer parti des cœurs • Amélioration des performances en fonction du nombre de processeurs • Simplicité • Le code peut être facilement diagnostiqué • La solution technique choisie est facile à maintenir

  15. Choisir un algorithme en fonction de votre stratégie ModéliserEtape 2

  16. ModéliserChoisir un algorithme en fonction de votre stratégie

  17. ModéliserAlgorithmes données • Décomposition géométrique Taille des morceaux  => Trop grand – sous utilisation => Trop petit – sur consommation Format des morceaux => Attention au false sharing Traitement d’une collection d’images, addition de matrices …

  18. ModéliserAlgorithmes données – Attention au False Sharing • Pour des raisons de performances, les systèmes utilisent des lignes de cache • Lorsque des threads sur différents processeurs modifient en parallèle les variables qui résident sur la même ligne de cache, le False Sharing n’est pas loin  Coeur 0 Coeur 1 T0 T1 Cache Cache Ligne de cache Ligne de cache • Éviter l'allocation de mémoire contiguë • Deux champs d'instance dans la même instance de classe sont proches dans leurs emplacement de mémoire • Deux champs statiques dans le même type sont proches en mémoire • Deux éléments avec des index adjacents dans un tableau sont proches en mémoire • Les objets alloués consécutivement sont probablement proches en mémoire • Les variables locales utilisées ensemble dans une fermeture sont probablement capturées dans les champs d'instance, et ainsi, d'après le premier commentaire ci-dessus, sont également proches en mémoire Mémoire

  19. ModéliserDécomposition géométrique for (int i = 0; i < size; i++) { parallel_for (0, size, 5, [&result](int j) { double t = 0; for (int k = 0; k < size; k++) { t += (m1[i][k] * m2[k][j]); } result[i][j] = t; }); }

  20. ModéliserAlgorithmes données • Décomposition récursive Le choix de la profondeur détermine la performance - Arbre profond => contention processeurs - Arbre de profondeur limitée => sous utilisation des processeurs 1 tâche 2 tâches 3 tâches 3 tâches Parcours de graphe ou parcours d’arbre …

  21. ModéliserRécursivité sur des données staticvoidWalk<T>(Tree<T> root, Action<T> Action) { if (root == null) return; var t1 = Task.Factory.StartNew(() => action(root.Data)); var t2 = Task.Factory.StartNew(() => Walk(root.Left, action)); var t3 = Task.Factory.StartNew(() => Walk(root.Rigth, action)); Task.WaitAll(t1, t2, t3); }

  22. ModéliserAlgorithmes tâches • Parallélisme de tâches linéaires Nombre de tâches => Trop peu: les cœurs sont sous utilisés => Trop élevé: contention des tâches Dépendances =>Retirables => Séparables => Lecture seule ou lecture/écriture sous opération 1 sous opération 2 sous opération 3 sous opération 4 sous opération 1 sous opération 4 sous opération 2 Paralléliser des opérations décomposables sous opération 3

  23. ModéliserAlgorithmes tâches Arbres profond => contention processeurs Arbres de profondeur limitée => sous utilisation des processeur • Diviser pour régner Problème Séquentiel Split Sous - problème Sous - problème 2 chemins parallèles Split Split Sous - problème Sous - problème Sous - problème Sous - problème 4 chemins parallèles Résoudre Résoudre Résoudre Résoudre Sous - problème Sous - problème Sous - problème Sous - problème Fusionner Fusionner 2 chemins parallèles Sous - solution Sous - solution Fusionner QuickSort Solution Séquentiel

  24. ModéliserDiviser pour régner voidquicksort(int* a, int n) { if (n <= 1) return; int s = partition(a, n); task_group g; g.run([&]{ quicksort(a, s); }); g.run([&]{ quicksort(a + s, n + s); }); g.wait(); }

  25. ModéliserAlgorithmes flux de données • Pipeline Les charges de travail des étapes => Egales – pipeline linéaire => Inégales – pipeline non-linéaire Chaîne de montage automobile

  26. ModéliserAlgorithmes flux de données • Coordination orientée événements Traitement d’une dépêche sur un desk journalistique …

  27. ModéliserPipeline agent_a a; agent_b b; agent_c c; // a -> b -> c b.set_input(a.get_output()); c.set_input(b.get_output()); c.start(); b.start(); a.start(), a.wait(); b.wait(); c.wait();

  28. Choisir un pattern de structure ModéliserEtape 3

  29. ModéliserChoisir un pattern de structure • Le passage à l’implémentation se décompose en deux types de patterns de structure Patterns de structures Programme Données

  30. ModéliserChoisir un pattern de structures de programme • Après avoir sélectionné votre algorithme parallèle, il faut maintenant le supporter dans votre programme Structures de programme SPMD Master/Worker Boucle parallèle Fork/Join

  31. ModéliserLes Patterns de structures de programme • SPMD, Master/Worker, Boucle parallèle et Fork/Join partagent les mêmes idiomes Partitionner Exécuter Fusionner

  32. ModéliserFork / Join Parallel.Invoke( () => ComputeMean(), () => ComputeMedian() ); parallel_invoke( [&] { ComputeMean(); }, [&] { ComputeMedian(); } );

  33. ModéliserBoucle parallèle Parallel.For(0, 1000, (i) => _treatments.Update(i); ); parallel_for (0, 1000, 1, [&](int i) { _treatments.Update(i); });

  34. ModéliserStructures de programme parallèle • Appliquées dans différents contextes • SPMD – Systèmes distribués • MPI, SOA, GridComputing, • Fork / Join – Orienté Tâches • TPL ou PPL • Master/Worker – Orienté Tâches • TPL ou PPL • Boucle Parallèle – Orienté Données • OpenMP, TPL, PLINQ ou PPL

  35. ModéliserChoisir un pattern de structures de données partagées Structures de données partagées Données partagées Queue partagée

  36. Modéliser Données Partagées • Définir une abstraction qui vous affranchira d’une complexité sujette à des erreurs • Cacher la complexité de la protection des données à travers des interfaces simples et non ambigües • Privilégier une stratégie de verrouillage performante • Si possible via des techniques peu couteuses (éviter les transitions mode noyau/ mode utilisateur) • Pour une boucle parallèle, utiliser les données privées des threads Thread Local Storage (TLS) pour réduire le coût du verrouillage excessif

  37. ModéliserDonnées Partagées combinable<list<TypeBitmap>> bitmaps; parallel_for_each(m_filenames.begin(), m_filenames.end(), [&](std::wstring filename) { bitmaps.local().push_back(LoadImage(filename)); }); bitmaps.combine_each([&](list<TypeBitmap>& localList) { images.splice(images.begin(), localList); });

  38. Modéliser Pattern Décorateur • Encapsuler le parallélisme • Permet un usage agnostique dans un contexte parallèle • Par exemple ajouter le support du parallélisme à une structure existante • Par exemple: rendre le type array<T> compatible parallèle • Encapsuler le type d’origine en protégeant les codes sensibles à une exécution simultanée : concurrent_array<T> concurrent_array<T> array<T> IArray IArray

  39. Modéliser Queue Partagée • ConcurrentQueue<T> • Cache le verrouillage interne qui protège l’objet interne Queue<T> • Implémente IProducerConsumerCollection<T> • Facilite le pattern Producteur / Consommateur • T1 -> theQueue.Enqueue • T2 -> theQueue.Dequeue

  40. ModéliserQueue Partagée var results = new ConcurrentQueue<Result>(); Parallel.For(0, 1000, (i) => { Resultresult = ComputeResult(i); results.Enqueue(result); });

  41. Agenda • Introduction • Modélisation • Conclusion

  42. ConclusionQuelques suggestions pour l’implémentation • Préférer les nouveaux outils de haut niveau d’abstraction • VS 2010: TPL, PLINQ, PPL et Asynchronous Agents Library • Tester Axum • Privilégier les solutions simples à maintenir • La granularité fine est souvent synonyme de complexité • Utiliser systématiquement des librairies thread-safe • Fiabilité == Gain de temps • Ne jamais présumer d’un ordre d’exécution • La justesse du code est à ce prix

  43. ConclusionPour retrouver le « Free Lunch » • Respecter les 4 grandes étapes • Notamment les « analyses des dépendances » et « analyses des performances » • Avancer de manière itérative • Difficile de trouver « la solution » du premier coup • Si possible privilégier les capacités de monter en charge ainsi que la simplicité • Mesurer régulièrement les performances de vos choix • Visual Studio 2010 est votre ami • Si vos choix ne vous semblent pas satisfaisants • Oser changer votre algorithme pour augmenter ses chances de parallélisation • Penser Parallèle • C’est en pratiquant régulièrement la méthode présentée que vous gagnerez en réflexes sur l’usage des Patterns parallèles les mieux adaptés à vos besoins

  44. Vous n’êtes pas seul !Livres et blogues • Mes ouvrages préférés • Programmation Parallèle • http://msmvps.com/blogs/brunoboucard • Portail Microsoft ParallelComputing • http://msdn.microsoft.com/en-us/concurrency • Patterns for Parallel Programming de Stephen Toub • http://www.microsoft.com/downloads/details.aspx?FamilyID=86b3d32b-ad26-4bb8-a3ae-c1637026c3ee&displaylang=en

More Related