.. | ||
src | ||
README.md | ||
src.tar.gz |
TP1 : Mémoire
Dans le répertoire scripts, vous avez 2 scripts qui permettent de formater sur la sortie standard les interfaces
/proc/pid/maps
et/proc/pid/smaps
d'un processus quelconque.
Ex1
Compilez avec g++
le programme structure.c, et
exécutez. Vérifiez que la taille et l'alignement de chaque structure est bien
conforme aux règles vues en cours.
Ex2
Soit le programme suivant qui affiche les adresses virtuelles de certaines variables lors de l'exécution du processus correspondant :
/* adresses virtuelles d'un processus */
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int t[1000] = {[0 ... 999] = 2};
int main(int argc, char * argv[])
{
int i=3;
static int j = 3;
char * m = (char*)malloc(1);
printf("je suis le pid %d\n\n",getpid());
/* ------- Affichage des adresses --------*/
printf("main\t=\t%p\n",main);
printf("&argc\t=\t%p\n",&argc);
printf("&i\t=\t%p\n",&i);
printf("&j\t=\t%p\n",&j);
printf("t\t=\t%p\n",t);
printf("m\t=\t%p\n",m);
getchar();
}
En utilisant le (pseudo) fichier /proc/pid/maps
, vérifiez à quel segment de
pages ces adresses appartiennent. Vous pouvez utiliser le script python
vmap.py.
Ex3
L'interface (pseudo-fichier) proc/pid/smaps
montre la consommation mémoire
d'un processus. On peut le formater avec la commande pmap -X
ou avec le script
python parse_smaps.py. Le but de l'exercice est
de voir ce qui se passe au niveau de la mémoire d'un processus suivant les
différents mode d'allocation. Le programme null.c
permet d'avoir un point de
comparaison. Vérifiez la consommation mémoire dans les cas suivants :
- Allocation statique buf.c.
- Allocation sur la pile stack.c,
- Allocation sur le tas heap.c,
- Allocation (grande quantité) sur le tas huge.c.
- Allocation par mapping mmap.c.
Ex4
Soit le programme suivant :
/* segment bss et data */
#define N 10000
int t[N]; /* version 1 */
//int t[N]={1}; /* version 2 */
int main()
{
return 0;
}
- Compilez le programme. Avec la commande
size
, regardez les différents segments du programme. Où se trouve le tableaut
? Augmentez la valeur de N. La taille de l'exécutable a-t-elle changé ? pourquoi ? - Recommencez avec la version 2. Expliquez.
Ex5
Soit le programme suivant :
/* accès mémoire */
#include<stdio.h>
#include<time.h>
#include <stdlib.h>
#define N 8192
int t[N][N];
static inline double tstamp(void)
{
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
return tv.tv_sec + tv.tv_nsec * 1.0e-9;
}
int main()
{
int i,j;
double t1,t2;
t1=tstamp();
/* version 1 */ for(i=0;i<N;i++) for(j=0;j<N;j++) t[i][j] = 1;
/* version 2 */ // for(i=0;i<N;i++) for(j=0;j<N;j++) t[j][i] = 1;
t2=tstamp();
printf("time = %lf\n",t2-t1);
return 0;
}
Le temps d'exécution est-il différent pour les deux versions ? Pourquoi ?
Ex6
Le programme sum_array.c calcule la somme des éléments
d'un tableau en accédant aux éléments séquentiellement (-c
croissant, -d
décroissant) ou de manière aléatoire (-a
) Testez en faisant varier la taille
du tableau. Expliquez .
Ex7
On veut implanter un allocateur de mémoire très simple. Un bloc de 8Mo est
reservé à l'aide de la fonction mmap
. On utilise pour la gestion des demandes
d'allocation la structure suivante :
struct my_memory_buffer {
char* buffer;
size_t pos;
size_t size;
};
buffer
est l'adresse de la zone reservée parmmap
.size
est la taille du buffer.pos
permet de garder la trace de ce qui a déjà été alloué.
buffer +-------------->+---------------------------+
|###########################| \
|###########################| |
|###########################| | already allocated
|###########################| |
|###########################| |
|###########################| /
pos +-------------->----------------------------+
| | \
| | |
| | |
| | |
| | |
| | | free space
| | |
| | |
| | |
| | |
| | |
| | /
+---------------------------+
C'est la fonction
void * my_alloc(size_t sz)
qui s'occupe de renvoyer l'adresse d'un bloc libre. On ne se préoccupe pas de désallocation, ni d'alignement. Une allocation consiste simplement à incrémenter (si c'est possible)
la valeur de pos
, et à retourner l'adresse du bloc alloué.
Implanter cette fonction, et tester.
Ex8
Ecrire une fonction
void hexdump(void * ptr,size_t size);
qui affiche sur la sortie standard le contenu de la mémoire [ptr,ptr+size[
au format :
XXXXXXXX BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB |CCCCCCCCCCCCCCCC|
(comme la commande shell)
XXXXXXXXX
représente l'adresse du premier octet de la ligneBB
la valeur hexadécimale de chaque octet|CCCCCCCCCCCCCCCC|
la correspondance ascii de chaque octet (.
si non affichable)
Testez avec les objets suivants et expliquez :
/* alignement et objets */
struct exemple1 {
int x;
int y;
int z;
int w;
};
struct exemple2 {
char x;
char y;
char z;
char w;
};
struct exemple3 {
int x;
int y;
char z;
char w;
};
struct exemple4 {
int x;
char y;
int z;
char w;
};
union exemple5 {
int x;
char y;
int z;
char w;
};
int main()
{
int a[4] = {1,2,3,4};
char c[4] = {'a','b','c','d'};
struct exemple1 ex1 = {1,2,3,4};
struct exemple2 ex2 = {'a','b','c','d'};
struct exemple3 ex3 = {1,2,'c','d'};
struct exemple4 ex4 = {1,'c',2,'d'};
union exemple5 ex5;
int x = 61;
char y = 62;
int z = 63;
char w = 64;
ex5.x=62;ex5.y=63;ex5.z=64;ex5.w=65;
// appelez hexdump pour chaque variable
return 0;
}
Est-ce conforme à ce que l'on a vu en cours concernant l'alignement en mémoire ?