1 #include "MonteCarlo.h"
8 #include <curand_kernel.h>
11 #include "cudaTools.h"
15 // Paramètres pour le calcul de pi.
16 const float X_MIN = 0;
17 const float X_MAX = 1;
21 * 1) Chaque thread calcule un résultat intermediaire qu'il va ensuite placer en shared memory.
22 * n: Nombre d'échantillon.
25 void mc_reductionIntraThread(int n, uint* tabSM, curandState* tabGeneratorThread)
27 const int NB_THREAD = Indice1D::nbThread();
28 const int TID = Indice1D::tid();
29 const int TID_LOCAL = Indice1D::tidLocal();
31 curandState& localState = tabGeneratorThread[TID];
33 uint threadResult = 0;
37 // Tire un point aléatoire entre (0,0) et (1,1), voir X_MIN, X_MAX et M.
38 const float x = curand_uniform(&localState);
39 const float y = curand_uniform(&localState);
40 const float fx = sqrtf(1 - x * x);
42 // Si y est sous la courbe alors on le comptabilise.
49 tabSM[TID_LOCAL] = threadResult;
53 * Combine les résultats de 'tabSM' dans 'tabSM[0]'
56 void mc_combine(uint* tabSM, int middle)
58 const int TID_LOCAL = Indice1D::tidLocal();
59 const int NB_THREAD_LOCAL = Indice1D::nbThreadBlock();
64 tabSM[s] += tabSM[s + middle];
70 * 2) La shared memory est réduite, le résultat est placé dans 'tabSM[0]'.
73 void mc_reductionIntraBlock(uint* tabSM)
75 const int TAB_SIZE = blockDim.x;
76 int middle = TAB_SIZE / 2;
80 mc_combine(tabSM, middle);
82 __syncthreads(); // Synchronisation des threads au niveau du bloc.
87 * 3) Le 'tabSM[0]' de chaque bloc est reduit dans 'ptrResult' qui se trouve en global memory.
90 void mc_reductionInterBlock(uint* tabSM, uint* ptrResult)
92 const int TID_LOCAL = Indice1D::tidLocal();
95 atomicAdd(ptrResult, tabSM[0]);
100 * La taille de la shared memory (en terme de # de sizeof(uint)) doit
101 * être égal à la taille des blocs.
102 * n: le nombre de point à tiré aléatoirement.
103 * ptrResult: Le resultat du calcul.
104 * tabGeneratorThread: les generateurs aléatoires
107 void monteCarlo(int n, uint* ptrResult, curandState* tabGeneratorThread)
109 extern __shared__ uint tabSM[]; // Dynamic shared memory.
111 // 1) Réduction intra-thread.
112 mc_reductionIntraThread(n, tabSM, tabGeneratorThread);
116 // 2) Réduction intra-block.
117 mc_reductionIntraBlock(tabSM);
119 // 3) Réduction inter-block.
120 mc_reductionInterBlock(tabSM, ptrResult);
124 void setupKernelRand(curandState* tabGeneratorThread, int deviceId)
126 int tid = Indice1D::tid();
127 int deltaSeed = deviceId * INT_MAX;
128 int deltaSequence = deviceId * 100;
129 int deltaOffset = deviceId * 100;
131 int seed = 1234 + deltaSeed;
132 int sequenceNumber = tid + deltaSequence;
133 int offset = deltaOffset;
134 curand_init(seed, sequenceNumber, offset, &tabGeneratorThread[tid]);
139 cout << endl << "monteCarlo() ..." << endl;
141 // Nombre de point total tiré aléatoirement.
142 const int N = 1000000;
144 // Allocation coté GPU en global memory (GM).
146 HANDLE_ERROR(cudaMalloc(&ptrDevResult, sizeof(uint)));
147 HANDLE_ERROR(cudaMemset(ptrDevResult, 0, sizeof(uint)));
149 // Paramètre de l'appel de la fonction sur le device.
150 const dim3 dg(256, 1, 1);
151 const dim3 db(256, 1, 1);
152 Device::assertDim(dg, db);
153 const size_t SMSize = db.x * sizeof(uint); // 256 uint;
155 // Gestion des générateurs aléatoires (un par thread).
156 curandState* tabGeneratorThread;
157 HANDLE_ERROR(cudaMalloc(&tabGeneratorThread, db.x * dg.x * sizeof(curandState)));
158 setupKernelRand<<<dg, db>>>(tabGeneratorThread, 0); // Device 0 (à utilise si utilisation en MP).
159 cudaDeviceSynchronize();
161 monteCarlo<<<dg, db, SMSize>>>(N, ptrDevResult, tabGeneratorThread);
163 // cudaDeviceSynchronize(); // Utilisé pour flusher les prints sur le stdout à partir du device (debug).
166 // Barrière implicite de synchronisation ('cudaMemCpy').
167 HANDLE_ERROR(cudaMemcpy(&nb, ptrDevResult, sizeof(uint), cudaMemcpyDeviceToHost));
169 double integrale = (double)nb / (double)N * (X_MAX - X_MIN) * M;
170 double pi = 4 * integrale;
173 cout << "Approximation de PI : " << pi << endl;