Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Modern C++ use "auto".
[simgrid.git] / src / smpi / colls / smpi_nbc_impl.cpp
1 /* Asynchronous parts of the basic collective algorithms, meant to be used both for the naive default implementation, but also for non blocking collectives */
2
3 /* Copyright (c) 2009-2020. The SimGrid Team. All rights reserved.          */
4
5 /* This program is free software; you can redistribute it and/or modify it
6  * under the terms of the license (GNU LGPL) which comes with this package. */
7
8 #include "colls_private.hpp"
9 #include "src/smpi/include/smpi_actor.hpp"
10
11 namespace simgrid{
12 namespace smpi{
13
14 int colls::ibarrier(MPI_Comm comm, MPI_Request* request, int external)
15 {
16   int size = comm->size();
17   int rank = comm->rank();
18   int system_tag=COLL_TAG_BARRIER-external;
19   (*request) = new Request( nullptr, 0, MPI_BYTE,
20                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
21   if (rank > 0) {
22     auto* requests = new MPI_Request[2];
23     requests[0] = Request::isend (nullptr, 0, MPI_BYTE, 0,
24                              system_tag,
25                              comm);
26     requests[1] = Request::irecv (nullptr, 0, MPI_BYTE, 0,
27                              system_tag,
28                              comm);
29     (*request)->set_nbc_requests(requests, 2);
30   }
31   else {
32     auto* requests = new MPI_Request[(size - 1) * 2];
33     for (int i = 1; i < 2 * size - 1; i += 2) {
34       requests[i - 1] = Request::irecv(nullptr, 0, MPI_BYTE, MPI_ANY_SOURCE, system_tag, comm);
35       requests[i]     = Request::isend(nullptr, 0, MPI_BYTE, (i + 1) / 2, system_tag, comm);
36     }
37     (*request)->set_nbc_requests(requests, 2*(size-1));
38   }
39   return MPI_SUCCESS;
40 }
41
42 int colls::ibcast(void* buf, int count, MPI_Datatype datatype, int root, MPI_Comm comm, MPI_Request* request,
43                   int external)
44 {
45   int size = comm->size();
46   int rank = comm->rank();
47   int system_tag=COLL_TAG_BCAST-external;
48   (*request) = new Request( nullptr, 0, MPI_BYTE,
49                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
50   if (rank != root) {
51     auto* requests = new MPI_Request[1];
52     requests[0] = Request::irecv (buf, count, datatype, root,
53                              system_tag,
54                              comm);
55     (*request)->set_nbc_requests(requests, 1);
56   }
57   else {
58     auto* requests = new MPI_Request[size - 1];
59     int n = 0;
60     for (int i = 0; i < size; i++) {
61       if(i!=root){
62         requests[n] = Request::isend(buf, count, datatype, i,
63                                  system_tag,
64                                  comm
65                                  );
66         n++;
67       }
68     }
69     (*request)->set_nbc_requests(requests, size-1);
70   }
71   return MPI_SUCCESS;
72 }
73
74 int colls::iallgather(const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount,
75                       MPI_Datatype recvtype, MPI_Comm comm, MPI_Request* request, int external)
76 {
77
78   const int system_tag = COLL_TAG_ALLGATHER-external;
79   MPI_Aint lb = 0;
80   MPI_Aint recvext = 0;
81
82   int rank = comm->rank();
83   int size = comm->size();
84   (*request) = new Request( nullptr, 0, MPI_BYTE,
85                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
86   // FIXME: check for errors
87   recvtype->extent(&lb, &recvext);
88   // Local copy from self
89   Datatype::copy(sendbuf, sendcount, sendtype, static_cast<char *>(recvbuf) + rank * recvcount * recvext, recvcount,
90                      recvtype);
91   // Send/Recv buffers to/from others;
92   auto* requests = new MPI_Request[2 * (size - 1)];
93   int index = 0;
94   for (int other = 0; other < size; other++) {
95     if(other != rank) {
96       requests[index] = Request::isend_init(sendbuf, sendcount, sendtype, other, system_tag,comm);
97       index++;
98       requests[index] = Request::irecv_init(static_cast<char *>(recvbuf) + other * recvcount * recvext, recvcount, recvtype,
99                                         other, system_tag, comm);
100       index++;
101     }
102   }
103   Request::startall(2 * (size - 1), requests);
104   (*request)->set_nbc_requests(requests, 2 * (size - 1));
105   return MPI_SUCCESS;
106 }
107
108 int colls::iscatter(const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount,
109                     MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request* request, int external)
110 {
111   const int system_tag = COLL_TAG_SCATTER-external;
112   MPI_Aint lb = 0;
113   MPI_Aint sendext = 0;
114
115   int rank = comm->rank();
116   int size = comm->size();
117   (*request) = new Request( nullptr, 0, MPI_BYTE,
118                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
119   if(rank != root) {
120     auto* requests = new MPI_Request[1];
121     // Recv buffer from root
122     requests[0] = Request::irecv(recvbuf, recvcount, recvtype, root, system_tag, comm);
123     (*request)->set_nbc_requests(requests, 1);
124   } else {
125     sendtype->extent(&lb, &sendext);
126     // Local copy from root
127     if(recvbuf!=MPI_IN_PLACE){
128         Datatype::copy(static_cast<const char *>(sendbuf) + root * sendcount * sendext,
129                            sendcount, sendtype, recvbuf, recvcount, recvtype);
130     }
131     // Send buffers to receivers
132     auto* requests = new MPI_Request[size - 1];
133     int index = 0;
134     for(int dst = 0; dst < size; dst++) {
135       if(dst != root) {
136         requests[index] = Request::isend_init(static_cast<const char *>(sendbuf) + dst * sendcount * sendext, sendcount, sendtype,
137                                           dst, system_tag, comm);
138         index++;
139       }
140     }
141     // Wait for completion of isend's.
142     Request::startall(size - 1, requests);
143     (*request)->set_nbc_requests(requests, size - 1);
144   }
145   return MPI_SUCCESS;
146 }
147
148 int colls::iallgatherv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, const int* recvcounts,
149                        const int* displs, MPI_Datatype recvtype, MPI_Comm comm, MPI_Request* request, int external)
150 {
151   const int system_tag = COLL_TAG_ALLGATHERV-external;
152   MPI_Aint lb = 0;
153   MPI_Aint recvext = 0;
154
155   int rank = comm->rank();
156   int size = comm->size();
157   (*request) = new Request( nullptr, 0, MPI_BYTE,
158                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
159   recvtype->extent(&lb, &recvext);
160   // Local copy from self
161   Datatype::copy(sendbuf, sendcount, sendtype,
162                      static_cast<char *>(recvbuf) + displs[rank] * recvext,recvcounts[rank], recvtype);
163   // Send buffers to others;
164   auto* requests = new MPI_Request[2 * (size - 1)];
165   int index = 0;
166   for (int other = 0; other < size; other++) {
167     if(other != rank) {
168       requests[index] =
169         Request::isend_init(sendbuf, sendcount, sendtype, other, system_tag, comm);
170       index++;
171       requests[index] = Request::irecv_init(static_cast<char *>(recvbuf) + displs[other] * recvext, recvcounts[other],
172                           recvtype, other, system_tag, comm);
173       index++;
174     }
175   }
176   // Wait for completion of all comms.
177   Request::startall(2 * (size - 1), requests);
178   (*request)->set_nbc_requests(requests, 2 * (size - 1));
179   return MPI_SUCCESS;
180 }
181
182 int colls::ialltoall(const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount,
183                      MPI_Datatype recvtype, MPI_Comm comm, MPI_Request* request, int external)
184 {
185   int system_tag   = COLL_TAG_ALLTOALL-external;
186   MPI_Aint lb      = 0;
187   MPI_Aint sendext = 0;
188   MPI_Aint recvext = 0;
189
190   /* Initialize. */
191   int rank = comm->rank();
192   int size = comm->size();
193   (*request) = new Request( nullptr, 0, MPI_BYTE,
194                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
195   sendtype->extent(&lb, &sendext);
196   recvtype->extent(&lb, &recvext);
197   /* simple optimization */
198   int err = Datatype::copy(static_cast<const char *>(sendbuf) + rank * sendcount * sendext, sendcount, sendtype,
199                                static_cast<char *>(recvbuf) + rank * recvcount * recvext, recvcount, recvtype);
200   if (err == MPI_SUCCESS && size > 1) {
201     /* Initiate all send/recv to/from others. */
202     auto* requests = new MPI_Request[2 * (size - 1)];
203     /* Post all receives first -- a simple optimization */
204     int count = 0;
205     for (int i = (rank + 1) % size; i != rank; i = (i + 1) % size) {
206       requests[count] = Request::irecv_init(static_cast<char *>(recvbuf) + i * recvcount * recvext, recvcount,
207                                         recvtype, i, system_tag, comm);
208       count++;
209     }
210     /* Now post all sends in reverse order
211      *   - We would like to minimize the search time through message queue
212      *     when messages actually arrive in the order in which they were posted.
213      * TODO: check the previous assertion
214      */
215     for (int i = (rank + size - 1) % size; i != rank; i = (i + size - 1) % size) {
216       requests[count] = Request::isend_init(static_cast<const char *>(sendbuf) + i * sendcount * sendext, sendcount,
217                                         sendtype, i, system_tag, comm);
218       count++;
219     }
220     /* Wait for them all. */
221     Request::startall(count, requests);
222     (*request)->set_nbc_requests(requests, count);
223   }
224   return MPI_SUCCESS;
225 }
226
227 int colls::ialltoallv(const void* sendbuf, const int* sendcounts, const int* senddisps, MPI_Datatype sendtype,
228                       void* recvbuf, const int* recvcounts, const int* recvdisps, MPI_Datatype recvtype, MPI_Comm comm,
229                       MPI_Request* request, int external)
230 {
231   const int system_tag = COLL_TAG_ALLTOALLV-external;
232   MPI_Aint lb = 0;
233   MPI_Aint sendext = 0;
234   MPI_Aint recvext = 0;
235
236   /* Initialize. */
237   int rank = comm->rank();
238   int size = comm->size();
239   (*request) = new Request( nullptr, 0, MPI_BYTE,
240                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
241   sendtype->extent(&lb, &sendext);
242   recvtype->extent(&lb, &recvext);
243   /* Local copy from self */
244   int err = Datatype::copy(static_cast<const char *>(sendbuf) + senddisps[rank] * sendext, sendcounts[rank], sendtype,
245                                static_cast<char *>(recvbuf) + recvdisps[rank] * recvext, recvcounts[rank], recvtype);
246   if (err == MPI_SUCCESS && size > 1) {
247     /* Initiate all send/recv to/from others. */
248     auto* requests = new MPI_Request[2 * (size - 1)];
249     int count = 0;
250     /* Create all receives that will be posted first */
251     for (int i = 0; i < size; ++i) {
252       if (i != rank) {
253         requests[count] = Request::irecv_init(static_cast<char *>(recvbuf) + recvdisps[i] * recvext,
254                                           recvcounts[i], recvtype, i, system_tag, comm);
255         count++;
256       }else{
257         XBT_DEBUG("<%d> skip request creation [src = %d, recvcounts[src] = %d]", rank, i, recvcounts[i]);
258       }
259     }
260     /* Now create all sends  */
261     for (int i = 0; i < size; ++i) {
262       if (i != rank) {
263       requests[count] = Request::isend_init(static_cast<const char *>(sendbuf) + senddisps[i] * sendext,
264                                         sendcounts[i], sendtype, i, system_tag, comm);
265       count++;
266       }else{
267         XBT_DEBUG("<%d> skip request creation [dst = %d, sendcounts[dst] = %d]", rank, i, sendcounts[i]);
268       }
269     }
270     /* Wait for them all. */
271     Request::startall(count, requests);
272     (*request)->set_nbc_requests(requests, count);
273   }
274   return err;
275 }
276
277 int colls::ialltoallw(const void* sendbuf, const int* sendcounts, const int* senddisps, const MPI_Datatype* sendtypes,
278                       void* recvbuf, const int* recvcounts, const int* recvdisps, const MPI_Datatype* recvtypes,
279                       MPI_Comm comm, MPI_Request* request, int external)
280 {
281   const int system_tag = COLL_TAG_ALLTOALLW-external;
282
283   /* Initialize. */
284   int rank = comm->rank();
285   int size = comm->size();
286   (*request) = new Request( nullptr, 0, MPI_BYTE,
287                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
288   /* Local copy from self */
289   int err = (sendcounts[rank]>0 && recvcounts[rank]) ? Datatype::copy(static_cast<const char *>(sendbuf) + senddisps[rank], sendcounts[rank], sendtypes[rank],
290                                static_cast<char *>(recvbuf) + recvdisps[rank], recvcounts[rank], recvtypes[rank]): MPI_SUCCESS;
291   if (err == MPI_SUCCESS && size > 1) {
292     /* Initiate all send/recv to/from others. */
293     auto* requests = new MPI_Request[2 * (size - 1)];
294     int count = 0;
295     /* Create all receives that will be posted first */
296     for (int i = 0; i < size; ++i) {
297       if (i != rank) {
298         requests[count] = Request::irecv_init(static_cast<char *>(recvbuf) + recvdisps[i],
299                                           recvcounts[i], recvtypes[i], i, system_tag, comm);
300         count++;
301       }else{
302         XBT_DEBUG("<%d> skip request creation [src = %d, recvcounts[src] = %d]", rank, i, recvcounts[i]);
303       }
304     }
305     /* Now create all sends  */
306     for (int i = 0; i < size; ++i) {
307       if (i != rank) {
308       requests[count] = Request::isend_init(static_cast<const char *>(sendbuf) + senddisps[i] ,
309                                         sendcounts[i], sendtypes[i], i, system_tag, comm);
310       count++;
311       }else{
312         XBT_DEBUG("<%d> skip request creation [dst = %d, sendcounts[dst] = %d]", rank, i, sendcounts[i]);
313       }
314     }
315     /* Wait for them all. */
316     Request::startall(count, requests);
317     (*request)->set_nbc_requests(requests, count);
318   }
319   return err;
320 }
321
322 int colls::igather(const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount,
323                    MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request* request, int external)
324 {
325   const int system_tag = COLL_TAG_GATHER-external;
326   MPI_Aint lb = 0;
327   MPI_Aint recvext = 0;
328
329   int rank = comm->rank();
330   int size = comm->size();
331   (*request) = new Request( nullptr, 0, MPI_BYTE,
332                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
333   if(rank != root) {
334     // Send buffer to root
335     auto* requests = new MPI_Request[1];
336     requests[0]=Request::isend(sendbuf, sendcount, sendtype, root, system_tag, comm);
337     (*request)->set_nbc_requests(requests, 1);
338   } else {
339     recvtype->extent(&lb, &recvext);
340     // Local copy from root
341     Datatype::copy(sendbuf, sendcount, sendtype, static_cast<char*>(recvbuf) + root * recvcount * recvext,
342                        recvcount, recvtype);
343     // Receive buffers from senders
344     auto* requests = new MPI_Request[size - 1];
345     int index = 0;
346     for (int src = 0; src < size; src++) {
347       if(src != root) {
348         requests[index] = Request::irecv_init(static_cast<char*>(recvbuf) + src * recvcount * recvext, recvcount, recvtype,
349                                           src, system_tag, comm);
350         index++;
351       }
352     }
353     // Wait for completion of irecv's.
354     Request::startall(size - 1, requests);
355     (*request)->set_nbc_requests(requests, size - 1);
356   }
357   return MPI_SUCCESS;
358 }
359
360 int colls::igatherv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, const int* recvcounts,
361                     const int* displs, MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request* request,
362                     int external)
363 {
364   int system_tag = COLL_TAG_GATHERV-external;
365   MPI_Aint lb = 0;
366   MPI_Aint recvext = 0;
367   
368   int rank = comm->rank();
369   int size = comm->size();
370   (*request) = new Request( nullptr, 0, MPI_BYTE,
371                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
372   if (rank != root) {
373     // Send buffer to root
374     auto* requests = new MPI_Request[1];
375     requests[0]=Request::isend(sendbuf, sendcount, sendtype, root, system_tag, comm);
376     (*request)->set_nbc_requests(requests, 1);
377   } else {
378     recvtype->extent(&lb, &recvext);
379     // Local copy from root
380     Datatype::copy(sendbuf, sendcount, sendtype, static_cast<char*>(recvbuf) + displs[root] * recvext,
381                        recvcounts[root], recvtype);
382     // Receive buffers from senders
383     auto* requests = new MPI_Request[size - 1];
384     int index = 0;
385     for (int src = 0; src < size; src++) {
386       if(src != root) {
387         requests[index] = Request::irecv_init(static_cast<char*>(recvbuf) + displs[src] * recvext,
388                           recvcounts[src], recvtype, src, system_tag, comm);
389         index++;
390       }
391     }
392     // Wait for completion of irecv's.
393     Request::startall(size - 1, requests);
394     (*request)->set_nbc_requests(requests, size - 1);
395   }
396   return MPI_SUCCESS;
397 }
398 int colls::iscatterv(const void* sendbuf, const int* sendcounts, const int* displs, MPI_Datatype sendtype,
399                      void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request* request,
400                      int external)
401 {
402   int system_tag = COLL_TAG_SCATTERV-external;
403   MPI_Aint lb = 0;
404   MPI_Aint sendext = 0;
405
406   int rank = comm->rank();
407   int size = comm->size();
408   (*request) = new Request( nullptr, 0, MPI_BYTE,
409                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
410   if(rank != root) {
411     // Recv buffer from root
412     auto* requests = new MPI_Request[1];
413     requests[0]=Request::irecv(recvbuf, recvcount, recvtype, root, system_tag, comm);
414     (*request)->set_nbc_requests(requests, 1);
415   } else {
416     sendtype->extent(&lb, &sendext);
417     // Local copy from root
418     if(recvbuf!=MPI_IN_PLACE){
419       Datatype::copy(static_cast<const char *>(sendbuf) + displs[root] * sendext, sendcounts[root],
420                        sendtype, recvbuf, recvcount, recvtype);
421     }
422     // Send buffers to receivers
423     auto* requests = new MPI_Request[size - 1];
424     int index = 0;
425     for (int dst = 0; dst < size; dst++) {
426       if (dst != root) {
427         requests[index] = Request::isend_init(static_cast<const char *>(sendbuf) + displs[dst] * sendext, sendcounts[dst],
428                             sendtype, dst, system_tag, comm);
429         index++;
430       }
431     }
432     // Wait for completion of isend's.
433     Request::startall(size - 1, requests);
434     (*request)->set_nbc_requests(requests, size - 1);
435   }
436   return MPI_SUCCESS;
437 }
438
439 int colls::ireduce(const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root,
440                    MPI_Comm comm, MPI_Request* request, int external)
441 {
442   const int system_tag = COLL_TAG_REDUCE-external;
443   MPI_Aint lb = 0;
444   MPI_Aint dataext = 0;
445
446   const void* real_sendbuf = sendbuf;
447
448   int rank = comm->rank();
449   int size = comm->size();
450
451   if (size <= 0)
452     return MPI_ERR_COMM;
453
454   unsigned char* tmp_sendbuf = nullptr;
455   if( sendbuf == MPI_IN_PLACE ) {
456     tmp_sendbuf = smpi_get_tmp_sendbuffer(count * datatype->get_extent());
457     Datatype::copy(recvbuf, count, datatype, tmp_sendbuf, count, datatype);
458     real_sendbuf = tmp_sendbuf;
459   }
460
461   if(rank == root){
462     (*request) =  new Request( recvbuf, count, datatype,
463                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
464   }
465   else
466     (*request) = new Request( nullptr, count, datatype,
467                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
468
469   if(rank != root) {
470     // Send buffer to root
471     auto* requests        = new MPI_Request[1];
472     requests[0]           = Request::isend(real_sendbuf, count, datatype, root, system_tag, comm);
473     (*request)->set_nbc_requests(requests, 1);
474   } else {
475     datatype->extent(&lb, &dataext);
476     // Local copy from root
477     if (real_sendbuf != nullptr && recvbuf != nullptr)
478       Datatype::copy(real_sendbuf, count, datatype, recvbuf, count, datatype);
479     // Receive buffers from senders
480     auto* requests = new MPI_Request[size - 1];
481     int index = 0;
482     for (int src = 0; src < size; src++) {
483       if (src != root) {
484         requests[index] =
485           Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype, src, system_tag, comm);
486         index++;
487       }
488     }
489     // Wait for completion of irecv's.
490     Request::startall(size - 1, requests);
491     (*request)->set_nbc_requests(requests, size - 1);
492   }     
493   if( sendbuf == MPI_IN_PLACE ) {
494     smpi_free_tmp_buffer(tmp_sendbuf);
495   }
496   return MPI_SUCCESS;
497 }
498
499 int colls::iallreduce(const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm,
500                       MPI_Request* request, int external)
501 {
502
503   const int system_tag = COLL_TAG_ALLREDUCE-external;
504   MPI_Aint lb = 0;
505   MPI_Aint dataext = 0;
506
507   int rank = comm->rank();
508   int size = comm->size();
509   (*request) = new Request( recvbuf, count, datatype,
510                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
511   // FIXME: check for errors
512   datatype->extent(&lb, &dataext);
513   // Local copy from self
514   Datatype::copy(sendbuf, count, datatype, recvbuf, count, datatype);
515   // Send/Recv buffers to/from others;
516   auto* requests = new MPI_Request[2 * (size - 1)];
517   int index = 0;
518   for (int other = 0; other < size; other++) {
519     if(other != rank) {
520       requests[index] = Request::isend_init(sendbuf, count, datatype, other, system_tag,comm);
521       index++;
522       requests[index] = Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype,
523                                         other, system_tag, comm);
524       index++;
525     }
526   }
527   Request::startall(2 * (size - 1), requests);
528   (*request)->set_nbc_requests(requests, 2 * (size - 1));
529   return MPI_SUCCESS;
530 }
531
532 int colls::iscan(const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm,
533                  MPI_Request* request, int external)
534 {
535   int system_tag = -888-external;
536   MPI_Aint lb      = 0;
537   MPI_Aint dataext = 0;
538
539   int rank = comm->rank();
540   int size = comm->size();
541   (*request) = new Request( recvbuf, count, datatype,
542                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
543   datatype->extent(&lb, &dataext);
544
545   // Local copy from self
546   Datatype::copy(sendbuf, count, datatype, recvbuf, count, datatype);
547
548   // Send/Recv buffers to/from others
549   auto* requests = new MPI_Request[size - 1];
550   int index = 0;
551   for (int other = 0; other < rank; other++) {
552     requests[index] = Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype, other, system_tag, comm);
553     index++;
554   }
555   for (int other = rank + 1; other < size; other++) {
556     requests[index] = Request::isend_init(sendbuf, count, datatype, other, system_tag, comm);
557     index++;
558   }
559   // Wait for completion of all comms.
560   Request::startall(size - 1, requests);
561   (*request)->set_nbc_requests(requests, size - 1);
562   return MPI_SUCCESS;
563 }
564
565 int colls::iexscan(const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm,
566                    MPI_Request* request, int external)
567 {
568   int system_tag = -888-external;
569   MPI_Aint lb         = 0;
570   MPI_Aint dataext    = 0;
571   int rank = comm->rank();
572   int size = comm->size();
573   (*request) = new Request( recvbuf, count, datatype,
574                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
575   datatype->extent(&lb, &dataext);
576   if(rank != 0)
577     memset(recvbuf, 0, count*dataext);
578
579   // Send/Recv buffers to/from others
580   auto* requests = new MPI_Request[size - 1];
581   int index = 0;
582   for (int other = 0; other < rank; other++) {
583     requests[index] = Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype, other, system_tag, comm);
584     index++;
585   }
586   for (int other = rank + 1; other < size; other++) {
587     requests[index] = Request::isend_init(sendbuf, count, datatype, other, system_tag, comm);
588     index++;
589   }
590   // Wait for completion of all comms.
591   Request::startall(size - 1, requests);
592   (*request)->set_nbc_requests(requests, size - 1);
593   return MPI_SUCCESS;
594 }
595
596 int colls::ireduce_scatter(const void* sendbuf, void* recvbuf, const int* recvcounts, MPI_Datatype datatype, MPI_Op op,
597                            MPI_Comm comm, MPI_Request* request, int external)
598 {
599   // Version where each process performs the reduce for its own part. Alltoall pattern for comms.
600   const int system_tag = COLL_TAG_REDUCE_SCATTER-external;
601   MPI_Aint lb = 0;
602   MPI_Aint dataext = 0;
603
604   int rank = comm->rank();
605   int size = comm->size();
606   int count=recvcounts[rank];
607   (*request) = new Request( recvbuf, count, datatype,
608                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
609   datatype->extent(&lb, &dataext);
610
611   // Send/Recv buffers to/from others;
612   auto* requests = new MPI_Request[2 * (size - 1)];
613   int index = 0;
614   int recvdisp=0;
615   for (int other = 0; other < size; other++) {
616     if(other != rank) {
617       requests[index] = Request::isend_init(static_cast<const char *>(sendbuf) + recvdisp * dataext, recvcounts[other], datatype, other, system_tag,comm);
618       XBT_VERB("sending with recvdisp %d", recvdisp);
619       index++;
620       requests[index] = Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype,
621                                         other, system_tag, comm);
622       index++;
623     }else{
624       Datatype::copy(static_cast<const char *>(sendbuf) + recvdisp * dataext, count, datatype, recvbuf, count, datatype);
625     }
626     recvdisp+=recvcounts[other];
627   }
628   Request::startall(2 * (size - 1), requests);
629   (*request)->set_nbc_requests(requests, 2 * (size - 1));
630   return MPI_SUCCESS;
631 }
632
633 }
634 }