>
>
Mesures de temps - Mesures de performances
- utiliser des nœuds entiers (tous les processeurs d’un nœud ou réserver le nœud en mode exclusif) pour qu’il n’y ai pas d’autre jobs parasites qui viennent s’exécuter sur votre/vos nœuds de calcul
- chronométrer uniquement le temps de calcul/communication en excluant les temps d’entrées/sortie (I/O) disque en ne démarrant le chrono qu’après le chargement des données et en l’arrêtant avant l’écriture des résultats
- désactiver le swap de la machine
- exécuter la commande sync pour flusher les buffers caches disque avant chaque run, et avant la phase de warmup (cf plus bas)
- dans le cas d’un logiciel ou d’une bibliothèque boite noire,
- forcez une lecture des fichiers avant l’exécution chronométrée afin qu’ils soient en cache mémoire
- paramétrez le logiciel ou la bibliothèque pour désactiver au maximum les affichages / outputs / logs
- si des entrée/sorties sont obligatoires, privilégier les disques locaux en mémoire : NVME, /tmp monté en mémoire, ou à défaut, les disques locaux aux nœuds de calcul (/tmp classique)
- si vous devez mesurer/inclure des temps d’entrées/sorties disque ou réseau vous devrez faire plusieurs mesures, en tenant compte des aléas des accès disques qui sont impactés par :
- l’utilisation des autres jobs
- les buffers cache des machines qui accélèrent énormément les relectures de fichiers et les écritures pour des volumes de données de l’ordre de grandeur des tailles des mémoires (dizaines de giga)
- faire quelques itérations de préchauffage (warmup) avant la vraie mesure pour être sur que les données/code soient bien chargés en mémoire et dans les caches au moment de la mesure.
- vérifier que les processus/thread sont verrouillés sur les cœurs pour éviter des ralentissements quand ils bougeront d’un cœur à un autre sur une même machine (ca arrive souvent à cause des démons qui se réveillent de temps en temps en tâche de fond). La plupart des implémentations MPI et OpenMP s’occupent de binder par défaut pour vous. Sinon utiliser hwloc-bind, numactl, etc pour le faire à la main.
- dans le cas de programme utilisant des nombres aléatoires, fixer le germe (seed) à une valeur précise pour obtenir toujours la même suite de nombre et avoir un comportement reproductible.
- les entrées/sorties sur espace partagés via le réseau ne sont plus rapides que pour les grosses opérations (grosses lectures/écritures). en revanche, les petites opérations (lecture, écriture, ouverture, fermeture, création/destructions de fichier, consultation des droits...) sont beaucoup plus coûteuses ( x10). il faut donc bufferiser. (attention à la sortie erreur qui est par défaut non bufferisée).
À Ajouter :
- si parallelisme sur pueieurs noeuds (ex : MPI) utiliser le bon réseau IB (-psm...), contrôler le placement des processus sur les nœuds
- laisser refroidir la machine entre deux mesures, ou au contraire, faire chauffer la machine avant de faire les mesures. L’idée étant que la températur des CPUs soit la même dans les deux cas, car cela impact leur fréquence de fonctionnement
- utiliser setarch pour désactiver la randomization mémoire, ce qui rend plus stable les défaut de cache de prédiction de branchement
Note : même si cela coïncide souvent, avoir des performances reproductibles n’est pas le même objectif que d’avoir les meilleurs performances possible.