1 /* Copyright (c) 2007, 2008, 2009, 2010. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
10 #include "xbt/replay.h"
12 #include "surf/surf.h"
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_base, smpi,
15 "Logging specific to SMPI (base)");
17 static int match_recv(void* a, void* b, smx_action_t ignored) {
18 MPI_Request ref = (MPI_Request)a;
19 MPI_Request req = (MPI_Request)b;
21 xbt_assert(ref, "Cannot match recv against null reference");
22 xbt_assert(req, "Cannot match recv against null request");
23 return (ref->src == MPI_ANY_SOURCE || req->src == ref->src)
24 && (ref->tag == MPI_ANY_TAG || req->tag == ref->tag);
27 static int match_send(void* a, void* b,smx_action_t ignored) {
28 MPI_Request ref = (MPI_Request)a;
29 MPI_Request req = (MPI_Request)b;
31 xbt_assert(ref, "Cannot match send against null reference");
32 xbt_assert(req, "Cannot match send against null request");
33 return (req->src == MPI_ANY_SOURCE || req->src == ref->src)
34 && (req->tag == MPI_ANY_TAG || req->tag == ref->tag);
37 static MPI_Request build_request(void *buf, int count,
38 MPI_Datatype datatype, int src, int dst,
39 int tag, MPI_Comm comm, unsigned flags)
43 request = xbt_new(s_smpi_mpi_request_t, 1);
45 // FIXME: this will have to be changed to support non-contiguous datatypes
46 request->size = smpi_datatype_size(datatype) * count;
51 request->action = NULL;
52 request->flags = flags;
60 void smpi_action_trace_run(char *path)
64 xbt_dict_cursor_t cursor;
68 action_fp = fopen(path, "r");
69 xbt_assert(action_fp != NULL, "Cannot open %s: %s", path,
73 if (!xbt_dict_is_empty(action_queues)) {
75 ("Not all actions got consumed. If the simulation ended successfully (without deadlock), you may want to add new processes to your deployment file.");
78 xbt_dict_foreach(action_queues, cursor, name, todo) {
79 XBT_WARN("Still %lu actions for %s", xbt_dynar_length(todo), name);
85 xbt_dict_free(&action_queues);
86 action_queues = xbt_dict_new_homogeneous(NULL);
89 static void smpi_mpi_request_free_voidp(void* request)
91 MPI_Request req = request;
92 smpi_mpi_request_free(&req);
95 /* MPI Low level calls */
96 MPI_Request smpi_mpi_send_init(void *buf, int count, MPI_Datatype datatype,
97 int dst, int tag, MPI_Comm comm)
100 build_request(buf, count, datatype, smpi_comm_rank(comm), dst, tag,
101 comm, PERSISTENT | SEND);
106 MPI_Request smpi_mpi_recv_init(void *buf, int count, MPI_Datatype datatype,
107 int src, int tag, MPI_Comm comm)
109 MPI_Request request =
110 build_request(buf, count, datatype, src, smpi_comm_rank(comm), tag,
111 comm, PERSISTENT | RECV);
116 void smpi_mpi_start(MPI_Request request)
121 xbt_assert(!request->action,
122 "Cannot (re)start a non-finished communication");
123 if(request->flags & RECV) {
124 print_request("New recv", request);
125 if (request->size < xbt_cfg_get_int(_surf_cfg_set, "smpi/async_small_thres"))
126 mailbox = smpi_process_mailbox_small();
128 mailbox = smpi_process_mailbox();
130 // FIXME: SIMIX does not yet support non-contiguous datatypes
131 request->action = simcall_comm_irecv(mailbox, request->buf, &request->size, &match_recv, request);
133 print_request("New send", request);
135 if (request->size < xbt_cfg_get_int(_surf_cfg_set, "smpi/async_small_thres")) { // eager mode => detached send (FIXME: this limit should be configurable)
136 mailbox = smpi_process_remote_mailbox_small(
137 smpi_group_index(smpi_comm_group(request->comm), request->dst));
139 XBT_DEBUG("Send request %p is not in the permanent receive mailbox (buf: %p)",request,request->buf);
140 mailbox = smpi_process_remote_mailbox(
141 smpi_group_index(smpi_comm_group(request->comm), request->dst));
143 if (request->size < 64*1024 ) { //(FIXME: this limit should be configurable)
144 void *oldbuf = request->buf;
146 request->buf = malloc(request->size);
148 memcpy(request->buf,oldbuf,request->size);
149 XBT_DEBUG("Send request %p is detached; buf %p copied into %p",request,oldbuf,request->buf);
153 simcall_comm_isend(mailbox, request->size, -1.0,
154 request->buf, request->size,
156 &smpi_mpi_request_free_voidp, // how to free the userdata if a detached send fails
158 // detach if msg size < eager/rdv switch limit
162 /* FIXME: detached sends are not traceable (request->action == NULL) */
164 simcall_set_category(request->action, TRACE_internal_smpi_get_category());
171 void smpi_mpi_startall(int count, MPI_Request * requests)
175 for(i = 0; i < count; i++) {
176 smpi_mpi_start(requests[i]);
180 void smpi_mpi_request_free(MPI_Request * request)
183 *request = MPI_REQUEST_NULL;
186 MPI_Request smpi_isend_init(void *buf, int count, MPI_Datatype datatype,
187 int dst, int tag, MPI_Comm comm)
189 MPI_Request request =
190 build_request(buf, count, datatype, smpi_comm_rank(comm), dst, tag,
191 comm, NON_PERSISTENT | SEND);
196 MPI_Request smpi_mpi_isend(void *buf, int count, MPI_Datatype datatype,
197 int dst, int tag, MPI_Comm comm)
199 MPI_Request request =
200 smpi_isend_init(buf, count, datatype, dst, tag, comm);
202 smpi_mpi_start(request);
206 MPI_Request smpi_irecv_init(void *buf, int count, MPI_Datatype datatype,
207 int src, int tag, MPI_Comm comm)
209 MPI_Request request =
210 build_request(buf, count, datatype, src, smpi_comm_rank(comm), tag,
211 comm, NON_PERSISTENT | RECV);
216 MPI_Request smpi_mpi_irecv(void *buf, int count, MPI_Datatype datatype,
217 int src, int tag, MPI_Comm comm)
219 MPI_Request request =
220 smpi_irecv_init(buf, count, datatype, src, tag, comm);
222 smpi_mpi_start(request);
226 void smpi_mpi_recv(void *buf, int count, MPI_Datatype datatype, int src,
227 int tag, MPI_Comm comm, MPI_Status * status)
231 request = smpi_mpi_irecv(buf, count, datatype, src, tag, comm);
232 smpi_mpi_wait(&request, status);
237 void smpi_mpi_send(void *buf, int count, MPI_Datatype datatype, int dst,
238 int tag, MPI_Comm comm)
242 request = smpi_mpi_isend(buf, count, datatype, dst, tag, comm);
243 smpi_mpi_wait(&request, MPI_STATUS_IGNORE);
246 void smpi_mpi_sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
247 int dst, int sendtag, void *recvbuf, int recvcount,
248 MPI_Datatype recvtype, int src, int recvtag,
249 MPI_Comm comm, MPI_Status * status)
251 MPI_Request requests[2];
255 smpi_isend_init(sendbuf, sendcount, sendtype, dst, sendtag, comm);
257 smpi_irecv_init(recvbuf, recvcount, recvtype, src, recvtag, comm);
258 smpi_mpi_startall(2, requests);
259 smpi_mpi_waitall(2, requests, stats);
260 if(status != MPI_STATUS_IGNORE) {
261 // Copy receive status
262 memcpy(status, &stats[1], sizeof(MPI_Status));
266 int smpi_mpi_get_count(MPI_Status * status, MPI_Datatype datatype)
268 return status->count / smpi_datatype_size(datatype);
271 static void finish_wait(MPI_Request * request, MPI_Status * status)
273 MPI_Request req = *request;
274 // if we have a sender, we should use its data, and not the data from the receive
276 (req->src==MPI_ANY_SOURCE || req->tag== MPI_ANY_TAG))
277 req = (MPI_Request)SIMIX_comm_get_src_data((*request)->action);
279 if(status != MPI_STATUS_IGNORE) {
280 status->MPI_SOURCE = req->src;
281 status->MPI_TAG = req->tag;
282 status->MPI_ERROR = MPI_SUCCESS;
283 // FIXME: really this should just contain the count of receive-type blocks,
285 status->count = req->size;
289 print_request("Finishing", req);
290 if(req->flags & NON_PERSISTENT) {
291 smpi_mpi_request_free(request);
297 int smpi_mpi_test(MPI_Request * request, MPI_Status * status) {
300 if ((*request)->action == NULL)
303 flag = simcall_comm_test((*request)->action);
305 smpi_mpi_wait(request, status);
310 int smpi_mpi_testany(int count, MPI_Request requests[], int *index,
317 *index = MPI_UNDEFINED;
320 comms = xbt_dynar_new(sizeof(smx_action_t), NULL);
321 map = xbt_new(int, count);
323 for(i = 0; i < count; i++) {
324 if(requests[i]->action) {
325 xbt_dynar_push(comms, &requests[i]->action);
331 i = simcall_comm_testany(comms);
332 // FIXME: MPI_UNDEFINED or does SIMIX have a return code?
333 if(i != MPI_UNDEFINED) {
335 smpi_mpi_wait(&requests[*index], status);
340 xbt_dynar_free(&comms);
345 void smpi_mpi_probe(int source, int tag, MPI_Comm comm, MPI_Status* status){
347 //FIXME find another wait to avoid busy waiting ?
348 // the issue here is that we have to wait on a nonexistent comm
351 request = smpi_mpi_iprobe(source, tag, comm, &flag, status);
352 XBT_DEBUG("Busy Waiting on probing : %d", flag);
354 smpi_mpi_request_free(&request);
355 simcall_process_sleep(0.0001);
360 MPI_Request smpi_mpi_iprobe(int source, int tag, MPI_Comm comm, int* flag, MPI_Status* status){
361 MPI_Request request =build_request(NULL, 0, MPI_CHAR, source, smpi_comm_rank(comm), tag,
362 comm, NON_PERSISTENT | RECV);
363 // behave like a receive, but don't do it
366 print_request("New iprobe", request);
367 // We have to test both mailboxes as we don't know if we will receive one one or another
368 if (xbt_cfg_get_int(_surf_cfg_set, "smpi/async_small_thres")>0){
369 mailbox = smpi_process_mailbox_small();
370 request->action = simcall_comm_iprobe(mailbox, request->src, request->tag, &match_recv, (void*)request);
373 if (request->action==NULL){
374 mailbox = smpi_process_mailbox();
375 request->action = simcall_comm_iprobe(mailbox, request->src, request->tag, &match_recv, (void*)request);
379 MPI_Request req = (MPI_Request)SIMIX_comm_get_src_data(request->action);
381 if(status != MPI_STATUS_IGNORE) {
382 status->MPI_SOURCE = req->src;
383 status->MPI_TAG = req->tag;
384 status->MPI_ERROR = MPI_SUCCESS;
385 status->count = req->size;
393 void smpi_mpi_wait(MPI_Request * request, MPI_Status * status)
395 print_request("Waiting", *request);
396 if ((*request)->action != NULL) { // this is not a detached send
397 simcall_comm_wait((*request)->action, -1.0);
398 finish_wait(request, status);
400 // FIXME for a detached send, finish_wait is not called:
403 int smpi_mpi_waitany(int count, MPI_Request requests[],
410 index = MPI_UNDEFINED;
412 // Wait for a request to complete
413 comms = xbt_dynar_new(sizeof(smx_action_t), NULL);
414 map = xbt_new(int, count);
416 XBT_DEBUG("Wait for one of");
417 for(i = 0; i < count; i++) {
418 if((requests[i] != MPI_REQUEST_NULL) && (requests[i]->action != NULL)) {
419 print_request("Waiting any ", requests[i]);
420 xbt_dynar_push(comms, &requests[i]->action);
426 i = simcall_comm_waitany(comms);
428 // FIXME: MPI_UNDEFINED or does SIMIX have a return code?
429 if (i != MPI_UNDEFINED) {
431 finish_wait(&requests[index], status);
436 xbt_dynar_free(&comms);
441 void smpi_mpi_waitall(int count, MPI_Request requests[],
446 MPI_Status *pstat = status == MPI_STATUS_IGNORE ? MPI_STATUS_IGNORE : &stat;
448 for(c = 0; c < count; c++) {
450 smpi_mpi_wait(&requests[c], pstat);
453 index = smpi_mpi_waitany(count, requests, pstat);
454 if(index == MPI_UNDEFINED) {
458 if(status != MPI_STATUS_IGNORE) {
459 memcpy(&status[index], pstat, sizeof(*pstat));
464 int smpi_mpi_waitsome(int incount, MPI_Request requests[], int *indices,
470 for(i = 0; i < incount; i++) {
471 if(smpi_mpi_testany(incount, requests, &index, status)) {
472 indices[count] = index;
479 void smpi_mpi_bcast(void *buf, int count, MPI_Datatype datatype, int root,
482 // arity=2: a binary tree, arity=4 seem to be a good setting (see P2P-MPI))
483 nary_tree_bcast(buf, count, datatype, root, comm, 4);
486 void smpi_mpi_barrier(MPI_Comm comm)
488 // arity=2: a binary tree, arity=4 seem to be a good setting (see P2P-MPI))
489 nary_tree_barrier(comm, 4);
492 void smpi_mpi_gather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
493 void *recvbuf, int recvcount, MPI_Datatype recvtype,
494 int root, MPI_Comm comm)
496 int system_tag = 666;
497 int rank, size, src, index;
498 MPI_Aint lb = 0, recvext = 0;
499 MPI_Request *requests;
501 rank = smpi_comm_rank(comm);
502 size = smpi_comm_size(comm);
504 // Send buffer to root
505 smpi_mpi_send(sendbuf, sendcount, sendtype, root, system_tag, comm);
507 // FIXME: check for errors
508 smpi_datatype_extent(recvtype, &lb, &recvext);
509 // Local copy from root
510 smpi_datatype_copy(sendbuf, sendcount, sendtype,
511 (char *)recvbuf + root * recvcount * recvext, recvcount, recvtype);
512 // Receive buffers from senders
513 requests = xbt_new(MPI_Request, size - 1);
515 for(src = 0; src < size; src++) {
517 requests[index] = smpi_irecv_init((char *)recvbuf + src * recvcount * recvext,
519 src, system_tag, comm);
523 // Wait for completion of irecv's.
524 smpi_mpi_startall(size - 1, requests);
525 smpi_mpi_waitall(size - 1, requests, MPI_STATUS_IGNORE);
530 void smpi_mpi_gatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
531 void *recvbuf, int *recvcounts, int *displs,
532 MPI_Datatype recvtype, int root, MPI_Comm comm)
534 int system_tag = 666;
535 int rank, size, src, index;
536 MPI_Aint lb = 0, recvext = 0;
537 MPI_Request *requests;
539 rank = smpi_comm_rank(comm);
540 size = smpi_comm_size(comm);
542 // Send buffer to root
543 smpi_mpi_send(sendbuf, sendcount, sendtype, root, system_tag, comm);
545 // FIXME: check for errors
546 smpi_datatype_extent(recvtype, &lb, &recvext);
547 // Local copy from root
548 smpi_datatype_copy(sendbuf, sendcount, sendtype,
549 (char *)recvbuf + displs[root] * recvext,
550 recvcounts[root], recvtype);
551 // Receive buffers from senders
552 requests = xbt_new(MPI_Request, size - 1);
554 for(src = 0; src < size; src++) {
557 smpi_irecv_init((char *)recvbuf + displs[src] * recvext,
558 recvcounts[src], recvtype, src, system_tag, comm);
562 // Wait for completion of irecv's.
563 smpi_mpi_startall(size - 1, requests);
564 smpi_mpi_waitall(size - 1, requests, MPI_STATUS_IGNORE);
569 void smpi_mpi_allgather(void *sendbuf, int sendcount,
570 MPI_Datatype sendtype, void *recvbuf,
571 int recvcount, MPI_Datatype recvtype,
574 int system_tag = 666;
575 int rank, size, other, index;
576 MPI_Aint lb = 0, recvext = 0;
577 MPI_Request *requests;
579 rank = smpi_comm_rank(comm);
580 size = smpi_comm_size(comm);
581 // FIXME: check for errors
582 smpi_datatype_extent(recvtype, &lb, &recvext);
583 // Local copy from self
584 smpi_datatype_copy(sendbuf, sendcount, sendtype,
585 (char *)recvbuf + rank * recvcount * recvext, recvcount,
587 // Send/Recv buffers to/from others;
588 requests = xbt_new(MPI_Request, 2 * (size - 1));
590 for(other = 0; other < size; other++) {
593 smpi_isend_init(sendbuf, sendcount, sendtype, other, system_tag,
596 requests[index] = smpi_irecv_init((char *)recvbuf + other * recvcount * recvext,
597 recvcount, recvtype, other,
602 // Wait for completion of all comms.
603 smpi_mpi_startall(2 * (size - 1), requests);
604 smpi_mpi_waitall(2 * (size - 1), requests, MPI_STATUS_IGNORE);
608 void smpi_mpi_allgatherv(void *sendbuf, int sendcount,
609 MPI_Datatype sendtype, void *recvbuf,
610 int *recvcounts, int *displs,
611 MPI_Datatype recvtype, MPI_Comm comm)
613 int system_tag = 666;
614 int rank, size, other, index;
615 MPI_Aint lb = 0, recvext = 0;
616 MPI_Request *requests;
618 rank = smpi_comm_rank(comm);
619 size = smpi_comm_size(comm);
620 // FIXME: check for errors
621 smpi_datatype_extent(recvtype, &lb, &recvext);
622 // Local copy from self
623 smpi_datatype_copy(sendbuf, sendcount, sendtype,
624 (char *)recvbuf + displs[rank] * recvext,
625 recvcounts[rank], recvtype);
626 // Send buffers to others;
627 requests = xbt_new(MPI_Request, 2 * (size - 1));
629 for(other = 0; other < size; other++) {
632 smpi_isend_init(sendbuf, sendcount, sendtype, other, system_tag,
636 smpi_irecv_init((char *)recvbuf + displs[other] * recvext, recvcounts[other],
637 recvtype, other, system_tag, comm);
641 // Wait for completion of all comms.
642 smpi_mpi_startall(2 * (size - 1), requests);
643 smpi_mpi_waitall(2 * (size - 1), requests, MPI_STATUS_IGNORE);
647 void smpi_mpi_scatter(void *sendbuf, int sendcount, MPI_Datatype sendtype,
648 void *recvbuf, int recvcount, MPI_Datatype recvtype,
649 int root, MPI_Comm comm)
651 int system_tag = 666;
652 int rank, size, dst, index;
653 MPI_Aint lb = 0, sendext = 0;
654 MPI_Request *requests;
656 rank = smpi_comm_rank(comm);
657 size = smpi_comm_size(comm);
659 // Recv buffer from root
660 smpi_mpi_recv(recvbuf, recvcount, recvtype, root, system_tag, comm,
663 // FIXME: check for errors
664 smpi_datatype_extent(sendtype, &lb, &sendext);
665 // Local copy from root
666 smpi_datatype_copy((char *)sendbuf + root * sendcount * sendext,
667 sendcount, sendtype, recvbuf, recvcount, recvtype);
668 // Send buffers to receivers
669 requests = xbt_new(MPI_Request, size - 1);
671 for(dst = 0; dst < size; dst++) {
673 requests[index] = smpi_isend_init((char *)sendbuf + dst * sendcount * sendext,
674 sendcount, sendtype, dst,
679 // Wait for completion of isend's.
680 smpi_mpi_startall(size - 1, requests);
681 smpi_mpi_waitall(size - 1, requests, MPI_STATUS_IGNORE);
686 void smpi_mpi_scatterv(void *sendbuf, int *sendcounts, int *displs,
687 MPI_Datatype sendtype, void *recvbuf, int recvcount,
688 MPI_Datatype recvtype, int root, MPI_Comm comm)
690 int system_tag = 666;
691 int rank, size, dst, index;
692 MPI_Aint lb = 0, sendext = 0;
693 MPI_Request *requests;
695 rank = smpi_comm_rank(comm);
696 size = smpi_comm_size(comm);
698 // Recv buffer from root
699 smpi_mpi_recv(recvbuf, recvcount, recvtype, root, system_tag, comm,
702 // FIXME: check for errors
703 smpi_datatype_extent(sendtype, &lb, &sendext);
704 // Local copy from root
705 smpi_datatype_copy((char *)sendbuf + displs[root] * sendext, sendcounts[root],
706 sendtype, recvbuf, recvcount, recvtype);
707 // Send buffers to receivers
708 requests = xbt_new(MPI_Request, size - 1);
710 for(dst = 0; dst < size; dst++) {
713 smpi_isend_init((char *)sendbuf + displs[dst] * sendext, sendcounts[dst],
714 sendtype, dst, system_tag, comm);
718 // Wait for completion of isend's.
719 smpi_mpi_startall(size - 1, requests);
720 smpi_mpi_waitall(size - 1, requests, MPI_STATUS_IGNORE);
725 void smpi_mpi_reduce(void *sendbuf, void *recvbuf, int count,
726 MPI_Datatype datatype, MPI_Op op, int root,
729 int system_tag = 666;
730 int rank, size, src, index;
731 MPI_Aint lb = 0, dataext = 0;
732 MPI_Request *requests;
735 rank = smpi_comm_rank(comm);
736 size = smpi_comm_size(comm);
738 // Send buffer to root
739 smpi_mpi_send(sendbuf, count, datatype, root, system_tag, comm);
741 // FIXME: check for errors
742 smpi_datatype_extent(datatype, &lb, &dataext);
743 // Local copy from root
744 if (sendbuf && recvbuf)
745 smpi_datatype_copy(sendbuf, count, datatype, recvbuf, count, datatype);
746 // Receive buffers from senders
747 //TODO: make a MPI_barrier here ?
748 requests = xbt_new(MPI_Request, size - 1);
749 tmpbufs = xbt_new(void *, size - 1);
751 for(src = 0; src < size; src++) {
753 // FIXME: possibly overkill we we have contiguous/noncontiguous data
755 tmpbufs[index] = xbt_malloc(count * dataext);
757 smpi_irecv_init(tmpbufs[index], count, datatype, src,
762 // Wait for completion of irecv's.
763 smpi_mpi_startall(size - 1, requests);
764 for(src = 0; src < size - 1; src++) {
765 index = smpi_mpi_waitany(size - 1, requests, MPI_STATUS_IGNORE);
766 XBT_VERB("finished waiting any request with index %d", index);
767 if(index == MPI_UNDEFINED) {
770 if(op) /* op can be MPI_OP_NULL that does nothing */
771 smpi_op_apply(op, tmpbufs[index], recvbuf, &count, &datatype);
773 for(index = 0; index < size - 1; index++) {
774 xbt_free(tmpbufs[index]);
781 void smpi_mpi_allreduce(void *sendbuf, void *recvbuf, int count,
782 MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
784 smpi_mpi_reduce(sendbuf, recvbuf, count, datatype, op, 0, comm);
785 smpi_mpi_bcast(recvbuf, count, datatype, 0, comm);
788 void smpi_mpi_scan(void *sendbuf, void *recvbuf, int count,
789 MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
791 int system_tag = 666;
792 int rank, size, other, index;
793 MPI_Aint lb = 0, dataext = 0;
794 MPI_Request *requests;
797 rank = smpi_comm_rank(comm);
798 size = smpi_comm_size(comm);
800 // FIXME: check for errors
801 smpi_datatype_extent(datatype, &lb, &dataext);
803 // Local copy from self
804 smpi_datatype_copy(sendbuf, count, datatype, recvbuf, count, datatype);
806 // Send/Recv buffers to/from others;
807 requests = xbt_new(MPI_Request, size - 1);
808 tmpbufs = xbt_new(void *, rank);
810 for(other = 0; other < rank; other++) {
811 // FIXME: possibly overkill we we have contiguous/noncontiguous data
813 tmpbufs[index] = xbt_malloc(count * dataext);
815 smpi_irecv_init(tmpbufs[index], count, datatype, other, system_tag,
819 for(other = rank + 1; other < size; other++) {
821 smpi_isend_init(sendbuf, count, datatype, other, system_tag, comm);
824 // Wait for completion of all comms.
825 smpi_mpi_startall(size - 1, requests);
826 for(other = 0; other < size - 1; other++) {
827 index = smpi_mpi_waitany(size - 1, requests, MPI_STATUS_IGNORE);
828 if(index == MPI_UNDEFINED) {
832 // #Request is below rank: it's a irecv
833 smpi_op_apply(op, tmpbufs[index], recvbuf, &count, &datatype);
836 for(index = 0; index < rank; index++) {
837 xbt_free(tmpbufs[index]);