Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Sort include lists according to clang-format.
[simgrid.git] / src / smpi / colls / scatter / scatter-ompi.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  * 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  *
19  * Additional copyrights may follow
20  */
21
22 #include "../coll_tuned_topo.hpp"
23 #include "../colls_private.hpp"
24
25 namespace simgrid{
26 namespace smpi{
27
28 int Coll_scatter_ompi_binomial::scatter(void* sbuf, int scount, MPI_Datatype sdtype, void* rbuf, int rcount,
29                                         MPI_Datatype rdtype, int root, MPI_Comm comm)
30 {
31     int line = -1;
32     int i;
33     int rank;
34     int vrank;
35     int size;
36     int total_send = 0;
37     char *ptmp     = NULL;
38     char *tempbuf  = NULL;
39     int err;
40     ompi_coll_tree_t* bmtree;
41     MPI_Status status;
42     MPI_Aint sextent, slb, strue_lb, strue_extent;
43     MPI_Aint rextent, rlb, rtrue_lb, rtrue_extent;
44
45     size = comm->size();
46     rank = comm->rank();
47
48     XBT_DEBUG(
49                  "Coll_scatter_ompi_binomial::scatter rank %d", rank);
50
51     /* create the binomial tree */
52
53 //    COLL_TUNED_UPDATE_IN_ORDER_BMTREE( comm, tuned_module, root );
54     bmtree =  ompi_coll_tuned_topo_build_in_order_bmtree( comm, root);//ompi_ data->cached_in_order_bmtree;
55
56     sdtype->extent(&slb, &sextent);
57     sdtype->extent(&strue_lb, &strue_extent);
58     rdtype->extent(&rlb, &rextent);
59     rdtype->extent(&rtrue_lb, &rtrue_extent);
60
61     vrank = (rank - root + size) % size;
62
63     if (rank == root) {
64       if (0 == root) {
65         /* root on 0, just use the send buffer */
66         ptmp = (char*)sbuf;
67         if (rbuf != MPI_IN_PLACE) {
68           /* local copy to rbuf */
69           err = Datatype::copy(sbuf, scount, sdtype, rbuf, rcount, rdtype);
70           if (MPI_SUCCESS != err) {
71             line = __LINE__;
72             goto err_hndl;
73           }
74         }
75       } else {
76         /* root is not on 0, allocate temp buffer for send */
77         tempbuf = (char*)smpi_get_tmp_sendbuffer(strue_extent + (scount * size - 1) * sextent);
78         if (NULL == tempbuf) {
79           err  = MPI_ERR_OTHER;
80           line = __LINE__;
81           goto err_hndl;
82         }
83
84         ptmp = tempbuf - slb;
85
86         /* and rotate data so they will eventually in the right place */
87         err = Datatype::copy((char*)sbuf + sextent * root * scount, scount * (size - root), sdtype, ptmp,
88                              scount * (size - root), sdtype);
89         if (MPI_SUCCESS != err) {
90           line = __LINE__;
91           goto err_hndl;
92         }
93
94         err = Datatype::copy((char*)sbuf, scount * root, sdtype, ptmp + sextent * scount * (size - root), scount * root,
95                              sdtype);
96         if (MPI_SUCCESS != err) {
97           line = __LINE__;
98           goto err_hndl;
99         }
100
101         if (rbuf != MPI_IN_PLACE) {
102           /* local copy to rbuf */
103           err = Datatype::copy(ptmp, scount, sdtype, rbuf, rcount, rdtype);
104           if (MPI_SUCCESS != err) {
105             line = __LINE__;
106             goto err_hndl;
107           }
108         }
109       }
110       total_send = scount;
111     } else if (not(vrank % 2)) {
112       /* non-root, non-leaf nodes, allocate temp buffer for recv
113        * the most we need is rcount*size/2 */
114       tempbuf = (char*)smpi_get_tmp_recvbuffer(rtrue_extent + (rcount * size - 1) * rextent);
115       if (NULL == tempbuf) {
116         err  = MPI_ERR_OTHER;
117         line = __LINE__;
118         goto err_hndl;
119       }
120
121       ptmp = tempbuf - rlb;
122
123       sdtype     = rdtype;
124       scount     = rcount;
125       sextent    = rextent;
126       total_send = scount;
127     } else {
128       /* leaf nodes, just use rbuf */
129       ptmp = (char*)rbuf;
130     }
131
132     if (not(vrank % 2)) {
133       if (rank != root) {
134         /* recv from parent on non-root */
135         Request::recv(ptmp, rcount * size, rdtype, bmtree->tree_prev, COLL_TAG_SCATTER, comm, &status);
136         /* local copy to rbuf */
137         Datatype::copy(ptmp, scount, sdtype, rbuf, rcount, rdtype);
138       }
139       /* send to children on all non-leaf */
140       for (i = 0; i < bmtree->tree_nextsize; i++) {
141         int mycount = 0, vkid;
142         /* figure out how much data I have to send to this child */
143         vkid    = (bmtree->tree_next[i] - root + size) % size;
144         mycount = vkid - vrank;
145         if (mycount > (size - vkid))
146           mycount = size - vkid;
147         mycount *= scount;
148
149         Request::send(ptmp + total_send * sextent, mycount, sdtype, bmtree->tree_next[i], COLL_TAG_SCATTER, comm);
150
151         total_send += mycount;
152       }
153
154     } else {
155       /* recv from parent on leaf nodes */
156       Request::recv(ptmp, rcount, rdtype, bmtree->tree_prev, COLL_TAG_SCATTER, comm, &status);
157     }
158
159     if (NULL != tempbuf)
160       smpi_free_tmp_buffer(tempbuf);
161     // not FIXME : store the tree, as done in ompi, instead of calculating it each time ?
162     xbt_free(bmtree);
163
164     return MPI_SUCCESS;
165
166  err_hndl:
167     if (NULL != tempbuf)
168       free(tempbuf);
169
170     XBT_DEBUG("%s:%4d\tError occurred %d, rank %2d", __FILE__, line, err, rank);
171     return err;
172 }
173
174 /*
175  * Linear functions are copied from the BASIC coll module
176  * they do not segment the message and are simple implementations
177  * but for some small number of nodes and/or small data sizes they
178  * are just as fast as tuned/tree based segmenting operations
179  * and as such may be selected by the decision functions
180  * These are copied into this module due to the way we select modules
181  * in V1. i.e. in V2 we will handle this differently and so will not
182  * have to duplicate code.
183  * JPG following the examples from other coll_tuned implementations. Dec06.
184  */
185
186 /* copied function (with appropriate renaming) starts here */
187 /*
188  *  scatter_intra
189  *
190  *  Function:  - basic scatter operation
191  *  Accepts:  - same arguments as MPI_Scatter()
192  *  Returns:  - MPI_SUCCESS or error code
193  */
194 int Coll_scatter_ompi_basic_linear::scatter(void* sbuf, int scount, MPI_Datatype sdtype, void* rbuf, int rcount,
195                                             MPI_Datatype rdtype, int root, MPI_Comm comm)
196 {
197     int i, rank, size, err;
198     char *ptmp;
199     ptrdiff_t lb, incr;
200
201     /* Initialize */
202
203     rank = comm->rank();
204     size = comm->size();
205
206     /* If not root, receive data. */
207
208     if (rank != root) {
209         Request::recv(rbuf, rcount, rdtype, root,
210                                 COLL_TAG_SCATTER,
211                                 comm, MPI_STATUS_IGNORE);
212         return MPI_SUCCESS;
213     }
214
215     /* I am the root, loop sending data. */
216
217     err = sdtype->extent(&lb, &incr);
218     if (MPI_SUCCESS != err) {
219         return MPI_ERR_OTHER;
220     }
221
222     incr *= scount;
223     for (i = 0, ptmp = (char *) sbuf; i < size; ++i, ptmp += incr) {
224
225         /* simple optimization */
226
227         if (i == rank) {
228             if (MPI_IN_PLACE != rbuf) {
229                 err =
230                     Datatype::copy(ptmp, scount, sdtype, rbuf, rcount,
231                                     rdtype);
232             }
233         } else {
234             Request::send(ptmp, scount, sdtype, i,
235                                     COLL_TAG_SCATTER,
236                                      comm);
237         }
238         if (MPI_SUCCESS != err) {
239             return err;
240         }
241     }
242
243     /* All done */
244
245     return MPI_SUCCESS;
246 }
247
248 }
249 }