BUT2FI_2024_R3.05/tp/tp1
2024-09-05 09:00:42 +02:00
..
src typo 2024-09-05 09:00:42 +02:00
README.md typo 2024-09-05 09:00:42 +02:00

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 qie 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 :

  1. Allocation statique buf.c.
  2. Allocation sur la pile stack.c,
  3. Allocation sur le tas heap.c,
  4. Allocation (grande quantité) sur le tas huge.c.
  5. 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;
}
  1. Compilez le programme. Avec la commande size, regardez les différents segments du programme. Où se trouve le tableau t ? Augmentez la valeur de N. La taille de l'exécutable a-t-elle changé ? pourquoi ?
  2. 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 par mmap.
  • 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 ligne
  • BB 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 ?