Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' into actor-yield
[simgrid.git] / src / smpi / colls / allgatherv / allgatherv-mpich-ring.cpp
1 /* Copyright (c) 2013-2017. The SimGrid Team.
2  * All rights reserved.                                                     */
3
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. */
6
7 /*
8  *
9  *  (C) 2001 by Argonne National Laboratory.
10  *      See COPYRIGHT in top-level directory.
11  */
12
13 #include "../colls_private.hpp"
14
15 /*****************************************************************************
16  * Function: allgather_mpich_ring
17  * return: int
18  * inputs:
19  *   send_buff: send input buffer
20  *   send_count: number of elements to send
21  *   send_type: data type of elements being sent
22  *   recv_buff: receive output buffer
23  *   recv_count: number of elements to received
24  *   recv_type: data type of elements being received
25  *   comm: communication
26  ****************************************************************************/
27
28 namespace simgrid{
29 namespace smpi{
30
31 int
32 Coll_allgatherv_mpich_ring::allgatherv(void *sendbuf, int sendcount,
33     MPI_Datatype send_type, void *recvbuf,
34     int *recvcounts, int *displs, MPI_Datatype recvtype,
35     MPI_Comm comm)
36 {
37
38   char * sbuf = NULL, * rbuf = NULL;
39   int soffset, roffset;
40   int torecv=0, tosend=0, min, rank, comm_size;
41   int sendnow, recvnow;
42   int sidx, ridx;
43   MPI_Status status;
44   MPI_Aint recvtype_extent;
45   int right, left, total_count, i;
46   rank= comm->rank();
47   comm_size=comm->size();
48
49   recvtype_extent= recvtype->get_extent();
50   total_count = 0;
51   for (i=0; i<comm_size; i++)
52     total_count += recvcounts[i];
53
54   if (sendbuf != MPI_IN_PLACE) {
55       /* First, load the "local" version in the recvbuf. */
56       Datatype::copy(sendbuf, sendcount, send_type,
57           ((char *)recvbuf + displs[rank]*recvtype_extent),
58           recvcounts[rank], recvtype);
59   }
60
61   left  = (comm_size + rank - 1) % comm_size;
62   right = (rank + 1) % comm_size;
63
64   torecv = total_count - recvcounts[rank];
65   tosend = total_count - recvcounts[right];
66
67   min = recvcounts[0];
68   for (i = 1; i < comm_size; i++)
69     if (min > recvcounts[i])
70       min = recvcounts[i];
71   if (min * recvtype_extent < 32768*8)
72     min = 32768*8 / recvtype_extent;
73   /* Handle the case where the datatype extent is larger than
74    * the pipeline size. */
75   if (not min)
76     min = 1;
77
78   sidx = rank;
79   ridx = left;
80   soffset = 0;
81   roffset = 0;
82   while (tosend || torecv) { /* While we have data to send or receive */
83       sendnow = ((recvcounts[sidx] - soffset) > min) ? min : (recvcounts[sidx] - soffset);
84       recvnow = ((recvcounts[ridx] - roffset) > min) ? min : (recvcounts[ridx] - roffset);
85       sbuf = (char *)recvbuf + ((displs[sidx] + soffset) * recvtype_extent);
86       rbuf = (char *)recvbuf + ((displs[ridx] + roffset) * recvtype_extent);
87
88       /* Protect against wrap-around of indices */
89       if (not tosend)
90         sendnow = 0;
91       if (not torecv)
92         recvnow = 0;
93
94       /* Communicate */
95       if (not sendnow && not recvnow) {
96         /* Don't do anything. This case is possible if two
97          * consecutive processes contribute 0 bytes each. */
98       } else if (not sendnow) { /* If there's no data to send, just do a recv call */
99         Request::recv(rbuf, recvnow, recvtype, left, COLL_TAG_ALLGATHERV, comm, &status);
100
101         torecv -= recvnow;
102       } else if (not recvnow) { /* If there's no data to receive, just do a send call */
103         Request::send(sbuf, sendnow, recvtype, right, COLL_TAG_ALLGATHERV, comm);
104
105         tosend -= sendnow;
106       }
107       else { /* There's data to be sent and received */
108           Request::sendrecv(sbuf, sendnow, recvtype, right, COLL_TAG_ALLGATHERV,
109               rbuf, recvnow, recvtype, left, COLL_TAG_ALLGATHERV,
110               comm, &status);
111           tosend -= sendnow;
112           torecv -= recvnow;
113       }
114
115       soffset += sendnow;
116       roffset += recvnow;
117       if (soffset == recvcounts[sidx]) {
118           soffset = 0;
119           sidx = (sidx + comm_size - 1) % comm_size;
120       }
121       if (roffset == recvcounts[ridx]) {
122           roffset = 0;
123           ridx = (ridx + comm_size - 1) % comm_size;
124       }
125   }
126
127   return MPI_SUCCESS;
128 }
129
130 }
131 }