Ajout de l'exo 1 dans le README

This commit is contained in:
Tom MOGULJAK 2023-09-14 16:18:27 +02:00
parent 22fc1af266
commit 8357f6a4c5
3 changed files with 280 additions and 10 deletions

View File

@ -1,7 +1,7 @@
# TP 1 : Mémoire
## Exercice 1
>Soit le [programme](Exo1/adresses_virtuelles.c) suivant qui affiche les adresses virtuelles de certaines variables lors de l'exécution du processus.
>Soit le [programme](TP1/Exo1/adresses_virtuelles.c) suivant qui affiche les adresses virtuelles de certaines variables lors de l'exécution du processus.
>En utilisant le (pseudo) fichier `/proc/pid/maps`, vérifiez à quel segment de pages ces adresses appartiennent.
```console
@ -55,7 +55,7 @@ m appartient au heap (564bfd7e6000-564bfd807000)
>L'interface (pseudo-fichier) `proc/pid/smaps` permet de voir la consommation mémoire d'un processus. On peut le formater avec la commande `pmap -X`. 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. Dans les cas suivants, vérifiez où se trouve la memoire correspondante :
1. Allocation statique [buf.c](Exo1/ex1bis/buf.c)
1. Allocation statique [buf.c](TP1/Exo1/ex1bis/buf.c)
```console
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 51
@ -92,7 +92,7 @@ total kB 27036 17936 16612
```
>L'allocation statique de `buf.c` se trouve à l'adresse 000055a1b7221000 et elle est de 24576 Kbytes
2. Allocation sur la pile [stack.c](Exo1/ex1bis/stack.c)
2. Allocation sur la pile [stack.c](TP1/Exo1/ex1bis/stack.c)
```console
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 57
@ -128,7 +128,7 @@ total kB 2460 1392 120
```
>L'allocation sur la pile de `stack.c` se trouve à l'adresse 00007ffdebac4000 et elle est de 132 Kbytes
3. Allocation sur le tas [heap.c](Exo1/ex1bis/heap.c)
3. Allocation sur le tas [heap.c](TP1/Exo1/ex1bis/heap.c)
```console
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 59
@ -165,7 +165,7 @@ total kB 52356 51280 50016
>L'allocation sur le tas de `heap.c` se trouve à l'adresse 000055ac0a4c2000 et elle est de 50028 Kbytes
4. Allocation (gande quantité) sur le tas [huge.c](Exo1/ex1bis/huge.c)
4. Allocation (gande quantité) sur le tas [huge.c](TP1/Exo1/ex1bis/huge.c)
```console
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 61
@ -201,7 +201,7 @@ total kB 2720 1728 456
```
>L'allocation (gande quantité) sur le tas de `huge.c` se trouve à l'adresse 00007f5bb5f2e000 et elle est de 272 Kbytes
5. Allocation sur le mapping [mmap.c](Exo1/ex1bis/mmap.c)
5. Allocation sur le mapping [mmap.c](TP1/Exo1/ex1bis/mmap.c)
```console
tom@Error404:/mnt/c/Users/naser/Documents/scr/TP1/Exo1/ex1bis$ pmap -x 64
@ -241,7 +241,7 @@ total kB 2828 1612 324
## Exercice 2
>Soit le [programme](Exo2/bss_data.c) suivant.
>Soit le [programme](TP1/Exo2/bss_data.c) suivant.
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 ?
>Le tableau `t` se trouve dans le segment `.bss` et la taille de l'exécutable n'a pas changé car le tableau `t` n'est pas initialisé.
@ -251,13 +251,13 @@ total kB 2828 1612 324
>Le tableau `t` se trouve dans le segment `.data` et la taille de l'exécutable a changé car le tableau `t` est initialisé.
## Exercice 3
>Soit le [programme](Exo3/ij_ji.c) suivant.
>Soit le [programme](TP1/Exo3/ij_ji.c) suivant.
>Le temps d'éxecution de ce programme est-il différent pour les deux versions ? Pourquoi ?
>Le temps d'éxecution de ce programme est différent pour les deux versions car dans la première version, les éléments du tableau sont accédés de manière séquentielle, alors que dans la deuxième version, le cache est rempli car on lit les éléments du tableau par colonne, donc il y a plus de cache miss vu qu'on fait des incréments bien plus grands que dans la première version.
## Exercice 4
>Le programme [sum_array.c](Exo4/sum_array.c) fait 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`).
>Le programme [sum_array.c](TP1/Exo4/sum_array.c) fait 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.
>La raison de pourquoi la manière aléatoire est plus lente que la manière croissante ou décroissante (qui sont aussi rapide l'une que l'autre), est que la manière aléatoire fait plus de cache miss que les deux autres, car elle accède aux éléments du tableau de manière aléatoire, donc il y a plus de chance que l'élément ne soit pas dans le cache, alors que dans les deux autres, les éléments sont accédés de manière séquentielle, donc il y a plus de chance que l'élément soit dans le cache. Ce qui force la lecture de la RAM.
@ -285,3 +285,22 @@ XXXXXXXX BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB |CCCCCCCCCCCCCCCC|
>L'alignement en mémoire est conforme à ce que l'on a vu en cours car les adresses sont alignées sur 16 octets.
# TP 2 : Fichiers
## Exercice 1
>Écrire deux versions d'un programme qui copie "octet par octet" un fichier source dans un fichier destination :
`./copy infile outfile`
>en utilisant :
1. les appels systèmes linux : `open`, `read`, `write`, `close`.
2. les fonctions E/S standards (sdtio) : `fopen`, `fread`, `fwrite`, `fclose`.
> Testez vos deux programmes sur un fichier volumineux (utilisez la commande `dd` le pseudo fichier `dev/urandom` pour générer un contenu aléatoire) et expliquez pourquoi le deuxième programme est beaucoup plus rapide que le premier.
>Remarque:
- pour être dans les mêmes conditions, il faut être sur que le fichier à copier n'est pas en cache en mémoire. Générez un nouveau fichier de même taille, ou utilisez le programme [fadvise.c](TP2/Exo1/fadvise.c) qui permet de vider les blocs du cache pour un fichier quelconque.
- utilisez strace pour tracer les appels systèmes de vos deux programmes.
>Le deuxième programme est beaucoup plus rapide que le premier car il utilise des buffers, alors que le premier programme lit et écrit octet par octet et fait plus d'appels systèmes.

155
TP2/Exo1/fadvise.c Normal file
View File

@ -0,0 +1,155 @@
#include <linux/falloc.h>
#include <linux/fadvise.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <asm/unistd_64.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
//#include <linux-ftools.h>
#define LINUX_FTOOLS_VERSION "1.0.0"
/**
SYNTAX: filename mode [offset] [,length]
Where mode can be:
POSIX_FADV_NORMAL No further special treatment.
POSIX_FADV_RANDOM Expect random page references.
POSIX_FADV_SEQUENTIAL Expect sequential page references.
POSIX_FADV_WILLNEED Will need these pages.
POSIX_FADV_DONTNEED Don't need these pages.
POSIX_FADV_NOREUSE Data will be accessed once.
Allows an application to to tell the kernel how it expects to use a file handle,
so that the kernel can choose appropriate read-ahead and caching techniques for
access to the corresponding file. This is similar to the POSIX version of the
madvise system call, but for file access instead of memory access. The
sys_fadvise64() function is obsolete and corresponds to a broken glibc API,
sys_fadvise64_64() is the fixed version. The following are the values for the
advice parameter:
FADV_NORMAL
No special treatment.
FADV_RANDOM
Expect page references in random order.
FADV_SEQUENTIAL
Expect page references in sequential order.
FADV_WILLNEED
Expect access in the near future.
FADV_DONTNEED
Do not expect access in the near future. Subsequent access of pages in this
range will succeed, but will result either in reloading of the memory contents
from the underlying mapped file or zero-fill-in-demand pages for mappings
without an underlying file.
FADV_NOREUSE
Access data only once.
*/
int main(int argc, char *argv[]) {
if ( argc < 3 ) {
fprintf( stderr, "%s version %s\n", argv[0], LINUX_FTOOLS_VERSION );
printf( "SYNTAX: fadvise filename mode [offset] [,length]\n" );
printf( "Where mode can be:\n\n" );
printf( " POSIX_FADV_NORMAL No further special treatment. \n" );
printf( " POSIX_FADV_RANDOM Expect random page references. \n" );
printf( " POSIX_FADV_SEQUENTIAL Expect sequential page references. \n" );
printf( " POSIX_FADV_WILLNEED Will need these pages. \n" );
printf( " POSIX_FADV_DONTNEED Don't need these pages. \n" );
printf( " POSIX_FADV_NOREUSE Data will be accessed once. \n" );
exit( 1 );
}
char* path = argv[1];
char* param_mode = argv[2];
printf( "Going to fadvise %s\n", path );
int flags = O_RDWR;
int fd = open( path, flags );
if ( fd == -1 ) {
perror( NULL );
return 1;
}
struct stat fd_stat ;
if ( fstat( fd, &fd_stat ) < 0 ) {
perror( "Could not stat file: " );
return 1;
}
loff_t offset = 0;
loff_t length = fd_stat.st_size;
if ( argc >= 4 ) {
offset = strtol( argv[3], NULL, 10 );
}
if ( argc >= 5 ) {
length = strtol( argv[4], NULL, 10 );
}
printf( "offset: %ld\n", offset );
printf( "length: %ld\n", length );
int mode = -1;
if ( strcmp( param_mode , "POSIX_FADV_NORMAL" ) == 0 ) {
mode = POSIX_FADV_NORMAL;
} else if ( strcmp( param_mode , "POSIX_FADV_RANDOM" ) == 0 ) {
mode = POSIX_FADV_RANDOM;
} else if ( strcmp( param_mode , "POSIX_FADV_SEQUENTIAL" ) == 0 ) {
mode = POSIX_FADV_SEQUENTIAL;
} else if ( strcmp( param_mode , "POSIX_FADV_WILLNEED" ) == 0 ) {
mode = POSIX_FADV_DONTNEED;
} else if ( strcmp( param_mode , "POSIX_FADV_DONTNEED" ) == 0 ) {
mode = POSIX_FADV_DONTNEED;
} else if ( strcmp( param_mode , "POSIX_FADV_NOREUSE" ) == 0 ) {
mode = POSIX_FADV_NOREUSE;
} else {
printf( "Invalid mode %s\n", param_mode );
exit( 1 );
}
printf( "mode: %s\n", param_mode );
long result = syscall( SYS_fadvise64, fd, offset, length , mode );
if ( result != 0 ) {
if ( result != -1 ) {
errno=result;
perror( "Unable to fadvise" );
} else {
printf( "Unable to fadvise: %ld\n" , result );
}
return 1;
}
printf( "WIN\n" );
close( fd );
return 0;
}

96
TP2/coherence.c Normal file
View File

@ -0,0 +1,96 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/fcntl.h>
#define TESTFILE "coherence-test.txt"
void write_asr_c_pas_bien()
{
FILE* f = fopen(TESTFILE, "w");
fprintf(f, "L'asr, c'est pas bien!\n");
fclose(f);
}
void write_asr_c_bien()
{
FILE* f = fopen(TESTFILE, "w");
fprintf(f, "L'asr, c'est bien!!\n");
fclose(f);
}
void read_using_syscalls()
{
write_asr_c_pas_bien();
// open file descriptor
int fd = open(TESTFILE, O_RDONLY);
// read first 12 bytes
char buf[BUFSIZ];
ssize_t nr1 = read(fd, buf, 12);
assert(nr1 >= 0);
write_asr_c_bien();
// read rest of file, print to stdout
ssize_t nr2 = read(fd, buf + nr1, BUFSIZ - nr1);
close(fd);
fwrite(buf, 1, nr1 + nr2, stdout);
}
void read_using_stdio()
{
write_asr_c_pas_bien();
// open stdio file
FILE* f = fopen(TESTFILE, "r");
// read first 12 bytes
char buf[BUFSIZ];
size_t nr1 = fread(buf, 1, 12, f);
write_asr_c_bien();
// read rest of file, print to stdout
size_t nr2 = fread(buf + nr1, 1, BUFSIZ - nr1, f);
fclose(f);
fwrite(buf, 1, nr1 + nr2, stdout);
}
static void usage()
{
fprintf(stderr, "Usage: ./coherence -l (linux syscalls) or ./coherence -s (stdio)\n");
exit(1);
}
int main(int argc, char** argv)
{
int which = 0;
int opt;
while ((opt = getopt(argc, argv, "ls")) != -1) {
switch (opt) {
case 's':
which = 's';
break;
case 'l':
which = 'l';
break;
default:
usage();
}
}
if (which == 's') {
read_using_stdio();
} else if (which == 'l') {
read_using_syscalls();
} else {
usage();
}
}