Mémoire (Recommandations)

Sommaire[Masquer]

1. Architecture NUMA: cas général sur Calculco

La plateforme Calculco est un cluster composé de serveurs (nœuds de calcul) multiprocesseurs à mémoire partagée. Ils ont une architecture NUMA et dans cette architecture on parle aussi de nœud mais cela représente cette fois un ensemble "espace mémoire + processeurs (cœurs) + entrées-sorties" au sein d'un même serveur (nœud de calcul).
On utilisera alors par la suite le terme "lame de calcul" au lieu de "nœud de calcul" sur cette page pour ne pas utiliser 2 fois le terme nœud.

Sur calculco, il n'y a pas eu de configuration spéciale concernant la configuration des nœuds mémoire sur nos lames de calcul. Actuellement il y a sur chaque lame de calcul x nœuds mémoire ou x est en fait le nombre de cpu (processeurs) de la lame. Physiquement ce sont les barrettes mémoires des différentes slots de chaque processeur couplé à l'ensemble des cœurs dudit processeur qui forme le nœud mémoire. La construction du nœud mémoire est assez logique.
Chaque cœur peut accéder à la mémoire du nœud mémoire auquel il appartient de manière optimale ou des nœuds mémoire voisins modulo un facteur d'accès pénalisant. Si vous désirez vous rendre compte de cette répartition sur une lame de calcul vous pouvez lancer une réservation interactive par défaut (oarsub -I) et lancer la commande numactl -H.

Vous vous apercevrez par la même occasion que le numéro des cœurs associés à chaque nœud est (modulo le nombre de processeurs de la lame) toujours le même. Le nœud mémoire est composé de tous les cœurs du même processeur.

note (2025): l'assertion ci-dessus est vraie pour tous les nœuds anciens et intel (même récent) , mais fausse pour les derniers nœuds équipés de cpus AMD EPYC (orval > 26) . cf note spécifique AMD EPYC plus bas.

 
Sur la plateforme :

Les lames anciennes ont de 128Go à 256Go de RAM.

Certaines, financées sur projet ont des configurations différentes: 384 Go pour orval12 (LPCA) et orval 35;  RUPTURE(LISIC),  512Go pour orval13 (LOG). 

Les lames récentes on 512 Go de RAM (orval > 17)  (sauf exception ci-dessus)

Il y a une lame "BigMem" (2To) : orval30.

Tout ça est visible via l'outil monika (cf menu "Monitoring"), il suffit de sélectionner les propriétés qui vous intéressent pour savoir quel(s) noeud(s) correspond(ent) à vos critères.


Par exemple sur orval13 qui a 4 cpu, pour voir la répartition des nœuds mémoire :

# numactl -H
available: 4 nodes (0-3)
node 0 cpus: 0 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68
node 0 size: 128377 MB
node 0 free: 53547 MB
node 1 cpus: 1 5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 65 69
node 1 size: 129019 MB
node 1 free: 124403 MB
node 2 cpus: 2 6 10 14 18 22 26 30 34 38 42 46 50 54 58 62 66 70
node 2 size: 129019 MB
node 2 free: 125309 MB
node 3 cpus: 3 7 11 15 19 23 27 31 35 39 43 47 51 55 59 63 67 71
node 3 size: 129016 MB
node 3 free: 123634 MB
node distances:
node 0 1 2 3
0: 10 21 21 21
1: 21 10 21 21
2: 21 21 10 21
3: 21 21 21 10

Sur orval13 il y a 4 processeurs de 18 cœurs et 512Go de RAM au total. Les cœurs du nœud de mémoire 0 (au nombre de 18) sont tous ceux du processeur 0 et sont numérotés 0,4,8,12,16,20...68. Le nœud mémoire dispose du quart de la mémoire totale de la lame de calcul, soit 126Go.
On voit aussi la quantité de mémoire non utilisée de chaque noeud de mémoire.
La compréhension de cette numérotation peut vous être utile aussi lorsque vous regardez les outils de monitoring comme drawgantt et monika. La numérotation des cœurs d'un même processeur n'est pas continue !

Plus généralement, sur calculco, pour chaque lame de calcul, tous les cœurs du nœud de mémoire n (n compris entre 0 et m-1 processeurs de la lame) sont égaux à n (modulo m). Le nœud de mémoire dispose du total de mémoire de la lame de calcul divisé par m.

note (2025): l'assertion ci-dessus est vraie pour tous les nœuds anciens et intel (même récent) , mais fausse pour les derniers nœuds équipés de CPU AMD EPYC (orval > 26) . cf note spécifique AMD EPYC plus bas.

 
Mais comment se traduit tout cela lorsque je lance une réservation. Pourquoi m'arrive t'il de swapper alors que je n'utilise pas toute la mémoire disponible de la lame de calcul !

 

En fait le gestionnaire de ressources et de tâches OAR via le mécanisme des cpusets va confiner votre réservation aux ressources demandées. Il peut donc y avoir un problème dans la quantité de mémoire disponible pour votre tâche si vous n'utilisez pas tous les nœuds mémoire dans votre réservation. Cela n'est pas explicite dans la réservation et c'est là que le bât blesse.

Par exemple sur cette même lame orval13 (qui dispose de 4 processeurs de 18 cœurs) vous voulez lancer une réservation de 8 cœurs de calcul sans être trop explicite (par exemple en interactif oarsub -I -I /core=8 -p "host='orval13'"), vous ne saurez alors pas comment sont répartis les cœurs de votre réservation, il se peut que ce soient tous les cœurs d'un même processeur. C'est d'ailleurs souvent le cas quand la lame de calcul n'est pas ou très peu utilisée. Vous n'aurez alors accès qu'à un seul nœud mémoire (celui affecté au seul processeur que vous utilisez) et donc au max 128Go avant de swapper.

Pour être sûr de pouvoir utiliser toute la mémoire de la lame orval13, il faut faire intervenir tous les nœuds mémoire dans notre réservation et donc répartir les cœurs réservés sur les 4 processeurs. Ça peut être fait via la commande oarsub -I -I /cpu=4/core=2 -p "host='orval13'". On réserve alors 2 cœurs sur chaque processeur de la lame (donc toujours 8 cœurs en tout). On a accès au 4 nœuds mémoire et on peut donc utiliser potentiellement toute la mémoire de la lame de calcul. Idem, si on n'utilise que 2 processeurs (oarsub -I -I /cpu=2/core=4 -p "host='orval13') on aura alors accès uniquement à un max de 256Go de RAM.


Essayer les commandes précédentes quand c'est possible (ou utiliser une autre lame de calcul si orval13 n'est pas disponible).

# oarsub -I -l /cpu=1/core=8 -p "host='orval13'"
[ADMISSION RULE] Set default walltime to 7200.
[ADMISSION RULE] Modify resource description with type constraints
[ADMISSION RULE] Automatically add constraint to go on nodes permitted for the user.
OAR_JOB_ID=637830
Interactive mode: waiting...
Starting...

Connect to OAR job 637830 via the node orval13


Vérifier alors les cœurs et nœuds mémoire affectés à votre réservation :

# cat /proc/self/cpuset
/oar/dverhaghe_637830

# cat /dev/cpuset/oar/dverhaghe_637830/cpuset.cpus
0,4,8,12,16,20,24,28

# cat /dev/cpuset/oar/dverhaghe_637830/cpuset.mems

On voit bien qu'on utilise tous les cœurs du processeur 0 et uniquement le nœud mémoire 0. Donc au max 126Go.


Par contre si on utilise 2 processeurs :

# oarsub -I -l /cpu=2/core=4 -p "host='orval01'"
[ADMISSION RULE] Set default walltime to 7200.
[ADMISSION RULE] Modify resource description with type constraints
[ADMISSION RULE] Automatically add constraint to go on nodes permitted for the user.
OAR_JOB_ID=637831
Interactive mode: waiting...
Starting...

Connect to OAR job 637831 via the node orval01


On peut aussi vérifier les cœurs et nœuds mémoires affectés à notre réservation :

# cat /dev/cpuset/oar/dverhaghe_637831/cpuset.cpus
0-1,4-5,8-9,12-13

# cat /dev/cpuset/oar/dverhaghe_637831/cpuset.mems
0-1

On voit cette fois qu'on utilise les cœurs 0,4,8,12 du processeur 0 (modulo 4 sur les numéros de cœurs)  et les cœurs 1,5,9 et 13 du processeur 1 (modulo 4 sur les numéros de cœurs).
Par contre on utilise ici les nœuds mémoire 0 et 1 et on pourra donc accéder à 256Go de RAM

 

De même si on utilise les 4 processeurs :

# oarsub -I -l /cpu=4/core=2 -p "host='orval01'"
[ADMISSION RULE] Set default walltime to 7200.
[ADMISSION RULE] Modify resource description with type constraints
[ADMISSION RULE] Automatically add constraint to go on nodes permitted for the user.
OAR_JOB_ID=637832
Interactive mode: waiting...
Starting...

Connect to OAR job 6378302 via the node orval01


Si on vérifie les cœurs et nœuds mémoire :

# cat /dev/cpuset/oar/dverhaghe_637832/cpuset.cpus
8-15

# cat /dev/cpuset/oar/dverhaghe_637832/cpuset.mems
0-3

On utilise les cœurs 8 et 12 du processeur 0,  9 et 13 du processeur 1, 10 et 14 du processeur 2 et 11 et 15 du processeur 3
On a accès cette fois à tous les nœuds mémoire, soit 512Go.

2. (note 2025) PARTICULARITÉ AMD EPYC:

Pour les lames récentes dotées de processeur AMD EPYC, de orval27 à orval41 (orval 14 et 17 ne sont pas concernées). Celles-ci sont toutes dotées non pas de 1 mais de 4 nœuds mémoire par cpu.  La très grande majorité est dotée de 512 Go de RAM et de 2 x 48 = 96 cœurs.

 

# numactl -H
available: 8 nodes (0-7)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11
node 0 size: 64198 MB
node 0 free: 63941 MB
node 1 cpus: 12 13 14 15 16 17 18 19 20 21 22 23
node 1 size: 64507 MB
node 1 free: 64231 MB
node 2 cpus: 24 25 26 27 28 29 30 31 32 33 34 35
node 2 size: 64507 MB
node 2 free: 64279 MB
node 3 cpus: 36 37 38 39 40 41 42 43 44 45 46 47
node 3 size: 64495 MB
node 3 free: 64272 MB
node 4 cpus: 48 49 50 51 52 53 54 55 56 57 58 59
node 4 size: 64507 MB
node 4 free: 64309 MB
node 5 cpus: 60 61 62 63 64 65 66 67 68 69 70 71
node 5 size: 64479 MB
node 5 free: 63845 MB
node 6 cpus: 72 73 74 75 76 77 78 79 80 81 82 83
node 6 size: 64507 MB
node 6 free: 64322 MB
node 7 cpus: 84 85 86 87 88 89 90 91 92 93 94 95
node 7 size: 64505 MB
node 7 free: 64354 MB
node distances:
node 0 1 2 3 4 5 6 7
0: 10 12 12 12 32 32 32 32
1: 12 10 12 12 32 32 32 32
2: 12 12 10 12 32 32 32 32
3: 12 12 12 10 32 32 32 32
4: 32 32 32 32 10 12 12 12
5: 32 32 32 32 12 10 12 12
6: 32 32 32 32 12 12 10 12
7: 32 32 32 32 12 12 12 10

Avec ces lames, si vos besoins de mémoire sont conséquents, il faut donc "forcer" (4 x plus) vos réservations car :   

# oarsub -I -l/cpu=1/core=8 -p 'host="orval31"'

[ADMISSION RULE] Set default walltime to 7200.
[ADMISSION RULE] Modify resource description with type constraints
[ADMISSION RULE] Automatically add constraint to go on nodes permitted for the user.
OAR_JOB_ID=4749998
Interactive mode: waiting...
Starting...
Connect to OAR job 4749998 via the node orval31

# cat /dev/cpuset/oar/dverhaghe_637832/cpuset.mems

Un seul nœud mémoire est utilisé, le 0. Par conséquent, le job n'accède qu'à 64 Go ( et swappera s'il a besoin de plus).  

1-12 cœurs : 1 seul nœud mémoire (64 Go max) 
13-24 cœurs: 2 nœuds mémoire (126 Go max) 
25-36 cœurs : 3 nœuds mémoire (196 Go max) 
37-48 cœurs: 4 nœuds mémoire (256 Go max)     [ oarsub -I -l/cpu=1 -p 'host="orval31"' ]

3. Usage avancé (solution 1) : contrôle et placement à la réservation (cpuset)

Proposition élégante par D. Fontanari, LPCA (merci à lui!):  réservation des nœuds mémoires en "plaçant" explicitement  les cœurs ( via cpuset )  lors de la réservation par  oarsub .  L'exemple ci-dessous montre comment réserver 4 nœuds mémoire avec une réservation de 4 cœurs sur une des lames AMD EPYC  nouvelle génération ( orval34 : 2 cpus  AMD EPYC 9174F de 16 cœurs chacun;  2 x 4 = 8 nœuds mémoire pour un total de 768Go de RAM, soit 96Go par nœud mémoire) 

La topologie d'orval34:

# numactl -H | grep cpu
node 0 cpus: 0 1 2 3
node 1 cpus: 4 5 6 7
node 2 cpus: 8 9 10 11
node 3 cpus: 12 13 14 15
node 4 cpus: 16 17 18 19
node 5 cpus: 20 21 22 23
node 6 cpus: 24 25 26 27
node 7 cpus: 28 29 30 31

Au lieu de : 

# coarsub -I -l/core=4 -q 'besteffort' -p 'host="orval34"

...qui n'autorisera  jamais (sur cette lame) l'usage de 384 Go de RAM, la proposition est : 

# coarsub -I -l {cpuset=1}/core=1+{cpuset=6}/core=1+{cpuset=9}/core=1+{cpuset=13}/core=1 -q 'besteffort' -p 'host="orval34"

Les cœurs n° 1, 6, 9 et 13 sont demandés, ces derniers sont répartis (cf numactl -H plus haut) sur les 4 nœuds mémoire n° 0, 1, 2, et 3 . Par conséquent, la tâche ainsi réservée aura bien accès à la moitié de la RAM de cette lame ( 768/2 = 384 Go ) .

4. Usage avancé AMD EPYC (solution 2) : ajout de la propriété memorynode dans la ropriété

À l'essai est  mis en place une  nouvelle propriété descriptive des nouvelles lames dotées de cpu AMD EPYC (orval > 26)  : memorynode . Elle s'insère dans la hiérarchie de réservation entre les cpus et les coeurs: host(ou node)  > cpu > memorynode > core. Cette nouvelle propriété (cf . Monitoring  : Monika ) vous permet de contrôler la répartition  des cœurs non pas aussi finement que la solution 1 (ci-dessus) mais néanmoins explicitement sur les nœuds de mémoire en fonction vos  besoins mémoire.

Réserver 8 coeurs sur une lame  dotée d'un bi-cpu -AMD EPYC et 512 Go RAM (répartie sur 8 nœuds de mémoire) pourra se faire , au choix selon vos besoins mémoire : 

# oarsub -I -p 'host="orval31"' -l/memorynode=8/core=1 -q besteffort

les 8 cœurs demandés sont répartis sur toute la lame (1 core sur chaque nœud mémoire) : le job dispose donc de 512 Go. 

# oarsub -I -p 'host="orval31"' -l/memorynode=4/core=2 -q besteffort

les 8 cœurs sont répartis par 2 sur 4  noeuds mémoire  : le job dispose donc de 256 Go (avant de swapper)  

# oarsub -I -p 'host="orval31"' -l/memorynode=1/core=8 -q besteffort

les 8 cœurs sont placés sur un seul nœud mémoire: 64 Go sont disponibles (avant de swapper) 

IMPORTANT: ces options de réservation n'ont d'intérêt que si vous avez réellement besoin de mémoire. En effet : 

numactl -H | grep cpu
....
node distances:
node 0 1 2 3 4 5 6 7
0: 10 12 12 12 32 32 32 32
1: 12 10 12 12 32 32 32 32
2: 12 12 10 12 32 32 32 32
3: 12 12 12 10 32 32 32 32
4: 32 32 32 32 10 12 12 12
5: 32 32 32 32 12 10 12 12
6: 32 32 32 32 12 12 10 12
7: 32 32 32 32 12 12 12 10

Cette matrice de distances indique les latences d'accès à la mémoire pour un cœur de calcul (10: même nœud mémoire; 12 : noeud mémoire différent mais sur le même processeur; 32: tous les noeuds mémoire de "l'autre processeur/cpu").  Demander (dans le doute) systématiquement l'accessibilité à toute la mémoire (-l/memorynode=8/core=1)  est très certainement contre-performant si on en a pas besoin.

5. Conclusion (à ré-écrire)  :

Lorsque vous savez pertinemment que vous utiliserez beaucoup de mémoire lors de l’exécution de votre tâche, il faut absolument faire intervenir tous les processeurs de la lame de calcul, et ce même si vous n'avez pas besoin de tous les cœurs de calcul.
A l'extrême, même si vous avez une tâche séquentielle sur 1 cœur qui nécessite beaucoup de mémoire, il faudra réserver toute la lame de calcul pour être sûr de ne pas swapper !!

Nous sommes conscient que ce n'est pas un fonctionnement transparent et qu'il faudra qu'on modifie cela afin que cela devienne plus intuitif et logique pour les utilisateurs.


Une piste serait de créer des bancs mémoire virtuels pour chaque cœurs de la lame de calcul. On pourrait par défaut diviser le nombre total de mémoire de la lame de calcul par le nombre de cœurs dont elle dispose et on affecterait un nœud mémoire par cœur.
Par exemple pour orval13 toujours, on créerait 72 nœuds mémoire de 7.Go affectés chacun à un cœur. Si on utilisait alors c cœurs dans notre réservation, on aurait accès à c x 7.Go de RAM.

Si vous avez d'autres idées, n'hésitez pas à nous contacter. Idem, si vous ne désirez pas qu'on change le mode de fonctionnement actuel.


 

Politique de réservation              Statistiques