source: CIVL/src/include/civl/civl-mpi.cvl@ a31b866

1.23 2.0 acw/focus-triggers main test-branch
Last change on this file since a31b866 was d3a475f, checked in by Ziqing Luo <ziqing@…>, 11 years ago

fix send to self problem in implementations and the bug in reduceScatter.c

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

  • Property mode set to 100644
File size: 14.1 KB
Line 
1#ifdef __CIVL_CIVLMPI__
2#else
3#define __CIVL_CIVLMPI__
4
5#include <civlc.cvh>
6#include <concurrency.cvh>
7#include <comm.cvh>
8#include <bundle.cvh>
9#include <mpi.h>
10#include <civl-mpi.cvh>
11#include <string.h>
12#include <pointer.cvh>
13
14/**************************** Duplicated Part *************************************/
15/* Duplicated definition with the same struct in mpi.h.
16 The reason of this duplication is to make civlmpi.cvl
17 independent with mpi.cvl. */
18typedef struct MPI_Comm {
19 $comm p2p; // point-to-point communication
20 $comm col; // collective communication
21 $collect_checker collect_checker;
22 $barrier barrier;
23}MPI_Comm;
24
25/* Definition of CMPI_Gcomm (CMPI_Gcomm has a type of __CMPI_Gcomm)
26 and MPI_Comm */
27struct CMPI_Gcomm {
28 $gcomm p2p; // point-to-point communication
29 $gcomm col; // collective communication
30 $gcollect_checker collect_checker;
31 $gbarrier gbarrier;
32};
33
34/****************************** Helper Functions **********************************/
35int sizeofDatatype(MPI_Datatype datatype) {
36 switch (datatype) {
37 case MPI_INT:
38 return sizeof(int);
39 case MPI_2INT:
40 return (sizeof(int)*2);
41 case MPI_FLOAT:
42 return sizeof(float);
43 case MPI_DOUBLE:
44 return sizeof(double);
45 case MPI_CHAR:
46 return sizeof(char);
47 case MPI_BYTE:
48 return sizeof(char); // char is always one byte ?
49 case MPI_SHORT:
50 return sizeof(short);
51 case MPI_LONG:
52 return sizeof(long);
53 case MPI_LONG_DOUBLE:
54 return sizeof(long double);
55 case MPI_LONG_LONG_INT:
56 return sizeof(long long int);
57 case MPI_LONG_LONG:
58 return sizeof(long long);
59 case MPI_UNSIGNED_LONG_LONG:
60 return sizeof(unsigned long long);
61 default:
62 $assert(0, "Unreachable");
63 }
64}
65
66/************************** MPI LIB Implementations *******************************/
67CMPI_Gcomm CMPI_Gcomm_create($scope scope, int size) {
68 CMPI_Gcomm result;
69
70 result.p2p = $gcomm_create(scope, size);
71 result.col = $gcomm_create(scope, size);
72 result.collect_checker = $gcollect_checker_create(scope);
73 result.gbarrier = $gbarrier_create(scope, size);
74 return result;
75}
76
77void CMPI_Gcomm_destroy(CMPI_Gcomm gc) {
78 $gcomm_destroy(gc.p2p);
79 $gcomm_destroy(gc.col);
80 $gcollect_checker_destroy(gc.collect_checker);
81 $gbarrier_destroy(gc.gbarrier);
82}
83
84MPI_Comm CMPI_Comm_create($scope scope, CMPI_Gcomm gc, int rank) {
85 MPI_Comm result;
86
87 result.p2p = $comm_create(scope, gc.p2p, rank);
88 result.col = $comm_create(scope, gc.col, rank);
89 result.collect_checker = $collect_checker_create(scope, gc.collect_checker);
90 result.barrier = $barrier_create(scope, gc.gbarrier, rank);
91 return result;
92}
93
94void CMPI_Comm_destroy(MPI_Comm comm) {
95 __MPI_Sys_status__ curr_status;
96
97 curr_status = CMPI_Get_status();
98 $assert(curr_status == __FINALIZED, "Process terminates without "
99 "calling MPI_Finalize() first.");
100 $comm_destroy(comm.p2p);
101 $comm_destroy(comm.col);
102 $collect_checker_destroy(comm.collect_checker);
103 $barrier_destroy(comm.barrier);
104}
105
106int _MPI_Init(void) {
107 CMPI_Set_status(__INIT);
108 return 0;
109}
110
111int _MPI_Finalize(void) {
112 CMPI_Set_status(__FINALIZED);
113 return 0;
114}
115
116void * CMPI_PointerAdd(const void * ptr, int offset, MPI_Datatype datatype) {
117 int type_size = sizeofDatatype(datatype);
118
119 return $pointer_add(ptr, offset, type_size);
120}
121
122/********************* Lower level MPI routines *********************/
123/* CMPI_Send and CMPI_Recv are a pair of send receives functions that
124 help implementing MPI routines. They should never be block which
125 means no potential deadlocks related to these functions */
126int CMPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,
127 int tag, $comm comm) {
128 if (dest >= 0) {
129 int size = count*sizeofDatatype(datatype);
130 int place = $comm_place(comm);
131 $message out = $message_pack(place, dest, tag, buf, size);
132 $comm_enqueue(comm, out);
133 }
134 return 0;
135}
136
137int CMPI_Recv(void *buf, int count, MPI_Datatype datatype, int source,
138 int tag, $comm comm, MPI_Status *status) {
139 if (source >= 0 || source == MPI_ANY_SOURCE) {
140 $message in = $comm_dequeue(comm, source, tag);
141 int size = count*sizeofDatatype(datatype);
142
143 $message_unpack(in, buf, size);
144 if (status != MPI_STATUS_IGNORE) {
145 status->size = $message_size(in);
146 status->MPI_SOURCE = $message_source(in);
147 status->MPI_TAG = $message_tag(in);
148 status->MPI_ERROR = 0;
149 }
150 }
151 return 0;
152}
153
154/********************* Collective helper functions ********************/
155/* Note: collective helpers functions are functions have same
156 behaviors as MPI collective functions, it can be re-used as a part
157 of implementation by different MPI routines. For example,
158 MPI_Allreduce will call CMPI_Reduce and CMPI_Bcast, both of them
159 should throw errors (if encounters any) as if errors are thrown
160 from MPI_Allreduce.
161*/
162int CMPI_Collective_recv(void *buf, int count, MPI_Datatype datatype,
163 int source, int tag, $comm comm,
164 MPI_Status * status, char * routName) {
165 if(source >= 0 || source == MPI_ANY_SOURCE) {
166 $message in = $comm_dequeue(comm, source, MPI_ANY_TAG);
167 int size = count*sizeofDatatype(datatype);
168 int recvTag;
169
170 recvTag = $message_tag(in);
171 $assert (recvTag == tag , "Collective routine %s receives a "
172 "message with a mismatched tag\n", routName);
173 $message_unpack(in, buf, size);
174 if (status != MPI_STATUS_IGNORE) {
175 status->size = $message_size(in);
176 status->MPI_SOURCE = $message_source(in);
177 status->MPI_TAG = recvTag;
178 status->MPI_ERROR = 0;
179 }
180 }
181 return 0;
182}
183
184/* Broadcast helper function that uses any specified message tag */
185int CMPI_Bcast(void *buf, int count, MPI_Datatype datatype, int root, int tag,
186 MPI_Comm comm, char * routName) {
187 if ($comm_place(comm.col) == root) {
188 int nprocs = $comm_size(comm.col);
189
190 for (int i=0; i<nprocs; i++)
191 if (i != root)
192 CMPI_Send(buf, count, datatype, i, tag, comm.col);
193 } else
194 CMPI_Collective_recv(buf, count, datatype, root, tag, comm.col,
195 MPI_STATUS_IGNORE, routName);
196 return 0;
197}
198
199/* Reduction helper function that uses any specified message tag */
200int CMPI_Reduce(const void* sendbuf, void* recvbuf, int count,
201 MPI_Datatype datatype, MPI_Op op, int root, int tag,
202 MPI_Comm comm, char * routName) {
203 int rank;
204
205 rank = $comm_place(comm.col);
206 if (rank != root)
207 CMPI_Send(sendbuf, count, datatype, root, tag, comm.col);
208 else {
209 int nprocs = $comm_size(comm.col);
210 int size;
211
212 size = count * sizeofDatatype(datatype);
213 memcpy(recvbuf, sendbuf, size);
214 for (int i = 0; i<nprocs; i++) {
215 if(i != root){
216 int colTag;
217 $message in = $comm_dequeue(comm.col, i, MPI_ANY_TAG);
218
219 colTag = $message_tag(in);
220 $assert (colTag == tag , "Collective routine %s receives a "
221 "message with a mismatched tag\n", routName);
222 /* the third argument "count" indicates the number of cells needs doing the
223 operation. */
224 $bundle_unpack_apply(in.data, recvbuf, count, op);
225 $assert (in.size <= size ,
226 "Message of size %d exceeds the specified size %d.", in.size, size);
227 }
228 }
229 }
230 return 0;
231}
232
233/* Gathering helper function that uses any specified message tag */
234int CMPI_Gather(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
235 void* recvbuf, int recvcount, MPI_Datatype recvtype,
236 int root, int tag, MPI_Comm comm, char * routName){
237 int rank, nprocs;
238 MPI_Status status;
239
240 rank = $comm_place(comm.col);
241 nprocs = $comm_size(comm.col);
242 /* MPI standard requirement:
243 * For root process, sendtype must be equal to
244 * recvtype. */
245 if(rank == root)
246 $assert (sendtype == recvtype,
247 "%s asks for equality "
248 "between 'sendtype' and 'recvtype'.", routName);
249 /* MPI_standard requirement:
250 * Only root process can use MPI_IN_PLACE*/
251 if(sendbuf == MPI_IN_PLACE){
252 $assert (root == rank,
253 "Only root can replace 'sendbuf' with 'MPI_IN_PLACE'.");
254 } else if(root == rank) {
255 void * ptr;
256
257 $assert(sendcount == recvcount, "Root process of routine %d without using"
258 " MPI_IN_PLACE should give the same value for recvcount and sendcount",
259 routName);
260 ptr = CMPI_PointerAdd(recvbuf, root * recvcount, recvtype);
261 memcpy(ptr, sendbuf, recvcount * sizeofDatatype(recvtype));
262 } else
263 CMPI_Send(sendbuf, sendcount, sendtype, root, tag, comm.col);
264 /* Root process receives messages and put them in right places */
265 if(rank == root){
266 int real_recvcount;
267 int offset;
268
269 for(int i=0; i<nprocs; i++){
270 if(i != root) {
271 void * ptr;
272
273 offset = i * recvcount;
274 ptr = CMPI_PointerAdd(recvbuf, offset, recvtype);
275 CMPI_Collective_recv(ptr, recvcount, recvtype,
276 i, tag, comm.col, &status, routName);
277 real_recvcount = status.size/sizeofDatatype(recvtype);
278 $assert(real_recvcount == recvcount,
279 "%s asks for equality between"
280 " the amount of data sent and the "
281 "amount of data received.", routName);
282 }
283 }
284 }
285 return 0;
286}
287
288int CMPI_Gatherv(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
289 void* recvbuf, const int recvcounts[], const int displs[],
290 MPI_Datatype recvtype, int root, int tag,
291 MPI_Comm comm, char * routName){
292 int rank, nprocs;
293
294 rank = $comm_place(comm.col);
295 nprocs = $comm_size(comm.col);
296 /* MPI standard requirement:
297 * For root process, sendtype must be equal to
298 * recvtype. */
299 if(rank == root)
300 $assert(sendtype == recvtype, "%s asks for equality "
301 "between 'sendtype' and 'recvtype'.", routName);
302 /* MPI_standard requirement:
303 * Only root process can use MPI_IN_PLACE*/
304 if(sendbuf == MPI_IN_PLACE){
305 $assert(root == rank, "Only root can replace 'sendbuf' with 'MPI_IN_PLACE'.");
306 }else if(root == rank) {
307 void * ptr;
308
309 $assert(sendcount == recvcounts[root], "For routine %s, recvcounts[%d] "
310 "should be same as the sendcount of the process with rank %d.\n",
311 routName, root, root);
312 ptr = CMPI_PointerAdd(recvbuf, displs[rank], recvtype);
313 memcpy(ptr, sendbuf, sendcount * sizeofDatatype(recvtype));
314 }else{
315 CMPI_Send(sendbuf, sendcount, sendtype, root, tag, comm.col);
316 }
317 /* Root process receives messages and put them in right places */
318 if(rank == root){
319 int real_recvcount;
320 MPI_Status status;
321
322 for(int i=0; i<nprocs; i++){
323 if(i != root){
324 void * ptr = CMPI_PointerAdd(recvbuf, displs[i], recvtype);
325
326 CMPI_Collective_recv(ptr, recvcounts[i],
327 recvtype, i, tag, comm.col, &status, routName);
328 real_recvcount = status.size/sizeofDatatype(recvtype);
329 $assert(real_recvcount == recvcounts[i], "%s asks for equality between"
330 " the amount of data sent and the "
331 "amount of data received.", routName);
332 }
333 }
334 }
335 return 0;
336}
337
338/* Scatter helper function that uses any specified message tag */
339int CMPI_Scatter(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
340 void* recvbuf, int recvcount, MPI_Datatype recvtype, int root,
341 int tag, MPI_Comm comm, char * routName){
342 int rank, nprocs;
343
344 rank = $comm_place(comm.col);
345 nprocs = $comm_size(comm.col);
346 /* MPI standard requirement:
347 * For root process, sendtype must be equal to
348 * recvtype. */
349 if(rank == root)
350 $assert(sendtype == recvtype, "MPI_Scatter() asks for equality "
351 "between 'sendtype' and 'recvtype'.");
352 /* MPI_standard requirement:
353 * Only root process can use MPI_IN_PLACE */
354 if(recvbuf == MPI_IN_PLACE){
355 $assert(root == rank, "Only root can replace 'recvbuf' with 'MPI_IN_PLACE'.");
356 }else if(rank == root) {
357 void * ptr;
358
359 $assert(sendcount == recvcount, "Root process of routine %d without using"
360 " MPI_IN_PLACE should give the same value for recvcount and sendcount",
361 routName);
362 ptr = CMPI_PointerAdd(sendbuf, root*recvcount, sendtype);
363 memcpy(recvbuf, ptr, sizeofDatatype(recvtype)*recvcount);
364 }
365 /* Root process scatters data to other processes */
366 if(rank == root){
367 int offset;
368
369 for(int i=0; i<nprocs; i++){
370 if(i != root) {
371 void * ptr;
372
373 offset = i * sendcount;
374 ptr = CMPI_PointerAdd(sendbuf, offset, sendtype);
375 CMPI_Send(ptr, sendcount, sendtype, i, tag, comm.col);
376 }
377 }
378 }
379 /* Non-root processes receive data */
380 if(!(root == rank)){
381 int real_recvcount;
382 MPI_Status status;
383
384 CMPI_Collective_recv(recvbuf, recvcount, recvtype,
385 root, tag, comm.col, &status, routName);
386 real_recvcount = status.size/sizeofDatatype(recvtype);
387 $assert(real_recvcount == recvcount,
388 "%s asks for equality between"
389 " the amount of data sent and the "
390 "amount of data received.", routName);
391 }
392 return 0;
393}
394
395/* Scatterv helper function that uses any specified message tag */
396int CMPI_Scatterv(const void* sendbuf, const int sendcounts[], const
397 int displs[], MPI_Datatype sendtype, void* recvbuf,
398 int recvcount, MPI_Datatype recvtype, int root, int tag,
399 MPI_Comm comm, char * routName){
400 int rank, nprocs;
401
402 rank = $comm_place(comm.col);
403 nprocs = $comm_size(comm.col);
404 /* MPI standard requirement:
405 * For root process, sendtype must be equal to
406 * recvtype. */
407 if(rank == root)
408 $assert(sendtype == recvtype, "%s asks for equality "
409 "between 'sendtype' and 'recvtype'.", routName);
410 /* MPI_standard requirement:
411 * Only root process can use MPI_IN_PLACE */
412 if(recvbuf == MPI_IN_PLACE){
413 $assert(root == rank, "Only root can replace 'recvbuf' with 'MPI_IN_PLACE'.");
414 } else if(rank == root) {
415 void * ptr;
416
417 $assert(sendcounts[root] == recvcount, "For routine %s, sendcounts[%d] "
418 "should be same as the recvcount of the process with rank %d.\n",
419 routName, root, root);
420 ptr = CMPI_PointerAdd(sendbuf, displs[root], sendtype);
421 memcpy(recvbuf, ptr, recvcount*sizeofDatatype(recvtype));
422 }
423 /* Root process scatters data to other processes */
424 if(rank == root){
425 for(int i=0; i<nprocs; i++){
426 if(i != root) {
427 void * ptr = CMPI_PointerAdd(sendbuf, displs[i], sendtype);
428
429 CMPI_Send(ptr, sendcounts[i], sendtype, i,
430 tag, comm.col);
431 }
432 }
433 }
434 if(!(root == rank)){
435 MPI_Status status;
436 int real_recvcount;
437
438 CMPI_Collective_recv(recvbuf, recvcount, recvtype,
439 root, tag, comm.col, &status, routName);
440 real_recvcount = status.size/sizeofDatatype(recvtype);
441 $assert(real_recvcount == recvcount, "Process rank:%d\n%s asks for equality between"
442 " the amount of data sent (%d) and the "
443 "amount of data received (%d).", rank, routName, real_recvcount, recvcount);
444 }
445 return 0;
446}
447
448#endif
449
Note: See TracBrowser for help on using the repository browser.