Bonjour,
j'ai développé, en reprenant un programme fait pour tourner sur 2 coeurs, une petite apllication du calcul de pi en essayant de le généraliser à un nombre quelconque de threads (à condition d'avoir le rapport (nombre d'itérations/nombre de thread) entier ).
Le code original (pour 2 coeurs) est le suivant :
On se sert du fork() pour que chaque thread génère (n_iterations/2) nombres aléatoires.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 /* parallel computation of pi with monte carlo method */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/wait.h> #include <sys/time.h> #define SEED 35791246 struct sharedMem { double child_p_in; }; int main (int argc, char** argv) { double parent_p_in; // number of hits inside the circle double niter; // total number of hits int fd; int i; double x,y,z,pi; struct sharedMem* smem; struct timeval chrono1, chrono2; int micro, second; pid_t pid; // parse the second argument if (argc != 2) { printf ("Please, specify interval number\n"); exit (1); } niter = (double) atoi(argv[1]); // create the shared memory fd = open ("/tmp/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) exit(2); if (ftruncate (fd, sizeof (struct sharedMem)) == -1) exit(3); smem = mmap (NULL, sizeof (struct sharedMem), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (smem == MAP_FAILED) exit(1); srand(SEED); // initialize random numbers gettimeofday(&chrono1, NULL); // monte carlo's method in parallel pid = fork(); if (pid < 0) exit(4); else if (pid == 0) { // child process // compute the first half of niter hits smem->child_p_in = 0; for (i=0; i<(niter/2); i++) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; z = x*x + y*y; if (z <= 1.0) smem->child_p_in++; } exit(0); } else { // parent process // compute the second half of niter hits parent_p_in = 0; for (i=(niter/2); i<niter; i++) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; z = x*x + y*y; if (z <= 1.0) parent_p_in++; } wait(NULL); // wait for child } gettimeofday(&chrono2, NULL); // munmap(smem, sizeof(struct sharedMem)); close(fd); // compute ellapsed time micro = chrono2.tv_usec - chrono1.tv_usec; if (micro < 0) { micro += 1000000; second = chrono2.tv_sec - chrono1.tv_sec - 1; } else second = chrono2.tv_sec - chrono1.tv_sec; pi = (parent_p_in + smem->child_p_in)/niter; pi *= 4; // special format fot limted niter parameter < 10e9 printf("# of trials= %d , estimate of pi is %f \n",(int) niter,pi); printf("%d second %d micro ellapsed\n", second, micro); return 0; }
A l'exécution, ce programme tourne effectivement sur 2 coeurs.
Pour le généraliser, j'ai codé une fonction récursive qui par exemple, pour un nombre de thread "nb_thread" égale à 4, va utiliser 2 fork(). Je récupère le nombre de thread et le nombre d'itérations en paramètres de l'exécutable.
Voici la procédure récursive :
Pour créer la mémoire partagée, j'utilise comme pour l'algo original :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 /* parallel computation of pi with monte carlo method */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/wait.h> #include <sys/time.h> #define SEED 35791246 struct sharedMem { double j[100]; }; struct sharedMem* Parallel( struct sharedMem* smem, pid_t* pid, int nbt, long int niter, int statut, int options, int nb_current ) { double x,y,z; long int i; if (nbt==1) { smem->j[nb_current]=0; for (i=0; i<(niter/nbt); i++) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; z = x*x + y*y; if (z <= 1.0) {smem->j[nb_current]++;}} return smem; } else if (nb_current==(nbt-1)) return smem; else { pid[nb_current]=fork(); if (pid[nb_current] < 0) exit(4); else if (pid[nb_current]==0) {// child process // compute the niter/nbt part of niter hits smem->j[nb_current]=0; for (i=0; i<(niter/nbt); i++) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; z = x*x + y*y; if (z <= 1.0) {smem->j[nb_current]++;}} exit(0); } else { // parent process // compute the niter/nbt part of niter hits smem->j[nb_current+1] = 0; for (i=0; i<(niter/nbt); i++) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; z = x*x + y*y; if (z <= 1.0) smem->j[nb_current+1]++; } waitpid(pid[nb_current],&statut,options); return Parallel(smem,pid,nbt,niter,statut,options,nb_current+1); } exit(0); } } .....
et avec l'appel de la fonction récursive :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 // create the shared memory fd = open ("/tmp/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) exit(2); if (ftruncate (fd, sizeof (struct sharedMem)) == -1) exit(3); smem = mmap (NULL, sizeof (struct sharedMem), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (smem == MAP_FAILED) exit(1);
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 // recursive function smem=Parallel(smem,pid,nb_thread,niter,statut,options,nb_current);
Mais voilà, le problème est qu'à l'exécution, pour un nombre de processus supérieur à 2 et inférieur ou égal à 8 (j'ai un processeur 8 cores), le programme ne tourne pas sur le nombre de cores correspondant ( vérifié grâce à la commande "htop" ou "ps aux | grep a.out" ) :
Pour nb_thread=4, j'aimerais qu'il tourne sur 4, pour 6, sur 6 ...
Il donne bien le résultat attendu, à savoir une estimation de pi, d'autant plus précise que le nombre d'itérations est grand,
Mais pourquoi ne tourne t-il pas sur le nombre de coeurs attendu comme j'aimerais (du moins pour nb_thread compris entre 4 et 8) ?
Est-ce que ceci est du au fait que je fait le fork() dans une fonction et non dans le "main" ?
Si quelqu'un pouvait m'aider à voir plus clair,
Merci d'avance.
Partager