# TP1 : Mémoire

> Dans le répertoire [scripts](./src/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.

> Lisez la fin du [cours](../../cours/memoire.pdf) sur la mémoire avant de commencer le tp
#### Ex1 

Soit  le   [programme](./src/adresses_virtuelles.c)  suivant  qui   affiche  les
adresses  virtuelles de  certaines variables  lors de  l'exécution du  processus
correspondant :

```c
/* adresses virtuelles d'un processus */

#include<stdio.h>
#include<sys/types.h>
#include <sys/time.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=\t%p\n",main);
	printf("gettimeofday\t=\t%p\n",gettimeofday);
	printf("&argc\t\t=\t%p\n",&argc);
	printf("&i\t\t=\t%p\n",&i);
	printf("&j\t\t=\t%p\n",&j);
	printf("t\t\t=\t%p\n",t);
	printf("m\t\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](./src/scripts/vmap.py) ou `cat`.

```bash
man proc_pid_maps
```

####  Ex2

L'interface  (pseudo-fichier) `proc/pid/smaps`  montre  la consommation  mémoire
d'un processus. On peut le formater avec la commande `pmap -x|X` ou avec le script
python [parse_smaps.py](./src/scripts/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](./src/ex2/buf.c).
2. Allocation sur la pile [stack.c](./src/ex2/stack.c),
3. Allocation sur le tas [heap.c](./src/ex2/heap.c),
4. Allocation (grande quantité) sur le tas [huge.c](./src/ex2/huge.c).
5. Allocation par mapping [mmap.c](./src/ex2/mmap.c). 

#### Ex3

Soit le [programme](./src/bss_data.c) suivant :

```c
/* 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.

#### Ex4

Soit le [programme](./src/ij_ji.c) suivant :   

```c
/* 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 ?    

#### Ex5  

Le  programme [sum_array.c](./src/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 .                                                         

#### Ex6

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 :

```c
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 
```c
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.

#### Ex7

Compilez   avec  `g++`   le  programme   [structure.c](./src/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.


#### Ex8 
Ecrire une fonction  
```c
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 :   
```c
/* 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 ?    


