%\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.

