Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Update copyright headers.
[simgrid.git] / src / smpi / colls / barrier / barrier-ompi.cpp
1 /* Copyright (c) 2013-2018. 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  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
9  *                         University Research and Technology
10  *                         Corporation.  All rights reserved.
11  * Copyright (c) 2004-2006 The University of Tennessee and The University
12  *                         of Tennessee Research Foundation.  All rights
13  *                         reserved.
14  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
15  *                         University of Stuttgart.  All rights reserved.
16  * Copyright (c) 2004-2005 The Regents of the University of California.
17  *                         All rights reserved.
18  * Copyright (c) 2008      Sun Microsystems, Inc.  All rights reserved.
19  *
20  * Additional copyrights may follow
21  */
22
23 #include "../coll_tuned_topo.hpp"
24 #include "../colls_private.hpp"
25
26 /*
27  * Barrier is ment to be a synchronous operation, as some BTLs can mark
28  * a request done before its passed to the NIC and progress might not be made
29  * elsewhere we cannot allow a process to exit the barrier until its last
30  * [round of] sends are completed.
31  *
32  * It is last round of sends rather than 'last' individual send as each pair of
33  * peers can use different channels/devices/btls and the receiver of one of
34  * these sends might be forced to wait as the sender
35  * leaves the collective and does not make progress until the next mpi call
36  *
37  */
38
39 /*
40  * Simple double ring version of barrier
41  *
42  * synchronous gurantee made by last ring of sends are synchronous
43  *
44  */
45 namespace simgrid{
46 namespace smpi{
47 int Coll_barrier_ompi_doublering::barrier(MPI_Comm comm)
48 {
49     int rank, size;
50     int left, right;
51
52
53     rank = comm->rank();
54     size = comm->size();
55
56     XBT_DEBUG("ompi_coll_tuned_barrier_ompi_doublering rank %d", rank);
57
58     left = ((rank-1+size)%size);
59     right = ((rank+1)%size);
60
61     if (rank > 0) { /* receive message from the left */
62         Request::recv((void*)NULL, 0, MPI_BYTE, left,
63                                 COLL_TAG_BARRIER, comm,
64                                 MPI_STATUS_IGNORE);
65     }
66
67     /* Send message to the right */
68     Request::send((void*)NULL, 0, MPI_BYTE, right,
69                             COLL_TAG_BARRIER,
70                              comm);
71
72     /* root needs to receive from the last node */
73     if (rank == 0) {
74         Request::recv((void*)NULL, 0, MPI_BYTE, left,
75                                 COLL_TAG_BARRIER, comm,
76                                 MPI_STATUS_IGNORE);
77     }
78
79     /* Allow nodes to exit */
80     if (rank > 0) { /* post Receive from left */
81         Request::recv((void*)NULL, 0, MPI_BYTE, left,
82                                 COLL_TAG_BARRIER, comm,
83                                 MPI_STATUS_IGNORE);
84     }
85
86     /* send message to the right one */
87     Request::send((void*)NULL, 0, MPI_BYTE, right,
88                             COLL_TAG_BARRIER,
89                              comm);
90
91     /* rank 0 post receive from the last node */
92     if (rank == 0) {
93         Request::recv((void*)NULL, 0, MPI_BYTE, left,
94                                 COLL_TAG_BARRIER, comm,
95                                 MPI_STATUS_IGNORE);
96     }
97
98     return MPI_SUCCESS;
99
100 }
101
102
103 /*
104  * To make synchronous, uses sync sends and sync sendrecvs
105  */
106
107 int Coll_barrier_ompi_recursivedoubling::barrier(MPI_Comm comm)
108 {
109     int rank, size, adjsize;
110     int mask, remote;
111
112     rank = comm->rank();
113     size = comm->size();
114     XBT_DEBUG(
115                  "ompi_coll_tuned_barrier_ompi_recursivedoubling rank %d",
116                  rank);
117
118     /* do nearest power of 2 less than size calc */
119     for( adjsize = 1; adjsize <= size; adjsize <<= 1 );
120     adjsize >>= 1;
121
122     /* if size is not exact power of two, perform an extra step */
123     if (adjsize != size) {
124         if (rank >= adjsize) {
125             /* send message to lower ranked node */
126             remote = rank - adjsize;
127             Request::sendrecv(NULL, 0, MPI_BYTE, remote,
128                                                   COLL_TAG_BARRIER,
129                                                   NULL, 0, MPI_BYTE, remote,
130                                                   COLL_TAG_BARRIER,
131                                                   comm, MPI_STATUS_IGNORE);
132
133         } else if (rank < (size - adjsize)) {
134
135             /* receive message from high level rank */
136             Request::recv((void*)NULL, 0, MPI_BYTE, rank+adjsize,
137                                     COLL_TAG_BARRIER, comm,
138                                     MPI_STATUS_IGNORE);
139
140         }
141     }
142
143     /* exchange messages */
144     if ( rank < adjsize ) {
145         mask = 0x1;
146         while ( mask < adjsize ) {
147             remote = rank ^ mask;
148             mask <<= 1;
149             if (remote >= adjsize) continue;
150
151             /* post receive from the remote node */
152             Request::sendrecv(NULL, 0, MPI_BYTE, remote,
153                                                   COLL_TAG_BARRIER,
154                                                   NULL, 0, MPI_BYTE, remote,
155                                                   COLL_TAG_BARRIER,
156                                                   comm, MPI_STATUS_IGNORE);
157         }
158     }
159
160     /* non-power of 2 case */
161     if (adjsize != size) {
162         if (rank < (size - adjsize)) {
163             /* send enter message to higher ranked node */
164             remote = rank + adjsize;
165             Request::send((void*)NULL, 0, MPI_BYTE, remote,
166                                     COLL_TAG_BARRIER,
167                                      comm);
168
169         }
170     }
171
172     return MPI_SUCCESS;
173
174 }
175
176
177 /*
178  * To make synchronous, uses sync sends and sync sendrecvs
179  */
180
181 int Coll_barrier_ompi_bruck::barrier(MPI_Comm comm)
182 {
183     int rank, size;
184     int distance, to, from;
185
186     rank = comm->rank();
187     size = comm->size();
188     XBT_DEBUG(
189                  "ompi_coll_tuned_barrier_ompi_bruck rank %d", rank);
190
191     /* exchange data with rank-2^k and rank+2^k */
192     for (distance = 1; distance < size; distance <<= 1) {
193         from = (rank + size - distance) % size;
194         to   = (rank + distance) % size;
195
196         /* send message to lower ranked node */
197         Request::sendrecv(NULL, 0, MPI_BYTE, to,
198                                               COLL_TAG_BARRIER,
199                                               NULL, 0, MPI_BYTE, from,
200                                               COLL_TAG_BARRIER,
201                                               comm, MPI_STATUS_IGNORE);
202     }
203
204     return MPI_SUCCESS;
205
206 }
207
208
209 /*
210  * To make synchronous, uses sync sends and sync sendrecvs
211  */
212 /* special case for two processes */
213 int Coll_barrier_ompi_two_procs::barrier(MPI_Comm comm)
214 {
215     int remote;
216
217     remote = comm->rank();
218     XBT_DEBUG(
219                  "ompi_coll_tuned_barrier_ompi_two_procs rank %d", remote);
220     remote = (remote + 1) & 0x1;
221
222     Request::sendrecv(NULL, 0, MPI_BYTE, remote,
223                                           COLL_TAG_BARRIER,
224                                           NULL, 0, MPI_BYTE, remote,
225                                           COLL_TAG_BARRIER,
226                                           comm, MPI_STATUS_IGNORE);
227     return (MPI_SUCCESS);
228 }
229
230
231 /*
232  * Linear functions are copied from the BASIC coll module
233  * they do not segment the message and are simple implementations
234  * but for some small number of nodes and/or small data sizes they
235  * are just as fast as tuned/tree based segmenting operations
236  * and as such may be selected by the decision functions
237  * These are copied into this module due to the way we select modules
238  * in V1. i.e. in V2 we will handle this differently and so will not
239  * have to duplicate code.
240  * GEF Oct05 after asking Jeff.
241  */
242
243 /* copied function (with appropriate renaming) starts here */
244
245 int Coll_barrier_ompi_basic_linear::barrier(MPI_Comm comm)
246 {
247     int i;
248     int size = comm->size();
249     int rank = comm->rank();
250
251     /* All non-root send & receive zero-length message. */
252
253     if (rank > 0) {
254         Request::send (NULL, 0, MPI_BYTE, 0,
255                                  COLL_TAG_BARRIER,
256                                   comm);
257
258         Request::recv (NULL, 0, MPI_BYTE, 0,
259                                  COLL_TAG_BARRIER,
260                                  comm, MPI_STATUS_IGNORE);
261     }
262
263     /* The root collects and broadcasts the messages. */
264
265     else {
266         MPI_Request* requests;
267
268         requests = new MPI_Request[size];
269         for (i = 1; i < size; ++i) {
270             requests[i] = Request::irecv(NULL, 0, MPI_BYTE, MPI_ANY_SOURCE,
271                                      COLL_TAG_BARRIER, comm
272                                      );
273         }
274         Request::waitall( size-1, requests+1, MPI_STATUSES_IGNORE );
275
276         for (i = 1; i < size; ++i) {
277             requests[i] = Request::isend(NULL, 0, MPI_BYTE, i,
278                                      COLL_TAG_BARRIER,
279                                       comm
280                                      );
281         }
282         Request::waitall( size-1, requests+1, MPI_STATUSES_IGNORE );
283         delete[] requests;
284     }
285
286     /* All done */
287
288     return MPI_SUCCESS;
289
290 }
291 /* copied function (with appropriate renaming) ends here */
292
293 /*
294  * Another recursive doubling type algorithm, but in this case
295  * we go up the tree and back down the tree.
296  */
297 int Coll_barrier_ompi_tree::barrier(MPI_Comm comm)
298 {
299     int rank, size, depth;
300     int jump, partner;
301
302     rank = comm->rank();
303     size = comm->size();
304     XBT_DEBUG(
305                  "ompi_coll_tuned_barrier_ompi_tree %d",
306                  rank);
307
308     /* Find the nearest power of 2 of the communicator size. */
309     for(depth = 1; depth < size; depth <<= 1 );
310
311     for (jump=1; jump<depth; jump<<=1) {
312         partner = rank ^ jump;
313         if (!(partner & (jump-1)) && partner < size) {
314             if (partner > rank) {
315                 Request::recv (NULL, 0, MPI_BYTE, partner,
316                                          COLL_TAG_BARRIER, comm,
317                                          MPI_STATUS_IGNORE);
318             } else if (partner < rank) {
319                 Request::send (NULL, 0, MPI_BYTE, partner,
320                                          COLL_TAG_BARRIER,
321                                           comm);
322             }
323         }
324     }
325
326     depth>>=1;
327     for (jump = depth; jump>0; jump>>=1) {
328         partner = rank ^ jump;
329         if (!(partner & (jump-1)) && partner < size) {
330             if (partner > rank) {
331                 Request::send (NULL, 0, MPI_BYTE, partner,
332                                          COLL_TAG_BARRIER,
333                                           comm);
334             } else if (partner < rank) {
335                 Request::recv (NULL, 0, MPI_BYTE, partner,
336                                          COLL_TAG_BARRIER, comm,
337                                          MPI_STATUS_IGNORE);
338             }
339         }
340     }
341
342     return MPI_SUCCESS;
343 }
344
345 }
346 }