source: CIVL/examples/messagePassing/diffusion1d_good.cvl@ 912b60d

1.23 2.0 main test-branch
Last change on this file since 912b60d was 6618f10, checked in by Stephen Siegel <siegel@…>, 12 years ago

Minor modifications to diffusion1d_good.cvl.

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@775 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[dd57b13]1/* Composite model of sequential and parallel 1d-diffusion solvers.
2 * Compares the results of the sequential and parallel computation to
3 * determine functional equivalence of the two versions.
4 *
5 * The initial values are taken as inputs. The two global boundary
6 * points are fixed.
7 *
8 * Command line example:
[6618f10]9 *
10 * civl verify -inputNPROCSB=3 -inputNSTEPSB=3 \
11 -inputNXB=6 diffusion1d_good.cvl
[dd57b13]12 */
13#include<civlc.h>
14#include<stdio.h>
15#include<stdlib.h>
16#include<assert.h>
17
18// Definitions from programs:
19#define OWNER(index) ((nprocs*(index+1)-1)/nx)
20
21// inputs:
22$input int NPROCS; // number of processes for parallel version
23$input int NPROCSB; // upper bound on nprocs
24$input double K; // k = alpha^2 * dt/(dx^2)
25$input int NSTEPS; // number of time steps
26$input int WSTEP; // write every this many time steps
27$input int NSTEPSB; // upperbound on nsteps
28$input int NX; // global number of discrete spatial points
29$input int NXB; // upper bound on nx
30$input double u_init[NX]; // initial values for temperature (u)
31
32// assumptions:
33$assume 2 <= NX && NX <= NXB;
34$assume K>0 && K<.5;
35$assume NSTEPS >= 1;
[6618f10]36$assume WSTEP >= 1 && WSTEP <= NSTEPS;
37// $assume NX >= NPROCS;
38$assume 1 <= NPROCS && NPROCS <= NPROCSB;
39$assume 1 <= NSTEPS && NSTEPS <= NSTEPSB;
[dd57b13]40
41// global variables:
42int output_seq[NX]; // final (color) result of sequential computation
43int output_par[NX]; // final (color) result of parallel computation
44$proc procs[NPROCS]; // the MPI processes
45$gcomm MPI_GCOMM_WORLD; // the global communicator object
46
47// MPI model:
48
49typedef enum {MPI_INT, MPI_DOUBLE} MPI_Datatype;
50#define BCAST_TAG 999
51#define MPI_PROC_NULL -1
52
53typedef struct {
54 int size;
55 int source;
56 int tag;
57} MPI_Status;
58
59#define MPI_STATUS_IGNORE NULL
60
61int sizeofDatatype(MPI_Datatype datatype) {
62 switch (datatype) {
63 case MPI_INT:
64 return sizeof(int);
65 case MPI_DOUBLE:
66 return sizeof(double);
67 default:
68 $assert(0, "Unreachable");
69 }
70}
71
72/* Sends a message. */
73void MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,
74 int tag, $comm comm) {
75 if (dest >= 0) {
76 int size = count*sizeofDatatype(datatype);
77 $message out =
78 $message_pack(comm->place, dest, tag, buf, size);
79
80 $comm_enqueue(comm, out);
81 }
82}
83
84/* Receives a message. */
85void MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source,
86 int tag, $comm comm, MPI_Status *status) {
87 if (source >= 0) {
88 $message in = $comm_dequeue(comm, source, tag);
89 int size = count*sizeofDatatype(datatype);
90
91 $message_unpack(in, buf, size);
92 if (status != MPI_STATUS_IGNORE) {
93 status->size = $message_size(in);
94 status->source = $message_source(in);
95 status->tag = $message_tag(in);
96 }
97 }
98}
99
100void MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count) {
101 *count = status->size/sizeofDatatype(datatype);
102}
103
104void MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
105 int dest, int sendtag,
106 void *recvbuf, int recvcount, MPI_Datatype recvtype,
107 int source, int recvtag,
108 $comm comm, MPI_Status *status) {
109 MPI_Send(sendbuf, sendcount, sendtype, dest, sendtag, comm);
110 MPI_Recv(recvbuf, recvcount, recvtype, source, recvtag, comm, status);
111}
112
113/* Broadcasts a message from root to everyone else.
114 * Need to use a differnt comm.
115 */
116void MPI_Bcast(void *buf, int count, MPI_Datatype datatype, int root,
117 $comm comm) {
118 int place = $comm_place(comm);
119
120 if (place == root) {
121 int nprocs = $comm_size(comm);
122
123 for (int i=0; i<nprocs; i++)
124 if (i != root)
125 MPI_Send(buf, count, datatype, i, BCAST_TAG, comm);
126 } else {
127 MPI_Recv(buf, count, datatype, root, BCAST_TAG, comm, MPI_STATUS_IGNORE);
128 }
129}
130
131/* Abstract function representing conversion from temperature to color */
132//$abstract int colorOf(double x);
133int colorOf(double x) { return (int)x; }
134
135/* Sequential algorithm: performs simulation storing result of final
136 * time step in output_seq */
137void main_seq() {
138 $scope seq_scope = $here;
139 int nx, nsteps, wstep;
140 double k, *u;
141
142 void init() {
143 int i;
144 int pos = 0; // file position
145
146 // in place of reading these from file:
147 nx = NX;
148 nsteps = NSTEPS;
149 wstep = WSTEP;
150 k = K;
[6618f10]151 printf("Diffusion1d (seq) with nx=%d, k=%f, nsteps=%d, wstep=%d\n",
[dd57b13]152 nx, k, nsteps, wstep);
153 assert(nx>=2);
154 assert(k>0 && k<.5);
155 assert(nsteps >= 1);
156 assert(wstep >= 1 && wstep <=nsteps);
157 u = (double*)$malloc(seq_scope, nx*sizeof(double));
158 assert(u);
159 for (i = 0; i < nx; i++) u[i] = u_init[pos++];
160 }
161
162 void write_frame(int time) {
163 for (int i=0; i<nx; i++)
164 output_seq[i] = colorOf(u[i]);
165 }
166
167 void update() {
168 int i;
169 double u_new[nx];
170
171 for (i = 1; i < nx-1; i++)
172 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
173 for (i = 1; i < nx-1; i++)
174 u[i] = u_new[i];
175 }
176
177 // main body starts here:
178 init();
179 write_frame(0);
180 for (int iter = 1; iter <= nsteps; iter++) {
181 update();
182 if (iter%wstep==0) write_frame(iter);
183 }
184 free(u);
185}
186
187/* MPI Process in parallel algorithm */
188void MPI_Process (int rank) {
189 $scope proc_scope = $here; /* this scope */
190 int nx, nsteps, wstep, nprocs;
191 double k;
192 $comm MPI_COMM_WORLD; /* the MPI communicator */
193 double *u; /* temperature function */
194 double *u_new; /* temp. used to update u */
195 int left; /* rank of left neighbor */
196 int right; /* rank of right neighbor on torus */
197 int nxl; /* horizontal extent of one process */
198 int first; /* global index for local index 0 */
199 int start; /* first local index to update */
200 int stop; /* last local index to update */
201 double *buf; /* temp. buffer used on proc 0 only */
202
203 int firstForProc(int rank) {
204 return (rank*nx)/nprocs;
205 }
206
207 int countForProc(int rank) {
208 int a;
209 int b;
210
211 a = firstForProc(rank+1);
212 b = firstForProc(rank);
213 return a-b;
214 }
215
216 /* init: initializes global variables. */
217 void init() {
218 int i, j;
219 int pos = 0; // position in input file
220
221 nprocs = NPROCS;
222 if (rank == 0) {
223 // in place of reading these from file:
224 nx = NX;
225 k = K;
226 nsteps = NSTEPS;
227 wstep = WSTEP;
[6618f10]228 printf("Diffusion1d (par) with nx=%d, k=%f, nsteps=%d, wstep=%d nprocs=%d\n",
[dd57b13]229 nx, k, nsteps, wstep, nprocs);
230 }
231 MPI_Bcast(&nx, 1, MPI_INT, 0, MPI_COMM_WORLD);
232 MPI_Bcast(&k, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
233 MPI_Bcast(&nsteps, 1, MPI_INT, 0, MPI_COMM_WORLD);
234 MPI_Bcast(&wstep, 1, MPI_INT, 0, MPI_COMM_WORLD);
[6618f10]235 // assert(nx>=nprocs);
[dd57b13]236 assert(k>0 && k<.5);
237 assert(nx>=2);
238 assert(nsteps>=1);
239 first = firstForProc(rank);
240 nxl = countForProc(rank);
241 if (first == 0 || nxl == 0)
242 left = MPI_PROC_NULL;
243 else
244 left = OWNER(first-1);
245 if (first+nxl >= nx || nxl == 0)
246 right = MPI_PROC_NULL;
247 else
248 right = OWNER(first+nxl);
249 u = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double));
250 assert(u != NULL);
251 u_new = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double));
252 assert(u_new != NULL);
253 if (rank == 0) {
254 buf = (double*)$malloc(proc_scope, (1+nx/nprocs)*sizeof(double));
255 for (i=1; i <= nxl; i++)
256 u[i] = u_init[pos++]; // instead of reading from file
257 for (i=1; i < nprocs; i++) {
258 int count_i = countForProc(i);
259
260 for (j=0; j<count_i; j++)
261 buf[j] = u_init[pos++];
262 MPI_Send(buf, count_i, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
263 }
264 }
265 else {
266 buf = NULL;
267 MPI_Recv(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
268 }
269 if (rank == OWNER(0)) {
270 start = 2;
271 }
272 else {
273 start = 1;
274 }
275 if (rank == OWNER(nx-1)) {
276 stop = nxl - 1;
277 }
278 else {
279 stop = nxl;
280 }
281 }
282
283 void write_frame(int time) {
284 if (rank != 0) {
285 MPI_Send(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
286 } else {
287 int source, i, j, count, global_index;
288 MPI_Status status;
289
290 global_index = 0;
291 for (source = 0; source < nprocs; source++) {
292 if (source != 0) {
293 MPI_Recv(buf, 1+nx/nprocs, MPI_DOUBLE, source, 0,
294 MPI_COMM_WORLD, &status);
295 MPI_Get_count(&status, MPI_DOUBLE, &count);
296 } else {
297 for (i = 1; i <= nxl; i++) buf[i-1] = u[i];
298 count = nxl;
299 }
300 for (i = 0; i < count; i++) {
301 output_par[global_index] = colorOf(buf[i]);
302 global_index++;
303 }
304 }
305 }
306 }
307
308 /* exchange_ghost_cells: updates ghost cells using MPI communication */
309 void exchange_ghost_cells() {
310 MPI_Sendrecv(&u[1], 1, MPI_DOUBLE, left, 0,
311 &u[nxl+1], 1, MPI_DOUBLE, right, 0,
312 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
313 MPI_Sendrecv(&u[nxl], 1, MPI_DOUBLE, right, 0,
314 &u[0], 1, MPI_DOUBLE, left, 0,
315 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
316 }
317
318 /* update: updates u. Uses ghost cells. Purely local operation. */
319 void update() {
320 int i;
321
322 for (i = start; i <= stop; i++)
323 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
324 for (i = start; i <= stop; i++)
325 u[i] = u_new[i];
326 }
327
328 // body of MPI Process procedure starts here:
329 MPI_COMM_WORLD = $comm_create($here, MPI_GCOMM_WORLD, rank);
330 init();
331 write_frame(0);
332 for (int iter = 1; iter <= nsteps; iter++) {
333 exchange_ghost_cells();
334 update();
335 if (iter%wstep==0) write_frame(iter);
336 }
337 free(u);
338 free(u_new);
339 if (rank == 0)
340 free(buf);
341 $comm_destroy(MPI_COMM_WORLD);
342}
343
344void main_par() {
345 MPI_GCOMM_WORLD = $gcomm_create($root, NPROCS);
346 for (int i=0; i<NPROCS; i++) procs[i] = $spawn MPI_Process(i);
347 for (int i=0; i<NPROCS; i++) $wait(procs[i]);
348 $gcomm_destroy(MPI_GCOMM_WORLD);
349}
350
351void main() {
[6618f10]352 for (int i=0; i<NX; i++) ;
353 for (int i=0; i<NSTEPS; i++) ;
354 for (int i=0; i<WSTEP; i++) ;
355 for (int i=0; i<NPROCS; i++) ;
[dd57b13]356 main_seq();
357 main_par();
[6618f10]358 for (int i=0; i<NX; i++) {
359 printf("output[%d] = %d\n", i, output_seq[i]);
[dd57b13]360 $assert(output_seq[i]==output_par[i]);
[6618f10]361 }
[dd57b13]362}
Note: See TracBrowser for help on using the repository browser.