Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Unlike errors on communicators and windows, the default behavior for files is to...
[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-2019. 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
15 int Colls::ibarrier(MPI_Comm comm, MPI_Request* request, int external)
16 {
17   int size = comm->size();
18   int rank = comm->rank();
19   int system_tag=COLL_TAG_BARRIER-external;
20   (*request) = new Request( nullptr, 0, MPI_BYTE,
21                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
22   if (rank > 0) {
23     MPI_Request* requests = new MPI_Request[2];
24     requests[0] = Request::isend (nullptr, 0, MPI_BYTE, 0,
25                              system_tag,
26                              comm);
27     requests[1] = Request::irecv (nullptr, 0, MPI_BYTE, 0,
28                              system_tag,
29                              comm);
30     (*request)->set_nbc_requests(requests, 2);
31   }
32   else {
33     MPI_Request* requests = new MPI_Request[(size - 1) * 2];
34     for (int i = 1; i < 2 * size - 1; i += 2) {
35       requests[i - 1] = Request::irecv(nullptr, 0, MPI_BYTE, MPI_ANY_SOURCE, system_tag, comm);
36       requests[i]     = Request::isend(nullptr, 0, MPI_BYTE, (i + 1) / 2, system_tag, comm);
37     }
38     (*request)->set_nbc_requests(requests, 2*(size-1));
39   }
40   return MPI_SUCCESS;
41 }
42
43 int Colls::ibcast(void *buf, int count, MPI_Datatype datatype, int root, MPI_Comm comm, MPI_Request* request, 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     MPI_Request* 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     MPI_Request* 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,
75                         void *recvbuf,int recvcount, 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   MPI_Request* 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,
109                       void *recvbuf, int recvcount, 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     MPI_Request* 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     MPI_Request* 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,
149                          const int *recvcounts, 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   MPI_Request *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, MPI_Datatype recvtype, MPI_Comm comm, MPI_Request* request, int external){
183   int system_tag   = COLL_TAG_ALLTOALL-external;
184   MPI_Aint lb      = 0;
185   MPI_Aint sendext = 0;
186   MPI_Aint recvext = 0;
187
188   /* Initialize. */
189   int rank = comm->rank();
190   int size = comm->size();
191   (*request) = new Request( nullptr, 0, MPI_BYTE,
192                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
193   sendtype->extent(&lb, &sendext);
194   recvtype->extent(&lb, &recvext);
195   /* simple optimization */
196   int err = Datatype::copy(static_cast<const char *>(sendbuf) + rank * sendcount * sendext, sendcount, sendtype,
197                                static_cast<char *>(recvbuf) + rank * recvcount * recvext, recvcount, recvtype);
198   if (err == MPI_SUCCESS && size > 1) {
199     /* Initiate all send/recv to/from others. */
200     MPI_Request* requests = new MPI_Request[2 * (size - 1)];
201     /* Post all receives first -- a simple optimization */
202     int count = 0;
203     for (int i = (rank + 1) % size; i != rank; i = (i + 1) % size) {
204       requests[count] = Request::irecv_init(static_cast<char *>(recvbuf) + i * recvcount * recvext, recvcount,
205                                         recvtype, i, system_tag, comm);
206       count++;
207     }
208     /* Now post all sends in reverse order
209      *   - We would like to minimize the search time through message queue
210      *     when messages actually arrive in the order in which they were posted.
211      * TODO: check the previous assertion
212      */
213     for (int i = (rank + size - 1) % size; i != rank; i = (i + size - 1) % size) {
214       requests[count] = Request::isend_init(static_cast<const char *>(sendbuf) + i * sendcount * sendext, sendcount,
215                                         sendtype, i, system_tag, comm);
216       count++;
217     }
218     /* Wait for them all. */
219     Request::startall(count, requests);
220     (*request)->set_nbc_requests(requests, count);
221   }
222   return MPI_SUCCESS;
223 }
224
225 int Colls::ialltoallv(const void *sendbuf, const int *sendcounts, const int *senddisps, MPI_Datatype sendtype,
226                               void *recvbuf, const int *recvcounts, const int *recvdisps, MPI_Datatype recvtype, MPI_Comm comm, MPI_Request *request, int external){
227   const int system_tag = COLL_TAG_ALLTOALLV-external;
228   MPI_Aint lb = 0;
229   MPI_Aint sendext = 0;
230   MPI_Aint recvext = 0;
231
232   /* Initialize. */
233   int rank = comm->rank();
234   int size = comm->size();
235   (*request) = new Request( nullptr, 0, MPI_BYTE,
236                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
237   sendtype->extent(&lb, &sendext);
238   recvtype->extent(&lb, &recvext);
239   /* Local copy from self */
240   int err = Datatype::copy(static_cast<const char *>(sendbuf) + senddisps[rank] * sendext, sendcounts[rank], sendtype,
241                                static_cast<char *>(recvbuf) + recvdisps[rank] * recvext, recvcounts[rank], recvtype);
242   if (err == MPI_SUCCESS && size > 1) {
243     /* Initiate all send/recv to/from others. */
244     MPI_Request* requests = new MPI_Request[2 * (size - 1)];
245     int count = 0;
246     /* Create all receives that will be posted first */
247     for (int i = 0; i < size; ++i) {
248       if (i != rank) {
249         requests[count] = Request::irecv_init(static_cast<char *>(recvbuf) + recvdisps[i] * recvext,
250                                           recvcounts[i], recvtype, i, system_tag, comm);
251         count++;
252       }else{
253         XBT_DEBUG("<%d> skip request creation [src = %d, recvcounts[src] = %d]", rank, i, recvcounts[i]);
254       }
255     }
256     /* Now create all sends  */
257     for (int i = 0; i < size; ++i) {
258       if (i != rank) {
259       requests[count] = Request::isend_init(static_cast<const char *>(sendbuf) + senddisps[i] * sendext,
260                                         sendcounts[i], sendtype, i, system_tag, comm);
261       count++;
262       }else{
263         XBT_DEBUG("<%d> skip request creation [dst = %d, sendcounts[dst] = %d]", rank, i, sendcounts[i]);
264       }
265     }
266     /* Wait for them all. */
267     Request::startall(count, requests);
268     (*request)->set_nbc_requests(requests, count);
269   }
270   return err;
271 }
272
273 int Colls::ialltoallw(const void *sendbuf, const int *sendcounts, const int *senddisps, const MPI_Datatype* sendtypes,
274                               void *recvbuf, const int *recvcounts, const int *recvdisps, const MPI_Datatype* recvtypes, MPI_Comm comm, MPI_Request *request, int external){
275   const int system_tag = COLL_TAG_ALLTOALLW-external;
276
277   /* Initialize. */
278   int rank = comm->rank();
279   int size = comm->size();
280   (*request) = new Request( nullptr, 0, MPI_BYTE,
281                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
282   /* Local copy from self */
283   int err = (sendcounts[rank]>0 && recvcounts[rank]) ? Datatype::copy(static_cast<const char *>(sendbuf) + senddisps[rank], sendcounts[rank], sendtypes[rank],
284                                static_cast<char *>(recvbuf) + recvdisps[rank], recvcounts[rank], recvtypes[rank]): MPI_SUCCESS;
285   if (err == MPI_SUCCESS && size > 1) {
286     /* Initiate all send/recv to/from others. */
287     MPI_Request* requests = new MPI_Request[2 * (size - 1)];
288     int count = 0;
289     /* Create all receives that will be posted first */
290     for (int i = 0; i < size; ++i) {
291       if (i != rank) {
292         requests[count] = Request::irecv_init(static_cast<char *>(recvbuf) + recvdisps[i],
293                                           recvcounts[i], recvtypes[i], i, system_tag, comm);
294         count++;
295       }else{
296         XBT_DEBUG("<%d> skip request creation [src = %d, recvcounts[src] = %d]", rank, i, recvcounts[i]);
297       }
298     }
299     /* Now create all sends  */
300     for (int i = 0; i < size; ++i) {
301       if (i != rank) {
302       requests[count] = Request::isend_init(static_cast<const char *>(sendbuf) + senddisps[i] ,
303                                         sendcounts[i], sendtypes[i], i, system_tag, comm);
304       count++;
305       }else{
306         XBT_DEBUG("<%d> skip request creation [dst = %d, sendcounts[dst] = %d]", rank, i, sendcounts[i]);
307       }
308     }
309     /* Wait for them all. */
310     Request::startall(count, requests);
311     (*request)->set_nbc_requests(requests, count);
312   }
313   return err;
314 }
315
316 int Colls::igather(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
317                      void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request *request, int external)
318 {
319   const int system_tag = COLL_TAG_GATHER-external;
320   MPI_Aint lb = 0;
321   MPI_Aint recvext = 0;
322
323   int rank = comm->rank();
324   int size = comm->size();
325   (*request) = new Request( nullptr, 0, MPI_BYTE,
326                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
327   if(rank != root) {
328     // Send buffer to root
329     MPI_Request* requests = new MPI_Request[1];
330     requests[0]=Request::isend(sendbuf, sendcount, sendtype, root, system_tag, comm);
331     (*request)->set_nbc_requests(requests, 1);
332   } else {
333     recvtype->extent(&lb, &recvext);
334     // Local copy from root
335     Datatype::copy(sendbuf, sendcount, sendtype, static_cast<char*>(recvbuf) + root * recvcount * recvext,
336                        recvcount, recvtype);
337     // Receive buffers from senders
338     MPI_Request* requests = new MPI_Request[size - 1];
339     int index = 0;
340     for (int src = 0; src < size; src++) {
341       if(src != root) {
342         requests[index] = Request::irecv_init(static_cast<char*>(recvbuf) + src * recvcount * recvext, recvcount, recvtype,
343                                           src, system_tag, comm);
344         index++;
345       }
346     }
347     // Wait for completion of irecv's.
348     Request::startall(size - 1, requests);
349     (*request)->set_nbc_requests(requests, size - 1);
350   }
351   return MPI_SUCCESS;
352 }
353
354 int Colls::igatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int *recvcounts, const int *displs,
355                       MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request *request, int external)
356 {
357   int system_tag = COLL_TAG_GATHERV-external;
358   MPI_Aint lb = 0;
359   MPI_Aint recvext = 0;
360   
361   int rank = comm->rank();
362   int size = comm->size();
363   (*request) = new Request( nullptr, 0, MPI_BYTE,
364                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
365   if (rank != root) {
366     // Send buffer to root
367     MPI_Request* requests = new MPI_Request[1];
368     requests[0]=Request::isend(sendbuf, sendcount, sendtype, root, system_tag, comm);
369     (*request)->set_nbc_requests(requests, 1);
370   } else {
371     recvtype->extent(&lb, &recvext);
372     // Local copy from root
373     Datatype::copy(sendbuf, sendcount, sendtype, static_cast<char*>(recvbuf) + displs[root] * recvext,
374                        recvcounts[root], recvtype);
375     // Receive buffers from senders
376     MPI_Request* requests = new MPI_Request[size - 1];
377     int index = 0;
378     for (int src = 0; src < size; src++) {
379       if(src != root) {
380         requests[index] = Request::irecv_init(static_cast<char*>(recvbuf) + displs[src] * recvext,
381                           recvcounts[src], recvtype, src, system_tag, comm);
382         index++;
383       }
384     }
385     // Wait for completion of irecv's.
386     Request::startall(size - 1, requests);
387     (*request)->set_nbc_requests(requests, size - 1);
388   }
389   return MPI_SUCCESS;
390 }
391 int Colls::iscatterv(const void *sendbuf, const int *sendcounts, const int *displs, MPI_Datatype sendtype, void *recvbuf, int recvcount,
392                        MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request *request, int external)
393 {
394   int system_tag = COLL_TAG_SCATTERV-external;
395   MPI_Aint lb = 0;
396   MPI_Aint sendext = 0;
397
398   int rank = comm->rank();
399   int size = comm->size();
400   (*request) = new Request( nullptr, 0, MPI_BYTE,
401                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
402   if(rank != root) {
403     // Recv buffer from root
404     MPI_Request* requests = new MPI_Request[1];
405     requests[0]=Request::irecv(recvbuf, recvcount, recvtype, root, system_tag, comm);
406     (*request)->set_nbc_requests(requests, 1);
407   } else {
408     sendtype->extent(&lb, &sendext);
409     // Local copy from root
410     if(recvbuf!=MPI_IN_PLACE){
411       Datatype::copy(static_cast<const char *>(sendbuf) + displs[root] * sendext, sendcounts[root],
412                        sendtype, recvbuf, recvcount, recvtype);
413     }
414     // Send buffers to receivers
415     MPI_Request *requests = new MPI_Request[size - 1];
416     int index = 0;
417     for (int dst = 0; dst < size; dst++) {
418       if (dst != root) {
419         requests[index] = Request::isend_init(static_cast<const char *>(sendbuf) + displs[dst] * sendext, sendcounts[dst],
420                             sendtype, dst, system_tag, comm);
421         index++;
422       }
423     }
424     // Wait for completion of isend's.
425     Request::startall(size - 1, requests);
426     (*request)->set_nbc_requests(requests, size - 1);
427   }
428   return MPI_SUCCESS;
429 }
430
431 int Colls::ireduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root,
432                      MPI_Comm comm, MPI_Request* request, int external)
433 {
434   const int system_tag = COLL_TAG_REDUCE-external;
435   MPI_Aint lb = 0;
436   MPI_Aint dataext = 0;
437
438   const void* real_sendbuf = sendbuf;
439
440   int rank = comm->rank();
441   int size = comm->size();
442
443   if (size <= 0)
444     return MPI_ERR_COMM;
445
446   unsigned char* tmp_sendbuf = nullptr;
447   if( sendbuf == MPI_IN_PLACE ) {
448     tmp_sendbuf = smpi_get_tmp_sendbuffer(count * datatype->get_extent());
449     Datatype::copy(recvbuf, count, datatype, tmp_sendbuf, count, datatype);
450     real_sendbuf = tmp_sendbuf;
451   }
452
453   if(rank == root){
454     (*request) =  new Request( recvbuf, count, datatype,
455                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
456   }
457   else
458     (*request) = new Request( nullptr, count, datatype,
459                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT);
460
461   if(rank != root) {
462     // Send buffer to root
463     MPI_Request* requests = new MPI_Request[1];
464     requests[0]           = Request::isend(real_sendbuf, count, datatype, root, system_tag, comm);
465     (*request)->set_nbc_requests(requests, 1);
466   } else {
467     datatype->extent(&lb, &dataext);
468     // Local copy from root
469     if (real_sendbuf != nullptr && recvbuf != nullptr)
470       Datatype::copy(real_sendbuf, count, datatype, recvbuf, count, datatype);
471     // Receive buffers from senders
472     MPI_Request *requests = new MPI_Request[size - 1];
473     int index = 0;
474     for (int src = 0; src < size; src++) {
475       if (src != root) {
476         requests[index] =
477           Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype, src, system_tag, comm);
478         index++;
479       }
480     }
481     // Wait for completion of irecv's.
482     Request::startall(size - 1, requests);
483     (*request)->set_nbc_requests(requests, size - 1);
484   }     
485   if( sendbuf == MPI_IN_PLACE ) {
486     smpi_free_tmp_buffer(tmp_sendbuf);
487   }
488   return MPI_SUCCESS;
489 }
490
491 int Colls::iallreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,
492                       MPI_Op op, MPI_Comm comm, MPI_Request* request, int external)
493 {
494
495   const int system_tag = COLL_TAG_ALLREDUCE-external;
496   MPI_Aint lb = 0;
497   MPI_Aint dataext = 0;
498
499   int rank = comm->rank();
500   int size = comm->size();
501   (*request) = new Request( recvbuf, count, datatype,
502                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
503   // FIXME: check for errors
504   datatype->extent(&lb, &dataext);
505   // Local copy from self
506   Datatype::copy(sendbuf, count, datatype, recvbuf, count, datatype);
507   // Send/Recv buffers to/from others;
508   MPI_Request* requests = new MPI_Request[2 * (size - 1)];
509   int index = 0;
510   for (int other = 0; other < size; other++) {
511     if(other != rank) {
512       requests[index] = Request::isend_init(sendbuf, count, datatype, other, system_tag,comm);
513       index++;
514       requests[index] = Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype,
515                                         other, system_tag, comm);
516       index++;
517     }
518   }
519   Request::startall(2 * (size - 1), requests);
520   (*request)->set_nbc_requests(requests, 2 * (size - 1));
521   return MPI_SUCCESS;
522 }
523
524 int Colls::iscan(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, MPI_Request* request, int external)
525 {
526   int system_tag = -888-external;
527   MPI_Aint lb      = 0;
528   MPI_Aint dataext = 0;
529
530   int rank = comm->rank();
531   int size = comm->size();
532   (*request) = new Request( recvbuf, count, datatype,
533                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
534   datatype->extent(&lb, &dataext);
535
536   // Local copy from self
537   Datatype::copy(sendbuf, count, datatype, recvbuf, count, datatype);
538
539   // Send/Recv buffers to/from others
540   MPI_Request *requests = new MPI_Request[size - 1];
541   int index = 0;
542   for (int other = 0; other < rank; other++) {
543     requests[index] = Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype, other, system_tag, comm);
544     index++;
545   }
546   for (int other = rank + 1; other < size; other++) {
547     requests[index] = Request::isend_init(sendbuf, count, datatype, other, system_tag, comm);
548     index++;
549   }
550   // Wait for completion of all comms.
551   Request::startall(size - 1, requests);
552   (*request)->set_nbc_requests(requests, size - 1);
553   return MPI_SUCCESS;
554 }
555
556 int Colls::iexscan(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, MPI_Request* request, int external)
557 {
558   int system_tag = -888-external;
559   MPI_Aint lb         = 0;
560   MPI_Aint dataext    = 0;
561   int rank = comm->rank();
562   int size = comm->size();
563   (*request) = new Request( recvbuf, count, datatype,
564                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
565   datatype->extent(&lb, &dataext);
566   if(rank != 0)
567     memset(recvbuf, 0, count*dataext);
568
569   // Send/Recv buffers to/from others
570   MPI_Request *requests = new MPI_Request[size - 1];
571   int index = 0;
572   for (int other = 0; other < rank; other++) {
573     requests[index] = Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype, other, system_tag, comm);
574     index++;
575   }
576   for (int other = rank + 1; other < size; other++) {
577     requests[index] = Request::isend_init(sendbuf, count, datatype, other, system_tag, comm);
578     index++;
579   }
580   // Wait for completion of all comms.
581   Request::startall(size - 1, requests);
582   (*request)->set_nbc_requests(requests, size - 1);
583   return MPI_SUCCESS;
584 }
585
586 int Colls::ireduce_scatter(const void *sendbuf, void *recvbuf, const int *recvcounts, MPI_Datatype datatype, MPI_Op op,
587                              MPI_Comm comm, MPI_Request* request, int external){
588 //Version where each process performs the reduce for its own part. Alltoall pattern for comms.
589   const int system_tag = COLL_TAG_REDUCE_SCATTER-external;
590   MPI_Aint lb = 0;
591   MPI_Aint dataext = 0;
592
593   int rank = comm->rank();
594   int size = comm->size();
595   int count=recvcounts[rank];
596   (*request) = new Request( recvbuf, count, datatype,
597                          rank,rank, system_tag, comm, MPI_REQ_PERSISTENT, op);
598   datatype->extent(&lb, &dataext);
599
600   // Send/Recv buffers to/from others;
601   MPI_Request* requests = new MPI_Request[2 * (size - 1)];
602   int index = 0;
603   int recvdisp=0;
604   for (int other = 0; other < size; other++) {
605     if(other != rank) {
606       requests[index] = Request::isend_init(static_cast<const char *>(sendbuf) + recvdisp * dataext, recvcounts[other], datatype, other, system_tag,comm);
607       XBT_VERB("sending with recvdisp %d", recvdisp);
608       index++;
609       requests[index] = Request::irecv_init(smpi_get_tmp_sendbuffer(count * dataext), count, datatype,
610                                         other, system_tag, comm);
611       index++;
612     }else{
613       Datatype::copy(static_cast<const char *>(sendbuf) + recvdisp * dataext, count, datatype, recvbuf, count, datatype);
614     }
615     recvdisp+=recvcounts[other];
616   }
617   Request::startall(2 * (size - 1), requests);
618   (*request)->set_nbc_requests(requests, 2 * (size - 1));
619   return MPI_SUCCESS;
620 }
621
622 }
623 }