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

1.23 2.0 acw/focus-triggers main test-branch
Last change on this file since e84bca3 was 4558569, checked in by Manchun Zheng <zmanchun@…>, 10 years ago

changed the impl. of $mpi_extent_of.

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

  • Property mode set to 100644
File size: 24.2 KB
Line 
1#ifndef __CIVL_CIVLMPI__
2#define __CIVL_CIVLMPI__
3
4#include <civlc.cvh>
5#include <concurrency.cvh>
6#include <collate.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#include <seq.cvh>
14#include <stdlib.h>
15#include <stdio.h>
16
17
18/* Library private helper function declaration */
19char * $mpi_coroutine_name(int tag);
20
21/**************************** Duplicated Part *************************************/
22
23#ifdef _MPI_CONTRACT
24struct _mpi_data_size{
25 MPI_Datatype type;
26 size_t size;
27};
28#endif
29
30/* Duplicated definition with the same struct in mpi.h.
31 The reason of this duplication is to make civlmpi.cvl
32 independent with mpi.cvl. */
33typedef struct MPI_Comm {
34 $comm p2p; // point-to-point communication
35 $comm col; // collective communication
36 $collator collator;
37 $barrier barrier;
38 int gcommIndex; //the index of the corresponding global communicator.
39}MPI_Comm;
40
41/* Definition of CMPI_Gcomm (CMPI_Gcomm has a type of __CMPI_Gcomm)
42 and MPI_Comm */
43struct $mpi_gcomm {
44 $gcomm p2p; // point-to-point communication
45 $gcomm col; // collective communication
46 $gcollator gcollator;
47 $gbarrier gbarrier;
48};
49
50$mpi_data_size_t _mpi_size_map[];//=($mpi_data_size_t[0]) $lambda(int i) (($mpi_data_size_t){0, 0});
51
52/****************************** Helper Functions **********************************/
53int sizeofDatatype(MPI_Datatype datatype) {
54#ifdef _MPI_CONTRACT
55 if (!$is_concrete_int(datatype))
56 return $mpi_extentof(datatype) * sizeof(char);
57#endif
58 switch (datatype) {
59 case MPI_INT:
60 return sizeof(int);
61 case MPI_2INT:
62 return (sizeof(int)*2);
63 case MPI_FLOAT:
64 return sizeof(float);
65 case MPI_DOUBLE:
66 return sizeof(double);
67 case MPI_CHAR:
68 return sizeof(char);
69 case MPI_BYTE:
70 return sizeof(char); // char is always one byte ?
71 case MPI_SHORT:
72 return sizeof(short);
73 case MPI_LONG:
74 return sizeof(long);
75 case MPI_LONG_DOUBLE:
76 return sizeof(long double);
77 case MPI_LONG_LONG_INT:
78 return sizeof(long long int);
79 case MPI_LONG_LONG:
80 return sizeof(long long);
81 case MPI_UNSIGNED_LONG_LONG:
82 return sizeof(unsigned long long);
83 default:
84 $assert(0, "Unreachable");
85 }
86}
87
88/************************** MPI LIB Implementations *******************************/
89$mpi_gcomm $mpi_gcomm_create($scope scope, int size) {
90 $mpi_gcomm result;
91
92 result.p2p = $gcomm_create(scope, size);
93 result.col = $gcomm_create(scope, size);
94 result.gcollator = $gcollator_create(scope, size);
95 result.gbarrier = $gbarrier_create(scope, size);
96 return result;
97}
98
99void $mpi_gcomm_destroy($mpi_gcomm gc) {
100 /* This function will report errors for any messages remaining the
101 $mpi_gcomm. Those messages are junk messages. */
102 int numJunkRecord;
103 int numJunkMsg;
104 $message junkMsgs[]; // A CIVL-C sequence for junk messages.
105
106 $seq_init(&junkMsgs, 0, NULL);
107 numJunkMsg = $gcomm_destroy(gc.p2p, &junkMsgs);
108 /* Informations of reporting junk messages in p2p communicator and
109 collective communicator are different: */
110 for(int i = 0; i < numJunkMsg; i++) {
111 int src, dest, tag;
112
113 src = $message_source(junkMsgs[i]);
114 dest = $message_dest(junkMsgs[i]);
115 tag = $message_tag(junkMsgs[i]);
116 $assert($false, "MPI message leak: There is a message from rank %d to rank %d with tag %d "
117 "has been sent but is never received in point-to-point communication.",
118 src, dest, tag);
119 }
120 numJunkMsg = $gcomm_destroy(gc.col, &junkMsgs);
121 for(int i = 0; i < numJunkMsg; i++) {
122 int src, tag;
123 char * routine;
124
125 src = $message_source(junkMsgs[i]);
126 tag = $message_tag(junkMsgs[i]);
127 routine = $mpi_coroutine_name(tag);
128 $assert($false, "MPI message leak: There is a message sent by rank %d for collective routine %s"
129 " that is never received.",
130 src, routine);
131 }
132 $free(gc.gcollator);
133 $gbarrier_destroy(gc.gbarrier);
134}
135
136MPI_Comm $mpi_comm_create($scope scope, $mpi_gcomm gc, int rank) {
137 MPI_Comm result;
138
139 result.p2p = $comm_create(scope, gc.p2p, rank);
140 result.col = $comm_create(scope, gc.col, rank);
141 result.collator = $collator_create(gc.gcollator, scope, rank);
142 result.barrier = $barrier_create(scope, gc.gbarrier, rank);
143 result.gcommIndex = 0;
144 return result;
145}
146
147void $mpi_comm_destroy(MPI_Comm comm, $mpi_state mpi_state) {
148#ifndef _MPI_CONTRACT
149 if(comm.gcommIndex == 0)
150 $assert(mpi_state == _MPI_FINALIZED, "Process terminates without "
151 "calling MPI_Finalize() first.");
152#endif
153 $comm_destroy(comm.p2p);
154 $comm_destroy(comm.col);
155 $free(comm.collator);
156 $barrier_destroy(comm.barrier);
157}
158
159void * $mpi_pointer_add(const void * ptr, int offset, MPI_Datatype datatype) {
160#ifdef _MPI_CONTRACT
161 int datatypeExtent = $mpi_extentof(datatype);
162
163// $elaborate(datatypeExtent);
164// $elaborate(offset);
165 return $pointer_add(ptr, offset * datatypeExtent, sizeof(char));
166#else
167 int type_size = sizeofDatatype(datatype);
168
169 return $pointer_add(ptr, offset, type_size);
170#endif
171}
172
173/********************* Lower level MPI routines *********************/
174/* CMPI_Send and CMPI_Recv are a pair of send receives functions that
175 help implementing MPI routines. They should never be block which
176 means no potential deadlocks related to these functions */
177int $mpi_send(void *buf, int count, MPI_Datatype datatype, int dest,
178 int tag, MPI_Comm comm) {
179 if (dest >= 0) {
180 int size = count*sizeofDatatype(datatype);
181 int place = $comm_place(comm.p2p);
182 $message out;
183
184 $elaborate(dest);
185#ifdef _MPI_CONTRACT
186 $elaborate(count);
187#endif
188 out = $message_pack(place, dest, tag, buf, size);
189 $comm_enqueue(comm.p2p, out);
190 }
191 return 0;
192}
193
194int $mpi_recv(void *buf, int count, MPI_Datatype datatype, int source,
195 int tag, MPI_Comm comm, MPI_Status *status) {
196 if (source >= 0 || source == MPI_ANY_SOURCE) {
197 $message in;
198 int place = $comm_place(comm.p2p);
199 int deterministicTag;
200
201 /* A deterministic tag is a sugar for CIVL implementaion. The CIVL
202 implementation only needs to care about two cases: tag == -2
203 which is a wild-card tag or any other tags which can either be
204 concrete or not:.*/
205 $assert(tag == -2 || tag >= 0, "Illegal MPI message receive tag %d.\n", tag);
206 deterministicTag = tag < 0 ? -2 : tag;
207 $elaborate(source);
208 in = $comm_dequeue(comm.p2p, source, deterministicTag);
209
210 int size = count*sizeofDatatype(datatype);
211
212 $message_unpack(in, buf, size);
213 if (status != MPI_STATUS_IGNORE) {
214 status->size = $message_size(in);
215 status->MPI_SOURCE = $message_source(in);
216 status->MPI_TAG = $message_tag(in);
217 status->MPI_ERROR = 0;
218 }
219 }
220 return 0;
221}
222
223int $mpi_sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
224 int dest, int sendtag, void *recvbuf, int recvcount,
225 MPI_Datatype recvtype, int source, int recvtag,
226 MPI_Comm comm, MPI_Status *status) {
227 int deterministicRecvTag;
228
229 $assert(sendtag >= 0, "MPI sendtag should be greater than or equal to zero");
230 $assert(recvtag == -2 || recvtag >= 0, "Illegal MPI message receive tag %d.\n", recvtag);
231 deterministicRecvTag = recvtag < 0 ? -2 : recvtag;
232 //send and receive triggering flags
233 if((dest >= 0) && ((source >= 0 || source == MPI_ANY_SOURCE))) {
234 $message out, in;
235 int size = sendcount*sizeofDatatype(sendtype);
236 int place = $comm_place(comm.p2p);
237
238 out = $message_pack(place, dest, sendtag, sendbuf, size);
239 $elaborate(source);
240
241 $choose {
242 $when($true){
243 $comm_enqueue(comm.p2p, out);
244 in = $comm_dequeue(comm.p2p, source, deterministicRecvTag);
245 }
246 $when($false){
247 /* This $choose branch plays a trick which correctly
248 implements the sendrecv() semantically. Such a branch
249 ensures that there is no chance of potential deadlocks when
250 all processes do send then recv collectively. However,
251 effectively, this branch is no need and never will be
252 executed.*/
253 in = $comm_dequeue(comm.p2p, source, deterministicRecvTag);
254 $comm_enqueue(comm.p2p, out);
255 }
256 }
257 size = recvcount*sizeofDatatype(recvtype);
258 $message_unpack(in, recvbuf, size);
259 if (status != MPI_STATUS_IGNORE) {
260 status->size = $message_size(in);
261 status->MPI_SOURCE = $message_source(in);
262 status->MPI_TAG = $message_tag(in);
263 status->MPI_ERROR = 0;
264 }
265 }
266 else if (dest >= 0) {
267 $mpi_send(sendbuf, sendcount, sendtype, dest, sendtag, comm);
268 }
269 else if (source >= 0 || source == MPI_ANY_SOURCE) {
270 $mpi_recv(recvbuf, recvcount, recvtype, source, deterministicRecvTag, comm, status);
271 }
272 return 0;
273}
274
275/********************* Collective helper functions ********************/
276/* Note: collective helpers functions are functions have same
277 behaviors as MPI collective functions, it can be re-used as a part
278 of implementation by different MPI routines. For example,
279 MPI_Allreduce will call CMPI_Reduce and CMPI_Bcast, both of them
280 should throw errors (if encounters any) as if errors are thrown
281 from MPI_Allreduce.
282*/
283int $mpi_collective_send(void *buf, int count, MPI_Datatype datatype, int dest,
284 int tag, MPI_Comm comm) {
285 if (dest >= 0) {
286 int size = count*sizeofDatatype(datatype);
287 int place = $comm_place(comm.col);
288 $message out = $message_pack(place, dest, tag, buf, size);
289
290#ifdef _MPI_CONTRACT
291 $atomic{
292 $comm_enqueue(comm.col, out);
293 //$mpi_colSendShot(comm.gcommIndex, out, place);
294 }
295#else
296 $comm_enqueue(comm.col, out);
297#endif
298 }
299 return 0;
300}
301
302int $mpi_collective_recv(void *buf, int count, MPI_Datatype datatype,
303 int source, int tag, MPI_Comm comm,
304 MPI_Status * status, char * routName) {
305 if(source >= 0 || source == MPI_ANY_SOURCE) {
306 $elaborate(source);
307 $message in = $comm_dequeue(comm.col, source, MPI_ANY_TAG);
308 int size = count*sizeofDatatype(datatype);
309 int recvTag;
310
311 /* This routine should only be used by collective routines, there
312 is no non-deterministic tags for collective routines.*/
313 recvTag = $message_tag(in);
314 $assert (recvTag == tag, "Collective routine %s receives a "
315 "message with a mismatched tag\n", routName);
316 $message_unpack(in, buf, size);
317 if (status != MPI_STATUS_IGNORE) {
318 status->size = $message_size(in);
319 status->MPI_SOURCE = $message_source(in);
320 status->MPI_TAG = recvTag;
321 status->MPI_ERROR = 0;
322 }
323 }
324 return 0;
325}
326
327/* Broadcast helper function that uses any specified message tag */
328int $mpi_bcast(void *buf, int count, MPI_Datatype datatype, int root, int tag,
329 MPI_Comm comm, char * routName) {
330 if ($comm_place(comm.col) == root) {
331 int nprocs = $comm_size(comm.col);
332
333 for (int i=0; i<nprocs; i++)
334 if (i != root)
335 $mpi_collective_send(buf, count, datatype, i, tag, comm);
336 } else
337 $mpi_collective_recv(buf, count, datatype, root, tag, comm,
338 MPI_STATUS_IGNORE, routName);
339 return 0;
340}
341
342/* Reduction helper function that uses any specified message tag */
343int $mpi_reduce(const void* sendbuf, void* recvbuf, int count,
344 MPI_Datatype datatype, MPI_Op op, int root, int tag,
345 MPI_Comm comm, char * routName) {
346 int rank;
347
348 rank = $comm_place(comm.col);
349 if (rank != root)
350 $mpi_collective_send(sendbuf, count, datatype, root, tag, comm);
351 else {
352 int nprocs = $comm_size(comm.col);
353 int size;
354
355 size = count * sizeofDatatype(datatype);
356 memcpy(recvbuf, sendbuf, size);
357 for (int i = 0; i<nprocs; i++) {
358 if(i != root){
359 int colTag;
360 $message in = $comm_dequeue(comm.col, i, MPI_ANY_TAG);
361
362 /* Collective routines have no non-deterministic tags.*/
363 colTag = $message_tag(in);
364 $assert (colTag == tag , "Collective routine %s receives a "
365 "message with a mismatched tag\n", routName);
366 /* the third argument "count" indicates the number of cells needs doing the
367 operation. */
368 $bundle_unpack_apply(in.data, recvbuf, count, op);
369 $assert (in.size <= size ,
370 "Message of size %d exceeds the specified size %d.", in.size, size);
371 }
372 }
373 }
374 return 0;
375}
376
377/* Gathering helper function that uses any specified message tag */
378int $mpi_gather(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
379 void* recvbuf, int recvcount, MPI_Datatype recvtype,
380 int root, int tag, MPI_Comm comm, char * routName){
381 int rank, nprocs;
382 MPI_Status status;
383
384 rank = $comm_place(comm.col);
385 nprocs = $comm_size(comm.col);
386 /* MPI standard requirement:
387 * For root process, sendtype must be equal to
388 * recvtype. */
389 if(rank == root)
390 $assert (sendtype == recvtype,
391 "%s asks for equality "
392 "between 'sendtype' and 'recvtype'.", routName);
393 /* MPI_standard requirement:
394 * Only root process can use MPI_IN_PLACE*/
395 if(sendbuf == MPI_IN_PLACE){
396 $assert (root == rank,
397 "Only root can replace 'sendbuf' with 'MPI_IN_PLACE'.");
398 } else if(root == rank) {
399 void * ptr;
400
401 $assert(sendcount == recvcount, "Root process of routine %d without using"
402 " MPI_IN_PLACE should give the same value for recvcount and sendcount",
403 routName);
404 ptr = $mpi_pointer_add(recvbuf, root * recvcount, recvtype);
405 memcpy(ptr, sendbuf, recvcount * sizeofDatatype(recvtype));
406 } else
407 $mpi_collective_send(sendbuf, sendcount, sendtype, root, tag, comm);
408 /* Root process receives messages and put them in right places */
409 if(rank == root){
410 int real_recvcount;
411 int offset;
412
413 for(int i=0; i<nprocs; i++){
414 if(i != root) {
415 void * ptr;
416
417 offset = i * recvcount;
418 ptr = $mpi_pointer_add(recvbuf, offset, recvtype);
419 $mpi_collective_recv(ptr, recvcount, recvtype,
420 i, tag, comm, &status, routName);
421 real_recvcount = status.size/sizeofDatatype(recvtype);
422 $assert(real_recvcount == recvcount,
423 "%s asks for equality between"
424 " the amount of data sent and the "
425 "amount of data received.", routName);
426 }
427 }
428 }
429 return 0;
430}
431
432int $mpi_gatherv(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
433 void* recvbuf, const int recvcounts[], const int displs[],
434 MPI_Datatype recvtype, int root, int tag,
435 MPI_Comm comm, char * routName){
436 int rank, nprocs;
437
438 rank = $comm_place(comm.col);
439 nprocs = $comm_size(comm.col);
440 /* MPI standard requirement:
441 * For root process, sendtype must be equal to
442 * recvtype. */
443 if(rank == root)
444 $assert(sendtype == recvtype, "%s asks for equality "
445 "between 'sendtype' and 'recvtype'.", routName);
446 /* MPI_standard requirement:
447 * Only root process can use MPI_IN_PLACE*/
448 if(sendbuf == MPI_IN_PLACE){
449 $assert(root == rank, "Only root can replace 'sendbuf' with 'MPI_IN_PLACE'.");
450 }else if(root == rank) {
451 void * ptr;
452
453 $assert(sendcount == recvcounts[root], "For routine %s, recvcounts[%d] "
454 "should be same as the sendcount of the process with rank %d.\n",
455 routName, root, root);
456 ptr = $mpi_pointer_add(recvbuf, displs[rank], recvtype);
457 memcpy(ptr, sendbuf, sendcount * sizeofDatatype(recvtype));
458 }else{
459 $mpi_collective_send(sendbuf, sendcount, sendtype, root, tag, comm);
460 }
461 /* Root process receives messages and put them in right places */
462 if(rank == root){
463 int real_recvcount;
464 MPI_Status status;
465
466 for(int i=0; i<nprocs; i++){
467 if(i != root){
468 void * ptr = $mpi_pointer_add(recvbuf, displs[i], recvtype);
469
470 $mpi_collective_recv(ptr, recvcounts[i],
471 recvtype, i, tag, comm, &status, routName);
472 real_recvcount = status.size/sizeofDatatype(recvtype);
473 $assert(real_recvcount == recvcounts[i], "%s asks for equality between"
474 " the amount of data sent and the "
475 "amount of data received.", routName);
476 }
477 }
478 }
479 return 0;
480}
481
482/* Scatter helper function that uses any specified message tag */
483int $mpi_scatter(const void* sendbuf, int sendcount, MPI_Datatype sendtype,
484 void* recvbuf, int recvcount, MPI_Datatype recvtype, int root,
485 int tag, MPI_Comm comm, char * routName){
486 int rank, nprocs;
487
488 rank = $comm_place(comm.col);
489 nprocs = $comm_size(comm.col);
490 /* MPI standard requirement:
491 * For root process, sendtype must be equal to
492 * recvtype. */
493 if(rank == root)
494 $assert(sendtype == recvtype, "MPI_Scatter() asks for equality "
495 "between 'sendtype' and 'recvtype'.");
496 /* MPI_standard requirement:
497 * Only root process can use MPI_IN_PLACE */
498 if(recvbuf == MPI_IN_PLACE){
499 $assert(root == rank, "Only root can replace 'recvbuf' with 'MPI_IN_PLACE'.");
500 }else if(rank == root) {
501 void * ptr;
502
503 $assert(sendcount == recvcount, "Root process of routine %d without using"
504 " MPI_IN_PLACE should give the same value for recvcount and sendcount",
505 routName);
506 ptr = $mpi_pointer_add(sendbuf, root*recvcount, sendtype);
507 memcpy(recvbuf, ptr, sizeofDatatype(recvtype)*recvcount);
508 }
509 /* Root process scatters data to other processes */
510 if(rank == root){
511 int offset;
512
513 for(int i=0; i<nprocs; i++){
514 if(i != root) {
515 void * ptr;
516
517 offset = i * sendcount;
518 ptr = $mpi_pointer_add(sendbuf, offset, sendtype);
519 $mpi_collective_send(ptr, sendcount, sendtype, i, tag, comm);
520 }
521 }
522 }
523 /* Non-root processes receive data */
524 if(!(root == rank)){
525 int real_recvcount;
526 MPI_Status status;
527
528 $mpi_collective_recv(recvbuf, recvcount, recvtype,
529 root, tag, comm, &status, routName);
530 real_recvcount = status.size/sizeofDatatype(recvtype);
531 $assert(real_recvcount == recvcount,
532 "%s asks for equality between"
533 " the amount of data sent and the "
534 "amount of data received.", routName);
535 }
536 return 0;
537}
538
539/* Scatterv helper function that uses any specified message tag */
540int $mpi_scatterv(const void* sendbuf, const int sendcounts[], const
541 int displs[], MPI_Datatype sendtype, void* recvbuf,
542 int recvcount, MPI_Datatype recvtype, int root, int tag,
543 MPI_Comm comm, char * routName){
544 int rank, nprocs;
545
546 rank = $comm_place(comm.col);
547 nprocs = $comm_size(comm.col);
548 /* MPI standard requirement:
549 * For root process, sendtype must be equal to
550 * recvtype. */
551 if(rank == root)
552 $assert(sendtype == recvtype, "%s asks for equality "
553 "between 'sendtype' and 'recvtype'.", routName);
554 /* MPI_standard requirement:
555 * Only root process can use MPI_IN_PLACE */
556 if(recvbuf == MPI_IN_PLACE){
557 $assert(root == rank, "Only root can replace 'recvbuf' with 'MPI_IN_PLACE'.");
558 } else if(rank == root) {
559 void * ptr;
560
561 $assert(sendcounts[root] == recvcount, "For routine %s, sendcounts[%d] "
562 "should be same as the recvcount of the process with rank %d.\n",
563 routName, root, root);
564 ptr = $mpi_pointer_add(sendbuf, displs[root], sendtype);
565 memcpy(recvbuf, ptr, recvcount*sizeofDatatype(recvtype));
566 }
567 /* Root process scatters data to other processes */
568 if(rank == root){
569 for(int i=0; i<nprocs; i++){
570 if(i != root) {
571 void * ptr = $mpi_pointer_add(sendbuf, displs[i], sendtype);
572
573 $mpi_collective_send(ptr, sendcounts[i], sendtype, i,
574 tag, comm);
575 }
576 }
577 }
578 if(!(root == rank)){
579 MPI_Status status;
580 int real_recvcount;
581
582 $mpi_collective_recv(recvbuf, recvcount, recvtype,
583 root, tag, comm, &status, routName);
584 real_recvcount = status.size/sizeofDatatype(recvtype);
585 $assert(real_recvcount == recvcount, "Process rank:%d\n%s asks for equality between"
586 " the amount of data sent (%d) and the "
587 "amount of data received (%d).", rank, routName, real_recvcount, recvcount);
588 }
589 return 0;
590}
591
592int $mpi_comm_dup($scope scope, MPI_Comm comm, MPI_Comm * newcomm, char * routName) {
593 int place = $comm_place(comm.col);
594 $mpi_gcomm newgcomm;
595 int idx;
596 $scope CMPI_ROOT_SCOPE = $mpi_root_scope(comm.col);
597
598 if(place == 0) {
599 int size = $comm_size(comm.col);
600
601 newgcomm = $mpi_gcomm_create(CMPI_ROOT_SCOPE, size);
602 idx = $mpi_new_gcomm(CMPI_ROOT_SCOPE, newgcomm);
603 }
604 $mpi_bcast(&idx, 1, MPI_INT, 0, COMMDUP_TAG,
605 comm, routName);
606 newgcomm = $mpi_get_gcomm(CMPI_ROOT_SCOPE, idx);
607 (*newcomm) = $mpi_comm_create(scope, newgcomm, place);
608 newcomm->gcommIndex = idx;
609 $barrier_call(comm.barrier);
610 $gcomm_dup(comm.p2p, newcomm->p2p);
611 $gcomm_dup(comm.col, newcomm->col);
612 $barrier_call(comm.barrier);
613 return 0;
614}
615
616int $mpi_comm_free(MPI_Comm *comm, $mpi_state mpi_state) {
617 int place = $comm_place(comm->col);
618 int size = $comm_size(comm->col);
619 int buf[size];
620 int gcommIndex = comm->gcommIndex;
621 $scope CMPI_ROOT_SCOPE = $mpi_root_scope(comm->col);
622
623 //TODO: $mpi_gather here is just a ugly synchronization
624 $mpi_gather(&place, 1, MPI_INT, buf, 1, MPI_INT, 0,
625 COMMFREE_TAG, (*comm), "MPI_Comm_free synchronization.");
626 $mpi_comm_destroy(*comm, mpi_state);
627 if(place == 0) {
628 $mpi_gcomm temp = $mpi_get_gcomm(CMPI_ROOT_SCOPE, gcommIndex);
629
630 $mpi_gcomm_destroy(temp);
631 }
632 return 0;
633}
634
635$bundle $mpi_create_coroutine_entry(int routineTag, int root,
636 int op, int numDatatypes, int * datatypes) {
637 int zero = 0;
638 $bundle bundledEntry;
639 struct Entry {
640 int routine_tag;
641 int root;
642 int op;
643 int numTypes;
644 int datatypes[];
645 }entry;
646
647 entry.routine_tag = routineTag;
648 entry.root = root;
649 entry.op = op;
650 entry.numTypes = numDatatypes;
651 $seq_init(&entry.datatypes, numDatatypes, &zero);
652 for(int i = 0; i < numDatatypes; i++)
653 entry.datatypes[i] = datatypes[i];
654 bundledEntry = $bundle_pack(&entry, sizeof(struct Entry));
655 return bundledEntry;
656}
657
658void $mpi_diff_coroutine_entries($bundle specEntry, $bundle mineEntry, int rank) {
659 struct Entry {
660 int routine_tag;
661 int root;
662 int op;
663 int numTypes;
664 int datatypes[];
665 }spec, mine;
666 char * routine;
667 int numTypes;
668
669 $bundle_unpack(specEntry, &spec);
670 $bundle_unpack(mineEntry, &mine);
671 routine = $mpi_coroutine_name(spec.routine_tag);
672 if(spec.routine_tag != mine.routine_tag) {
673 char * mineRoutine = $mpi_coroutine_name(mine.routine_tag);
674
675 $assert($false, "Process with rank %d reaches an MPI collective routine "
676 "%s while at least one of others are collectively reaching %s.",
677 rank, mineRoutine, routine);
678 }
679 else if(spec.root != mine.root) {
680 $assert($false, "Process with rank %d reaches an MPI collective routine "
681 "%s which has a different root with at least one of others.", rank, routine);
682 } else if(spec.op != mine.op) {
683 $assert($false, "Process with rank %d reaches an MPI collective routine "
684 "%s which has a different MPI_Op with at least one of others", rank, routine);
685 } else if(spec.numTypes != mine.numTypes) {
686 $assert($false, "Process with rank %d reaches an MPI collective routine "
687 "%s which has an inconsistent datatype specification with at least"
688 " one of others",
689 rank, routine);
690 }
691 numTypes = spec.numTypes;
692 for(int i = 0; i < numTypes; i++)
693 if(spec.datatypes[i] != mine.datatypes[i]) {
694 $assert($false, "Process with rank %d reaches an MPI collective routine "
695 "%s which has an inconsistent datatype specification with at "
696 "least one of others",
697 rank, routine);
698 break;
699 }
700}
701
702$collate_state $mpi_snapshot(MPI_Comm comm, $scope scope) {
703 return $collate_arrives(comm.collator, scope);
704}
705
706void $mpi_unsnapshot(MPI_Comm comm) {
707 $collate_departs(comm.collator);
708}
709
710/*@ depends_on \nothing;
711 @ executes_when \true;
712 @*/
713$state_f $atomic_f size_t $mpi_extentof(MPI_Datatype datatype) {
714 int len=$seq_length(&_mpi_size_map);
715
716 for(int i=0; i<len; i++)
717 if(_mpi_size_map[i].type==datatype)
718 return _mpi_size_map[i].size;
719
720 $mpi_data_size_t newSize;
721
722 newSize.type=datatype;
723 $havoc(&newSize.size);
724 $assume(newSize.size>0);
725 $seq_append(&_mpi_size_map, &newSize, 1);
726 printf("size=%d\n", newSize.size);
727 return newSize.size;
728}
729
730void $mpi_assigns(void * buf, int count, MPI_Datatype datatype) {
731 size_t realCount = count * $mpi_extentof(datatype);
732 char newValues[realCount];
733
734 $havoc(&newValues);
735 memcpy(buf, newValues, realCount * sizeof(char));
736}
737
738
739/********************* Private helper functions *********************/
740/* Returns the string literal of MPI collective routine names by
741 * giving the unique message tag. */
742char * $mpi_coroutine_name(int tag) {
743 switch(tag) {
744 case 9999: return "MPI_Bcast";
745 case 9998: return "MPI_Reduce";
746 case 9997: return "MPI_Allreduce";
747 case 9996: return "MPI_Gather";
748 case 9995: return "MPI_Scatter";
749 case 9994: return "MPI_Gatherv";
750 case 9993: return "MPI_Scatterv";
751 case 9992: return "MPI_Allgather";
752 case 9991: return "MPI_Reduce_scatter";
753 case 9990: return "MPI_Alltoall";
754 case 9989: return "MPI_Alltoallv";
755 case 9988: return "MPI_Alltoallw";
756 case 9987: return "MPI_Barrier";
757 case 9986: return "MPI_Commdup";
758 case 9985: return "MPI_Commfree";
759 default: $assert($false, "Internal Error: Unexpected MPI routine tag:%d.\n", tag);
760 }
761}
762#endif
763
Note: See TracBrowser for help on using the repository browser.