%\part{Cours 1\er} \chapter{Introduction} \section{Motivations} On augmente plus trop en fréquence, ça augmente plus trop ces dernières années comparé à avant. Et pourtant, on augmente toujours le nombre de processeurs sur les puces. On va de plus en plus vers du parallélisme et non plus vers de la vitesse. \section{Vocabulaire} \subsection{Modèle d'exécution} \subsubsection{À acteurs} Ils communiquent entre-eux~: au lieu d'éxécuter le code d'un objet dans le thread courant, la méthode s'éxécute dans le thread de l'objet. Similaire au RPC. \subsubsection{Futures} Notion d'éxécution lazy. Le calcul commence en tâche de fond, lorsque l'on a besoin de la valeur, on est mis en attente si elle n'est pas encore calculée~; on a donc pas à attendre au début du calcul. \subsubsection{CSP -- Communication Séquential Processors} Modèle dans lequel on a des processus séquentiel qui ne font que se parler (pas de mémoire partagée). \subsubsection{CCS} ? \subsection{Gestion des sections critiques} \subsubsection{Locks} \subsubsection{Conditions} \subsubsection{Mutex} \subsubsection{Sémaphores} \subsection{Histoire} Apparu vers la fin des années 50. Premier aboutissement (machine à 4 processeurs) en 1962. \subsection{Définitions} \subsubsection{Matérielle} \paragraph{Symetric MultiProcessor} On place plusieurs processeurs (identiques ou non) sur une carte mère spéciale. \paragraph{Multi-core} deux processeurs ou plus en un, avec certain composants partagés~: en particulier les caches. Moins cher que du SMP \paragraph{Hyper-threading} Étant donné que chaque famille d'instruction a une zone réservée dans le processeur, du coup, lorsqu'une instruction est en train de s'exécuter, elle bloque le reste du processeur, du coup, beaucoup de circuit ne servent pas, l'hyperthreading essaye d'exécuter plusieurs zone en même temps. \paragraph{Vectorized instructions} applique une instruction sur un lot de donnée. \paragraph{Non-Uniform Memory Access (\textsc{numa})} on associe à chaque processeur des blocs mémoires. Un certain processeur a un accès prioritaire à ses blocs mémoires. \chapter{Soyons parallèle} \section{Gain~?} Amdahl's law~: $$\frac{1}{(1-P\frac{P}{N}}$$ On n'ira jamais deux fois plus vite que deux fois plus vite avec 50\% du code parallélisé. Au final, il faut s'arranger sur la parallélisation du code, plutôt que sur le nombre de processeurs.\\ Gustafson's law~: $$S(P)=P+a\times(P-1)$$ \section{Différents types de parallélisme} \subsection{Décomposition par tâches} On lance un thread par tâche en gros. Il faut voir les problèmes d'interdépendances entre chaque thread, etc. \subsection{Data driven} On a un paquet de données similaire. On a un traitement similaire à effectuer sur ces données. On découpe les données en petits blocs et on lance plein de petit threads. \subsection{Modèle flow} Comme une chaîne de production. On a $n$ tâche, chaque unité traite une tâche. Pour que ça marche, il faut que les données soient correctement découpés. \subsection{Design Patterns} \paragraph{Divide and Conquer} on divise le problème, puis on a une seconde phase de recollection des données. \paragraph{Pipeline} mise en pratique de la décomposition par data flow. \paragraph{Wave front} mise en œuvre d'un tri topologique parallélisée. On traite une tâche quand on a traitée ses prédécesseurs. \paragraph{Geometric decomposition} façon de couper les blocs de données qui ne sont pas forcément contigus. \chapter{Interragir avec le cache du CPU} Le cache est nécessaire du fait que la mémoire est beaucoup plus lente que le processeur. Le cache est géré par ligne~: de quelques dizaine d'octets. Chaque ligne a un état par rapport à sa cohérence. Lorsqu'elle est invalide cela signifie qu'une modification a été effectuée en mémoire ou dans un autre cache (d'un autre processeur par exemple). En état partagé, il n'est pas possible d'écrire dessus, on peut seulement la lire. En mode exclusif, seul un processeur peut écrire la zone mémoire, elle est ensuite noté modified. \section{False sharing} Par moment, il peut y avoir deux processeurs qui utilisent deux valeurs différentes mais dans des lignes de cache identiques. Du coup il va invalider une ligne de cache sur l'autre processeur alors qu'en réalité, la valeur qui intéressait le processeur n'a pas été modifiée. On parle de \emph{False sharing}. Pour éviter ce genre de chose, il faut utiliser le plus de variable locale possible dans chaque thread, et avoir le moins de données communes.\\ \section{Memory fence} \chapter{Exclusion mutuelle} Une section critique est une section de code où l'on manipule des données partagées (quand on dépend d'événement d'écriture sur une zone mémoire). \section{Problème classique~: compteur partagé} On a un compteur partagé entre deux threads. \paragraph{Exclussion mutuelle~:} deux threads ne doivent pas pouvoir être au même endroit en même temps. \paragraph{Progression~:} lorsque l'on veut aller dans une section critique, on ne doit attendre que parce que quelqu'un y est déjà. \paragraph{Attente bornée~:} quand on attend la section critique. On attend un nombre fini de thread. \paragraph{Deadlock~:} mauvaise combinaison d'accès du coup deux thread s'attendent mutuellement. \paragraph{Race condition~:} sous certaines conditions d'éxécution, certaines propriétés ne sont pas respectées. \paragraph{Famine~:} un thread est en famine quand il attend indéfiniment une ressources.