Logo AND Algorithmique Numérique Distribuée

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