Add NUMA, ^2, LCC

This commit is contained in:
augustin64 2024-08-15 19:45:17 +02:00
parent 2f7790f2bc
commit 2fc97b6285
3 changed files with 98 additions and 39 deletions

BIN
figs/lstopo.pdf Normal file

Binary file not shown.

135
main.tex
View File

@ -20,8 +20,8 @@
% titre
\title{Caractérisation de linstruction \texttt{clflush} sur systèmes multi-\ang{socket}}
\author{\textsc{Augustin LUCAS}\\ENS de Lyon\\ \\Encadré par :\\
\textsc{Guillaume DIDIER}, \textsc{Angeliki KRITIKAKOU}\\
\author{Augustin \textsc{Lucas}\\ENS de Lyon\\ \\Encadré par :\\
Guillaume \textsc{Didier}, Angeliki \textsc{Kritikakou}\\
Équipe \textsc{Taran}\\
Laboratoire \textsc{Irisa}\\
Université de \textsc{Rennes} 1}
@ -46,24 +46,35 @@ Université de \textsc{Rennes} 1}
\section{Introduction}
\TODO{
Points à aborder
\begin{itemize}
\item NUMA balancing
\item Low Core Count, possibilité cores fantôme
\item Pourquoi nombre de coeurs = puissance de 2 ?
\end{itemize}
}
\TODO{Réordonner, faire des liens entre les subsubsections}
\subsubsection{Low Core Count}
Pour répondre à des demandes variées, \ang{Intel} base ses processeurs serveurs sur
trois tailles \TODO{à partir de la micro-architecture Haswell ?}:
\begin{itemize}
\item LCC (\ang{Low Core Count}) : de 4 à 8 coeurs physiques pour
la micro-architecture Haswell (jusqu'à 10 pour Broadwell)
\item MCC (\ang{Medium Core Count}) : de 10 à 12 coeurs pour Haswell (12 à 14 pour Broadwell)
\item HCC (\ang{High Core Count}) : de 14 à 18 coeurs pour Haswell (16 à 24 pour Broadwell)
\end{itemize}
Les machines que nous utiliserons sont uniquement basées sur la \ang{die} LCC, mais certaines
(les Broadwell à 8 coeurs par exemple) sont alors livrées avec des coeurs désactivés. La \ang{slice}
de cache L3 associée est alors désactivée également. Cela pose tout de même question sur la possibilité
de sauts supplémentaires dûs à ces coeurs manquants. \TODO{Alors, quel est le coeur désactivé ?
Est-ce similaire sur toutes les puces du même modèle ou choisi spécifiquement en usine ? Quelle
est la conséquence dans ce cas ?}
\subsection{Hiérarchie de cache}
La mémoire DRAM d'un ordinateur est lente comparée à la fréquence du CPU. Le CPU dispose donc de caches,
basés sur une mémoire SRAM, plus petite mais plus rapide. Stocker en cache les éléments accédés
basés sur des mémoires SRAM, plus petites mais plus rapides. Stocker en cache les éléments accédés
le plus fréquemment permet donc de réduire le nombre d'appels à la mémoire et donc le temps d'exécution.
Les processeurs que nous étudions disposent de 3 niveaux de cache : L1, L2, L3.
Chaque coeur possède, au premier niveau, un L1i (cache des instructions) et
un L1d (cache des données). Au second niveau, il possède un L2 qui contient potentiellement
Chaque coeur possède, au premier niveau, un L1-I (cache des instructions) et
un L1-D (cache des données). Au second niveau, il possède un L2 qui contient potentiellement
des données et des instructions. Au dernier niveau, le L3 est partagé entre tous les coeurs de la
\ang{socket}, et celui-ci est inclusif de tous les caches de niveau inférieur : toute ligne
stockée dans le cache L1 ou L2 est également dans le L3.
@ -75,7 +86,7 @@ mais est réparti en différentes \ang{slices} : des tranches de mémoire accol
\begin{figure}[ht]
\centering
\includegraphics[width=0.4\textwidth]{broadwell-die-shot}
\caption{Broadwell Deca-Core die shot by Intel - annotated by Wikichip~\cite{broadwelldieshot}}
\caption{Broadwell Deca-Core die shot by Intel - annotated by Wikichip~\cite{broadwell-wikichip}}
% L'espace vide l'est bien sur le die-shot, donc sûrement "Intel being stupid"
\end{figure}
@ -85,6 +96,34 @@ la ligne y est chargée également. Une fonction de hachage non-documentée attr
physique une unique \ang{slice} dans laquelle elle peut être mise en cache.
Différents travaux~\cite{slice-reverse, practicalTiming} ont permis de déterminer cette fonction.
\label{poweroftwo} Si les fonctions initialement utilisées
étaient simplement basés sur certains bits de l'adresse,
la fonction de hachage utilisée à partir de la micro-architecture Sandy Bridge
(et au moins jusqu'à Tiger Lake) utilise le XOR de plusieurs bits de chaque adresse physique
pour générer chaque bit du numéro de \ang{slice}. Alors, la fonction de hachage est linéaire sur les
processeurs avec un nombre de coeurs qui est une puissance de 2, mais une composante non-linéaire
s'ajoute sur les autres processeurs.
\subsubsection{\ang{NUMA}}
\begin{figure}[ht]
\centering
\includegraphics[width=1.0\textwidth]{lstopo}
\caption{Topologie \ang{NUMA} de \textit{paravance} extraite
avec l'outil \texttt{lstopo} de \texttt{hwloc}}
\end{figure}
Dans un système à plusieurs \ang{sockets}, chaque \ang{socket} a de la mémoire DRAM à laquelle il
peut accéder directement. Sur les machines Intel, le \ang{QPI} (\ang{QuickPath Interconnect})
permet à un processeur d'accéder au données localisées dans la mémoire rattachée à un autre processeur.
Le principe \ang{NUMA} (\ang{Non-uniform memory access}) délimite alors des groupes contenant
un processeur et les adresses mémoire qui en sont rapprochées et les transmet au système d'exploitation.
Cela permet à ce dernier d'allouer la mémoire dans les adresses proche du processeurs qui en a besoin.
Sur Linux, si beaucoup d'accès mémoire sont réalisés d'un processeur
à des adresses qui lui sont éloignées, les pages correspondantes sont migrées.
\subsection{Protocoles de cohérence de cache}
Dans des systèmes à plusieurs coeurs, d'autant plus avec plusieurs processeurs, où chaque coeur a
@ -121,11 +160,6 @@ même \ang{socket}, mais par \ang{snooping} entre les deux \ang{sockets}.
\subsubsection{Mémoire partagée}
\TODO{était bien formulé dans le 2.2 de~\cite{flushflush}
donc reprend largement les mêmes idées, ce n'est pas une citation et ces infos
ne sont pas non plus particulières à ce papier.
Comment dire que ça en est inspiré, faut-il le faire ?}
Les systèmes d'exploitation utilisent le principe de mémoire partagée pour
réduire l'utilisation totale de mémoire physique. C'est-à-dire que différentes
pages de mémoire virtuelle correspondent à une même page de mémoire physique,
@ -141,8 +175,8 @@ les différentes instances du programme.
Une autre forme de déduplication consiste à regarder
les pages de mémoire contenant les mêmes données et à les combiner.
Cela peut amener différents processus \TODO{\ang{sandbox}és}
ou même de machines virtuelles différentes à partager des données en commun.
Cela peut amener différents processus \ang{sandbox}és
même de machines virtuelles différentes à partager des données en commun.
\subsubsection{L'instruction \texttt{clflush}}
@ -246,10 +280,24 @@ messages échangés en fonction de l'état de cohérence des lignes
évincées du cache. Cela passe par l'étude des sources de variabilité et permet de
mieux choisir un seuil propre à chaque combinaison attaquant/victime/\ang{slice}.
Ce travail s'était intéressé à certains processeurs Intel de micro-architectures \ang{Coffee Lake} et
Ce travail s'était intéressé à certains processeurs Intel de micro-architectures
\ang{Coffee Lake} et
\ang{Haswell} à une seule \ang{socket}, mais a révélé que les résultats seraient bien plus complexes
sur des systèmes à plusieurs \ang{sockets}.
\TODO{paragraphe à déplacer}
\label{nonprivilegedinfo} Dans un scénario réel,
l'attaquant peut choisir le coeur sur lequel il s'exécute,
a accès au coeur sur lequel le processus victime s'exécute via \texttt{/proc/pid}.
La \ang{slice} peut-être trouvée en utilisant l'adresse physique mais cette information demande
généralement des privilèges qu'un attaquant n'aura pas. En revanche, si la fonction de hachage
est linéaire -- ce qui est le cas si le nombre de coeurs
est une puissance de 2 (\ref{poweroftwo}) --
il est possible de définir une classe d'équivalence des adresses des pages qui appartiennent aux
mêmes \ang{slices}. Une connaissance fine d'éléments dépendants du numéro de \ang{slice} -- comme
le temps d'exécution de \texttt{clflush} dans certaines conditions -- permettrait alors
de déterminer la \ang{slice}.
\section{Organisation des expériences}
Les expériences ont été faites sur 6 machines différentes,
@ -258,8 +306,7 @@ par processeur répondant aux critères suivants:
\begin{itemize}
\item Processeur Intel ;
\item Exactement 2 \ang{socket} ;
\item Nombre de coeurs par \ang{socket} est une puissance de
deux \footnote{\TODO{l'expliquer en amont et le rappeler ici, voir Intro}} ;
\item Nombre de coeurs par \ang{socket} est une puissance de deux
\item Micro-architecture antérieure à SkyLake\footnote{Le L3 n'est plus inclusif
sur les processeurs serveur à partir de SkyLake et la topologie devient plus complexe}
\end{itemize}
@ -281,12 +328,29 @@ Les machines suivantes ont donc été utilisées~\cite{g5k-nodes}
\end{tabular}
\end{center}
Le turbo a été désactivé sur toutes les machines.
La fréquence des coeurs fixée : à la fréquence minimale supportée par les processeurs ;
le mode performance ne donnant pas le même résultat que sur les machines \ang{Intel Core}.
Le \ang{NUMA balancing} a également été désactivé (à l'échelle du système),
ce qui peut se faire pour le processus courant sans
privilèges\footnote{\TODO{à vérifier ! voir les "À faire"}}.
La prise de mesure consistait à relever pour un lot d'adresse (chacune correspondant à une \ang{slice})
les temps d'exécution de l'instruction \texttt{clflush} pour toutes les paires de coeurs
et tous les états de cohérence possibles.
Initialement, le turbo était désactivé sur toutes les machines, la fréquence des coeurs était fixée
à la fréquence maximale en activant le mode "performance" via \texttt{cpufreq}.
Nous avons trouvé que:
\begin{itemize}
\item Contrairement aux machine \ang{Intel Core}, le mode performance ne permet pas
de fixer la fréquence de tous les coeurs à la fréquence maximale possible.
Nous avons donc fixé la fréquence des coeurs à la fréquence minimale (généralement 400MHz) ;
\item L'architecture \ang{NUMA} impliquant de déplacer les pages exploitées principalement par un
processeur distant, les adresses physiques changeaient durant l'expérience, ce qui rendait
tous les résultats complètement incohérents.
Nous avons donc désactivé le \ang{NUMA balancing} via \texttt{numactl},
ce qui peut se faire pour le processus courant sans privilèges\footnote{
Il faudrait vérifier que cela fonctionne aussi pour les pages
partagées comme les bibliothèques
}.
\item Nous avons également fixé la fréquence de l'\ang{uncore} via un MSR, mais cela n'a
pas eu de grand impact sur la clarté des résultats.
\end{itemize}
Les fichiers de résultats bruts sont accessibles en ligne~\cite{g5k-results}.
@ -332,17 +396,12 @@ c'est la numérotation que nous utiliserons pour la suite:
Pour trouver la numérotation des \ang{slices}, deux méthodes sont possibles:
\begin{itemize}
\item Utiliser la méthode proposée pour un attaquant non-privilégié (\ref{nonprivilegedinfo}).
Cela nécessite une connaissance préalable de la topologie ;
\item Utiliser les compteurs de performance pour déterminer la \ang{slice} d'une adresse.
Cela nécessite
de lire les MSR correspondants donc d'avoir un accès \ang{root}. Nous avons suivi cette méthode
afin d'être sûr que les numéros de \ang{slice} correspondent aux numéros de coeurs ;
\item Utiliser la fonction de hachage~\cite{slice-reverse} pour
déterminer la \ang{slice} de chaque adresse. Comme la fonction est appliquée sur
l'adresse virtuelle et non pas physique, celle-ci est déterminée à permutation
près.\footnote{\TODO{référence à l'explication du nb de coeur = puissance de 2 en intro}}
Il serait envisageable de donner une méthode permettant de
réordonner automatiquement les \ang{slices}, et donc de déterminer l'information de la slice
depuis un utilisateur non privilégié.
afin d'être sûr que les numéros de \ang{slice} correspondent aux numéros de coeurs.
\end{itemize}

View File

@ -32,7 +32,7 @@
HAL_VERSION = {v1},
}
@misc{broadwelldieshot,
@misc{broadwell-wikichip,
title={Broadwell - Microarchitectures - Intel - WikiChip (2024)},
url={https://en.wikichip.org/wiki/intel/microarchitectures/broadwell_(client)#Deca-core_Broadwell},
note={\url{https://en.wikichip.org/wiki/intel/microarchitectures/broadwell_(client)#Deca-core_Broadwell}},