Logo AND Algorithmique Numérique Distribuée

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