Connaître la quantité de mémoire utilisée par une application n'est pas toujours facile. Sa connaissance est importante pour pouvoir déterminer les besoins lors de l'exécution. Sur une machine comme Babel, la mémoire est une ressource limitée. En effet, selon le mode d'exécution choisi, seuls 512 Mo, 1 Go ou 2 Go sont disponibles par processus.
Heureusement, vous avez accès à plusieurs outils sur Babel pour vous aider à mesurer l'occupation mémoire d'un code de calcul.
Attention : si vous pensez avoir des problèmes dus à un manque de mémoire ou si vous pensez en disposer d'assez mais que votre application échoue lors d'allocations, il se peut que vous soyez touché par le phénomène de la fragmentation de la mémoire.
sizeLa commande size permet d'obtenir certaines informations concernant l'occupation mémoire d'un programme sans avoir à l'exécuter. Vous obtiendrez la taille des zones texte (instructions du programme), data (variables globales initialisées non-nulles) et BSS (variables globales non-initialisées ou nulles).
Attention : cette commande est incapable de vous donner la quantité de mémoire qui sera utilisée par des allocations dynamiques ou qui se trouve sur le stack.
Exemple d'utilisation :
votre_login@babel1:~> size mon_code text data bss dec hex filename 2197695 178460 618836 2994991 2db32f test
L'IDRIS a développé la bibliothèque libhpcidris permettant de déterminer l'utilisation de la mémoire d'une application en l'instrumentant.
Un module est disponible. Il permet de positionner les chemins pour la bibliothèque, les fichiers d'include et les modules Fortran.
module load libhpcidris
Voici un exemple de ce que vous obtenez sur la sortie standard pour l'utilisation du sous-programme HPCIDRIS_F03_MPI_memusage_print en Fortran ou HPCIDRIS_MPI_memusage_print en C :
-------------------------------------------------------------------------------------
MEMORY USAGE (libhpcidris version 3.1)
(C)2009-2011 Philippe WAUTELET, IDRIS-CNRS
-------------------------------------------------------------------------------------
| Max (position) | Min (position) | Average | Sum
-------------------------------------------------------------------------------------
Used by application | 266.9MiB( 63) | 26.6MiB( 0) | 146.8MiB | 9.2GiB
Available | 483.6MiB( 1) | 241.1MiB( 63) | 361.5MiB | 22.6GiB
-------------------------------------------------------------------------------------
Text | 2.0MiB( 0) | 2.0MiB( 0) | 2.0MiB | 31.5MiB
Data | 1.1MiB( 0) | 1.1MiB( 0) | 1.1MiB | 72.2MiB
BSS | 633.0KiB( 0) | 633.0KiB( 0) | 633.0KiB | 39.6MiB
Stack | 44.8KiB( 0) | 44.8KiB( 0) | 44.8KiB | 2.8MiB
Heap | 262.9MiB( 63) | 22.6MiB( 0) | 142.7MiB | 8.9GiB
Dynamically allocated | 253.9MiB( 63) | 13.6MiB( 0) | 133.7MiB | 8.4GiB
Allocated with mmap | 939.6KiB( 0) | 837.5KiB( 1) | 839.1KiB | 52.4MiB
Reserved by kernel | 16.0MiB( 0) | 16.0MiB( 0) | 16.0MiB | 256.0MiB
Shared | 8.0MiB( 0) | 8.0MiB( 0) | 8.0MiB | 128.0MiB
Max heap | 262.9MiB( 63) | 22.6MiB( 0) | 142.7MiB | 8.9GiB
-------------------------------------------------------------------------------------
Donne une estimation de la mémoire utilisée par les différents processus de l'application exécutée. Elle correspond à la somme des zones text, data, BSS, stack et heap et tient compte de l'alignement sur les pages mémoire pour les 3 premières zones (la valeur sera donc un peu plus grande que la simple somme de tous ces champs).
Estimation de la mémoire restant disponible pour chaque processus. Elle correspond à la mémoire totale à laquelle à accès un processus moins la mémoire utilisée.
Attention : la mémoire réellement disponible peut être plus grande car le heap peut contenir des trous.
La mémoire totale à laquelle à accès un processus n'est pas nécessairement la même pour tous les processus car une partie de l'espace mémoire de chaque nœud est réservée à des usages particuliers (zones Reserved by kernel, shared ou text).
Les zones text, data et BSS correspondent respectivement à la mémoire utilisée pour stocker le code exécutable, les variables globales initialisées non-nulles et les variables globales nulles ou non-initialisées au démarrage de l'application.
Elles se trouvent dans des pages mémoire particulières (généralement d'une taille de 1 Mio).
Remarque : la zone text est partagée entre tous les processus d'un même nœud de calcul.
Le stack (pile) est la mémoire correspondant typiquement à celle allouée par les appels de fonctions ou sous-programmes et à leurs variables locales non persistantes.
Le heap (tas) est la mémoire correspondant typiquement aux allocations dynamique de mémoire (appels allocate en Fortran et calloc/malloc en C).
La taille donnée est la taille totale du heap. Or, celui-ci peut contenir des trous (phénomène de fragmentation mémoire). Il peut donc y avoir de la mémoire disponible à l'intérieur de cet espace.
La mémoire allouée dynamiquement (Dynamically allocated) correspond aux appels allocate en Fortran et calloc/malloc en C. Elle est incluse dans la mémoire heap.
Il est à noter que la bibliothèque MPI en utilise. Si les valeurs obtenues vous semblent surestimées, la cause est probablement à chercher là.
Il s'agit de la mémoire allouée directement avec la fonction mmap.
La bibliothèque MPI semble en utiliser un petit peu.
La mémoire réservée par le noyau (Reserved by kernel) correspond à celle dont le système d'exploitation CNK à besoin. Celle-ci est toujours de 16 Mio par nœud de calcul (quel que soit le mode d'exécution).
La mémoire partagée est un espace mémoire qui peut être utilisé avec la programmation de type shmem. Par défaut, elle est de 8 Mio et peut être modifiée avec la variable d'environnement BG_SHAREDMEMPOOLSIZE (à passer dans l'option -env de la commande mpirun, la valeur est donnée est méga-cotets).
La mémoire partagée est disponible pour tous les processus du nœud de calcul et n'existe pas en mode SMP.
Valeur maximale de la taille du heap atteinte avant ou au moment de l'appel. Elle peut donc donner une idée de la mémoire maximale qui a été utilisée par l'application (attention, le stack n'est pas pris en compte ici).
Toutes les fonctionnalités de mesure de l'occupation mémoire sont disponibles par le chargement du module Fortran hpcidris. Dans votre programme Fortran, il suffit d'ajouter la ligne suivante partout où vous utilisez cette bibliothèque :
use hpcidris
Les sous-programmes disponibles sont les suivants :
HPCIDRIS_F03_MPI_memusage_print(comm,level) : affiche des informations sur l'occupation mémoire de tous les processus. Il prend 2 arguments : le communicateur à utiliser (c'est une communication collective et doit être appellé par tous ses membres) et le niveau de détails :
HPCIDRIS_F03_memusage_print : affiche l'utilisation de la mémoire du processus qui l'appelle (attention : ce sous-programme n'est pas MPI et chaque processus l'appellant affichera ses valeurs avec le risque d'obtenir des sorties mélangées)HPCIDRIS_F03_memusage_get(mu) : récupère l'utilisation de la mémoire dans une structure de données HPCIDRIS_F03_memusage (voir plus loin)HPCIDRIS_F03_memusage_print_at_exit() : affiche l'utilisation de la mémoire du processus qui l'appelle lorsque le processus se terminera normalement. Cet appel peut être fait n'importe quand dans votre application (attention : ce sous-programme n'est pas MPI et chaque processus l'appellant affichera ses valeurs avec le risque d'obtenir des sorties mélangées)La structure de données HPCIDRIS_F03_memusage obtenue par le sous-programme HPCIDRIS_F03_memusage_get est détaillé ici :
type :: HPCIDRIS_F03_memusage
character(len=5) :: mode
integer(kind=8) :: totalmem
integer(kind=8) :: text
integer(kind=8) :: data
integer(kind=8) :: bss
integer(kind=8) :: stack
integer(kind=8) :: heap
integer(kind=8) :: mallocated
integer(kind=8) :: mmaped
integer(kind=8) :: reserved
integer(kind=8) :: shared
integer(kind=8) :: available
integer(kind=8) :: totalused
integer(kind=8) :: heapmax
integer(kind=8) :: maxrss
end type HPCIDRIS_F03_memusage
Vous trouverez un exemple d'utilisation dans le répertoire /bglocal/pub/libhpcidris/3.1/examples.
Toutes les fonctionnalités de mesure de l'occupation mémoire sont disponibles en incluant le fichier hpcidris.h ou hpcidris_mem.h. Dans votre programme C, il suffit d'ajouter la ligne suivante partout où vous utilisez cette bibliothèque :
#include "hpcidris.h"
Les fonctions disponibles sont les suivantes :
HPCIDRIS_MPI_memusage_print(comm,level) : affiche des informations sur l'occupation mémoire de tous les processus. Elle prend 2 arguments : le communicateur à utiliser (c'est une communication collective et doit être appellé par tous ses membres) et le niveau de détails :
HPCIDRIS_memusage_print : affiche l'utilisation de la mémoire du processus qui l'appelle (attention : cette fonction n'est pas MPI et chaque processus l'appellant affichera ses valeurs avec le risque d'obtenir des sorties mélangées)HPCIDRIS_memusage_get(mu) : récupère l'utilisation de la mémoire dans une structure de données struct HPCIDRIS_memusage (voir plus loin)HPCIDRIS_memusage_print_at_exit() : affiche l'utilisation de la mémoire du processus qui l'appelle lorsque le processus se terminera normalement. Cet appel peut être fait n'importe quand dans votre application (attention : ce sous-programme n'est pas MPI et chaque processus l'appellant affichera ses valeurs avec le risque d'obtenir des sorties mélangées)La structure de données struct HPCIDRIS_memusage obtenue par le sous-programme HPCIDRIS_memusage_get est détaillé ici :
struct HPCIDRIS_memusage {
char mode[5]; // Execution mode (VN, DUAL or SMP)
long long totalmem; // Total memory
long long text; // Text zone
long long data; // Data
long long bss; // BSS
long long stack; // Stack
long long heap; // Heap usage
long long mallocated; // Dynamically allocated
long long mmaped; // Allocated with mmap
long long reserved; // Reserved by kernel
long long shared; // Shared memory (shmem)
long long available; // Available to the process
long long totalused; // Used memory (without reserved by kernel)
long long heapmax; // Maximum heap
long long maxrss; // Max RSS
};