Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Big move of all SMPI files in subfolders because it was a mess.
[simgrid.git] / src / smpi / colls / allgatherv / allgatherv-mpich-rdb.cpp
1 /* Copyright (c) 2013-2017. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 /* Short or medium size message and power-of-two no. of processes. Use
7  * recursive doubling algorithm */
8
9 #include "../colls_private.h"
10 #include "smpi_status.hpp"
11
12 namespace simgrid{
13 namespace smpi{
14
15 int Coll_allgatherv_mpich_rdb::allgatherv (
16   void *sendbuf,
17   int sendcount,
18   MPI_Datatype sendtype,
19   void *recvbuf,
20   int *recvcounts,
21   int *displs,
22   MPI_Datatype recvtype,
23   MPI_Comm comm)
24 {
25   unsigned int  j, i;
26   MPI_Status status;
27   MPI_Aint  recvtype_extent, recvtype_true_extent, recvtype_true_lb;
28   unsigned int curr_cnt, dst, total_count;
29   void *tmp_buf, *tmp_buf_rl;
30   unsigned int mask, dst_tree_root, my_tree_root, position,
31     send_offset, recv_offset, last_recv_cnt=0, nprocs_completed, k,
32     offset, tmp_mask, tree_root;
33
34   unsigned int comm_size = comm->size();
35   unsigned int rank = comm->rank();
36
37   total_count = 0;
38   for (i=0; i<comm_size; i++)
39     total_count += recvcounts[i];
40
41   if (total_count == 0)
42     return MPI_ERR_COUNT;
43
44   recvtype_extent=recvtype->get_extent();
45
46   /* need to receive contiguously into tmp_buf because
47      displs could make the recvbuf noncontiguous */
48
49   recvtype->extent(&recvtype_true_lb, &recvtype_true_extent);
50
51   tmp_buf_rl= (void*)smpi_get_tmp_sendbuffer(total_count*(MAX(recvtype_true_extent,recvtype_extent)));
52
53   /* adjust for potential negative lower bound in datatype */
54   tmp_buf = (void *)((char*)tmp_buf_rl - recvtype_true_lb);
55
56   /* copy local data into right location in tmp_buf */
57   position = 0;
58   for (i=0; i<rank; i++)
59     position += recvcounts[i];
60   if (sendbuf != MPI_IN_PLACE)
61   {
62     Datatype::copy(sendbuf, sendcount, sendtype,
63                        ((char *)tmp_buf + position*
64                         recvtype_extent),
65                        recvcounts[rank], recvtype);
66   }
67   else
68   {
69     /* if in_place specified, local data is found in recvbuf */
70     Datatype::copy(((char *)recvbuf +
71                         displs[rank]*recvtype_extent),
72                        recvcounts[rank], recvtype,
73                        ((char *)tmp_buf + position*
74                         recvtype_extent),
75                        recvcounts[rank], recvtype);
76   }
77   curr_cnt = recvcounts[rank];
78
79   mask = 0x1;
80   i = 0;
81   while (mask < comm_size) {
82     dst = rank ^ mask;
83
84     /* find offset into send and recv buffers. zero out
85        the least significant "i" bits of rank and dst to
86        find root of src and dst subtrees. Use ranks of
87        roots as index to send from and recv into buffer */
88
89     dst_tree_root = dst >> i;
90     dst_tree_root <<= i;
91
92     my_tree_root = rank >> i;
93     my_tree_root <<= i;
94
95     if (dst < comm_size) {
96       send_offset = 0;
97       for (j=0; j<my_tree_root; j++)
98         send_offset += recvcounts[j];
99
100       recv_offset = 0;
101       for (j=0; j<dst_tree_root; j++)
102         recv_offset += recvcounts[j];
103
104       Request::sendrecv(((char *)tmp_buf + send_offset * recvtype_extent),
105                         curr_cnt, recvtype, dst,
106                         COLL_TAG_ALLGATHERV,
107                         ((char *)tmp_buf + recv_offset * recvtype_extent),
108                         total_count - recv_offset, recvtype, dst,
109                         COLL_TAG_ALLGATHERV,
110                         comm, &status);
111       /* for convenience, recv is posted for a bigger amount
112          than will be sent */
113       last_recv_cnt=Status::get_count(&status, recvtype);
114       curr_cnt += last_recv_cnt;
115     }
116
117     /* if some processes in this process's subtree in this step
118        did not have any destination process to communicate with
119        because of non-power-of-two, we need to send them the
120        data that they would normally have received from those
121        processes. That is, the haves in this subtree must send to
122        the havenots. We use a logarithmic
123        recursive-halfing algorithm for this. */
124
125     /* This part of the code will not currently be
126        executed because we are not using recursive
127        doubling for non power of two. Mark it as experimental
128        so that it doesn't show up as red in the coverage
129        tests. */
130
131     /* --BEGIN EXPERIMENTAL-- */
132     if (dst_tree_root + mask > comm_size) {
133       nprocs_completed = comm_size - my_tree_root - mask;
134       /* nprocs_completed is the number of processes in this
135          subtree that have all the data. Send data to others
136          in a tree fashion. First find root of current tree
137          that is being divided into two. k is the number of
138          least-significant bits in this process's rank that
139          must be zeroed out to find the rank of the root */
140       j = mask;
141       k = 0;
142       while (j) {
143         j >>= 1;
144         k++;
145       }
146       k--;
147
148       tmp_mask = mask >> 1;
149
150       while (tmp_mask) {
151         dst = rank ^ tmp_mask;
152
153         tree_root = rank >> k;
154         tree_root <<= k;
155
156         /* send only if this proc has data and destination
157            doesn't have data. at any step, multiple processes
158            can send if they have the data */
159         if ((dst > rank) &&
160             (rank < tree_root + nprocs_completed)
161             && (dst >= tree_root + nprocs_completed)) {
162
163           offset = 0;
164           for (j=0; j<(my_tree_root+mask); j++)
165             offset += recvcounts[j];
166           offset *= recvtype_extent;
167
168           Request::send(((char *)tmp_buf + offset),
169                         last_recv_cnt,
170                         recvtype, dst,
171                         COLL_TAG_ALLGATHERV, comm);
172           /* last_recv_cnt was set in the previous
173              receive. that's the amount of data to be
174              sent now. */
175         }
176         /* recv only if this proc. doesn't have data and sender
177            has data */
178         else if ((dst < rank) &&
179                  (dst < tree_root + nprocs_completed) &&
180                  (rank >= tree_root + nprocs_completed)) {
181
182           offset = 0;
183           for (j=0; j<(my_tree_root+mask); j++)
184             offset += recvcounts[j];
185
186           Request::recv(((char *)tmp_buf + offset * recvtype_extent),
187                         total_count - offset, recvtype,
188                         dst, COLL_TAG_ALLGATHERV,
189                         comm, &status);
190           /* for convenience, recv is posted for a
191              bigger amount than will be sent */
192           last_recv_cnt=Status::get_count(&status, recvtype);
193           curr_cnt += last_recv_cnt;
194         }
195         tmp_mask >>= 1;
196         k--;
197       }
198     }
199     /* --END EXPERIMENTAL-- */
200
201     mask <<= 1;
202     i++;
203   }
204
205   /* copy data from tmp_buf to recvbuf */
206   position = 0;
207   for (j=0; j<comm_size; j++) {
208     if ((sendbuf != MPI_IN_PLACE) || (j != rank)) {
209       /* not necessary to copy if in_place and
210          j==rank. otherwise copy. */
211       Datatype::copy(((char *)tmp_buf + position*recvtype_extent),
212                          recvcounts[j], recvtype,
213                          ((char *)recvbuf + displs[j]*recvtype_extent),
214                          recvcounts[j], recvtype);
215     }
216     position += recvcounts[j];
217   }
218
219   smpi_free_tmp_buffer(tmp_buf_rl);
220   return MPI_SUCCESS;
221 }
222
223 }
224 }