Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
18f1d0882508f2f9d04e7269b2bf615c060a47d7
[simgrid.git] / src / smpi / colls / gather-ompi.c
1 /*
2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
3  *                         University Research and Technology
4  *                         Corporation.  All rights reserved.
5  * Copyright (c) 2004-2009 The University of Tennessee and The University
6  *                         of Tennessee Research Foundation.  All rights
7  *                         reserved.
8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9  *                         University of Stuttgart.  All rights reserved.
10  * Copyright (c) 2004-2005 The Regents of the University of California.
11  *                         All rights reserved.
12  * $COPYRIGHT$
13  *
14  * Additional copyrights may follow
15  *
16  * $HEADER$
17  */
18
19 #include "colls_private.h"
20 #include "coll_tuned_topo.h"
21
22 /* Todo: gather_intra_generic, gather_intra_binary, gather_intra_chain,
23  * gather_intra_pipeline, segmentation? */
24 int
25 smpi_coll_tuned_gather_ompi_binomial(void *sbuf, int scount,
26                                       MPI_Datatype sdtype,
27                                       void *rbuf, int rcount,
28                                       MPI_Datatype rdtype,
29                                       int root,
30                                       MPI_Comm comm)
31 {
32     int line = -1;
33     int i;
34     int rank;
35     int vrank;
36     int size;
37     int total_recv = 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
47     size = smpi_comm_size(comm);
48     rank = smpi_comm_rank(comm);
49
50     XBT_DEBUG(
51                  "smpi_coll_tuned_gather_ompi_binomial rank %d", rank);
52
53     /* create the binomial tree */
54    // COLL_TUNED_UPDATE_IN_ORDER_BMTREE( comm, tuned_module, root );
55     bmtree = ompi_coll_tuned_topo_build_in_order_bmtree(comm, root);
56     // data->cached_in_order_bmtree;
57
58     smpi_datatype_extent(sdtype, &slb, &sextent);
59     smpi_datatype_extent(sdtype, &strue_lb, &strue_extent);
60
61     vrank = (rank - root + size) % size;
62
63     if (rank == root) {
64         smpi_datatype_extent(rdtype, &rlb, &rextent);
65         smpi_datatype_extent(rdtype, &rtrue_lb, &rtrue_extent);
66         if (0 == root){
67             /* root on 0, just use the recv buffer */
68             ptmp = (char *) rbuf;
69             if (sbuf != MPI_IN_PLACE) {
70                 err = smpi_datatype_copy(sbuf, scount, sdtype,
71                                       ptmp, rcount, rdtype);
72                 if (MPI_SUCCESS != err) { line = __LINE__; goto err_hndl; }
73             }
74         } else {
75             /* root is not on 0, allocate temp buffer for recv,
76              * rotate data at the end */
77             tempbuf = (char *) malloc(rtrue_extent + (rcount*size - 1) * rextent);
78             if (NULL == tempbuf) {
79                 err= MPI_ERR_OTHER; line = __LINE__; goto err_hndl;
80             }
81
82             ptmp = tempbuf - rlb;
83             if (sbuf != MPI_IN_PLACE) {
84                 /* copy from sbuf to temp buffer */
85                 err = smpi_datatype_copy(sbuf, scount, sdtype,
86                                       ptmp, rcount, rdtype);
87                 if (MPI_SUCCESS != err) { line = __LINE__; goto err_hndl; }
88             } else {
89                 /* copy from rbuf to temp buffer  */
90                 err = smpi_datatype_copy((char *) rbuf + rank*rextent*rcount, rcount, rdtype, ptmp, rcount, rdtype );
91                 if (MPI_SUCCESS != err) { line = __LINE__; goto err_hndl; }
92             }
93         }
94         total_recv = rcount;
95     } else if (!(vrank % 2)) {
96         /* other non-leaf nodes, allocate temp buffer for data received from
97          * children, the most we need is half of the total data elements due
98          * to the property of binimoal tree */
99         tempbuf = (char *) malloc(strue_extent + (scount*size - 1) * sextent);
100         if (NULL == tempbuf) {
101             err= MPI_ERR_OTHER; line = __LINE__; goto err_hndl;
102         }
103
104         ptmp = tempbuf - slb;
105         /* local copy to tempbuf */
106         err = smpi_datatype_copy(sbuf, scount, sdtype,
107                                    ptmp, scount, sdtype);
108         if (MPI_SUCCESS != err) { line = __LINE__; goto err_hndl; }
109
110         /* use sdtype,scount as rdtype,rdcount since they are ignored on
111          * non-root procs */
112         rdtype = sdtype;
113         rcount = scount;
114         rextent = sextent;
115         total_recv = rcount;
116     } else {
117         /* leaf nodes, no temp buffer needed, use sdtype,scount as
118          * rdtype,rdcount since they are ignored on non-root procs */
119         ptmp = (char *) sbuf;
120         total_recv = scount;
121     }
122
123     if (!(vrank % 2)) {
124         /* all non-leaf nodes recv from children */
125         for (i = 0; i < bmtree->tree_nextsize; i++) {
126             int mycount = 0, vkid;
127             /* figure out how much data I have to send to this child */
128             vkid = (bmtree->tree_next[i] - root + size) % size;
129             mycount = vkid - vrank;
130             if (mycount > (size - vkid))
131                 mycount = size - vkid;
132             mycount *= rcount;
133
134             XBT_DEBUG(
135                          "smpi_coll_tuned_gather_ompi_binomial rank %d recv %d mycount = %d",
136                          rank, bmtree->tree_next[i], mycount);
137
138             smpi_mpi_recv(ptmp + total_recv*rextent, rcount*size-total_recv, rdtype,
139                                     bmtree->tree_next[i], COLL_TAG_GATHER,
140                                     comm, &status);
141
142             total_recv += mycount;
143         }
144     }
145
146     if (rank != root) {
147         /* all nodes except root send to parents */
148         XBT_DEBUG(
149                      "smpi_coll_tuned_gather_ompi_binomial rank %d send %d count %d\n",
150                      rank, bmtree->tree_prev, total_recv);
151
152         smpi_mpi_send(ptmp, total_recv, sdtype,
153                                 bmtree->tree_prev,
154                                 COLL_TAG_GATHER,
155                                  comm);
156   }
157     if (rank == root) {
158         if (root != 0) {
159             /* rotate received data on root if root != 0 */
160             err = smpi_datatype_copy(ptmp, rcount*(size - root), rdtype,
161                                                  (char *) rbuf + rextent*root*rcount, rcount*(size - root), rdtype );
162             if (MPI_SUCCESS != err) { line = __LINE__; goto err_hndl; }
163
164
165             err = smpi_datatype_copy( ptmp + rextent*rcount*(size-root), rcount*root,rdtype, 
166                                                  (char *) rbuf,rcount*root,rdtype);
167             if (MPI_SUCCESS != err) { line = __LINE__; goto err_hndl; }
168
169             free(tempbuf);
170         }
171     } else if (!(vrank % 2)) {
172         /* other non-leaf nodes */
173         free(tempbuf);
174     }
175     return MPI_SUCCESS;
176
177  err_hndl:
178     if (NULL != tempbuf)
179         free(tempbuf);
180
181     XBT_DEBUG(  "%s:%4d\tError occurred %d, rank %2d",
182                  __FILE__, line, err, rank);
183     return err;
184 }
185
186 /*
187  *      gather_intra_linear_sync
188  *
189  *      Function:       - synchronized gather operation with
190  *      Accepts:        - same arguments as MPI_Gather(), first segment size
191  *      Returns:        - MPI_SUCCESS or error code
192  */
193 int
194 smpi_coll_tuned_gather_ompi_linear_sync(void *sbuf, int scount,
195                                          MPI_Datatype sdtype,
196                                          void *rbuf, int rcount,
197                                          MPI_Datatype rdtype,
198                                          int root, 
199                                          MPI_Comm comm)
200 {
201     int i;
202     int ret, line;
203     int rank, size;
204     int first_segment_count;
205     size_t typelng;
206     MPI_Aint extent;
207     MPI_Aint lb;
208
209     int first_segment_size=0;
210     size = smpi_comm_size(comm);
211     rank = smpi_comm_rank(comm);
212     
213     size_t dsize, block_size;
214     if (rank == root) {
215         dsize= smpi_datatype_size(rdtype);
216         block_size = dsize * rcount;
217     } else {
218         dsize=smpi_datatype_size(sdtype);
219         block_size = dsize * scount;
220     }
221     
222      if (block_size > 92160){
223      first_segment_size = 32768;
224      }else{
225      first_segment_size = 1024;
226      }
227
228     XBT_DEBUG(
229                  "smpi_coll_tuned_gather_ompi_linear_sync rank %d, segment %d", rank, first_segment_size);
230
231     if (rank != root) {
232         /* Non-root processes:
233            - receive zero byte message from the root,
234            - send the first segment of the data synchronously,
235            - send the second segment of the data.
236         */
237
238         typelng= smpi_datatype_size(sdtype);
239         smpi_datatype_extent(sdtype, &lb, &extent);
240         first_segment_count = scount;
241         COLL_TUNED_COMPUTED_SEGCOUNT( (size_t) first_segment_size, typelng, 
242                                       first_segment_count );
243
244         smpi_mpi_recv(sbuf, 0, MPI_BYTE, root, 
245                                 COLL_TAG_GATHER,
246                                 comm, MPI_STATUS_IGNORE);
247
248         smpi_mpi_send(sbuf, first_segment_count, sdtype, root,
249                                 COLL_TAG_GATHER,
250                                  comm);
251
252         smpi_mpi_send((char*)sbuf + extent * first_segment_count, 
253                                 (scount - first_segment_count), sdtype, 
254                                 root, COLL_TAG_GATHER,
255                                  comm);
256     }
257
258     else {
259         /* Root process, 
260            - For every non-root node:
261            - post irecv for the first segment of the message
262            - send zero byte message to signal node to send the message
263            - post irecv for the second segment of the message
264            - wait for the first segment to complete
265            - Copy local data if necessary
266            - Waitall for all the second segments to complete.
267         */
268         char *ptmp;
269         MPI_Request *reqs = NULL, first_segment_req;
270         reqs = (MPI_Request *) calloc(size, sizeof(MPI_Request ));
271         if (NULL == reqs) { ret = -1; line = __LINE__; goto error_hndl; }
272         
273         typelng=smpi_datatype_size(rdtype);
274         smpi_datatype_extent(rdtype, &lb, &extent);
275         first_segment_count = rcount;
276         COLL_TUNED_COMPUTED_SEGCOUNT( (size_t)first_segment_size, typelng, 
277                                       first_segment_count );
278
279         ptmp = (char *) rbuf;
280         for (i = 0; i < size; ++i) {
281             if (i == rank) {  
282                 /* skip myself */
283                 reqs[i] = MPI_REQUEST_NULL; 
284                 continue; 
285             } 
286
287             /* irecv for the first segment from i */
288             ptmp = (char*)rbuf + i * rcount * extent;
289             first_segment_req = smpi_mpi_irecv(ptmp, first_segment_count, rdtype, i,
290                                      COLL_TAG_GATHER, comm
291                                      );
292             
293             /* send sync message */
294             smpi_mpi_send(rbuf, 0, MPI_BYTE, i,
295                                     COLL_TAG_GATHER,
296                                      comm);
297
298             /* irecv for the second segment */
299             ptmp = (char*)rbuf + (i * rcount + first_segment_count) * extent;
300             reqs[i]=smpi_mpi_irecv(ptmp, (rcount - first_segment_count), 
301                                      rdtype, i, COLL_TAG_GATHER, comm
302                                      );
303
304             /* wait on the first segment to complete */
305             smpi_mpi_wait(&first_segment_req, MPI_STATUS_IGNORE);
306         }
307
308         /* copy local data if necessary */
309         if (MPI_IN_PLACE != sbuf) {
310             ret = smpi_datatype_copy(sbuf, scount, sdtype,
311                                   (char*)rbuf + rank * rcount * extent, 
312                                   rcount, rdtype);
313             if (ret != MPI_SUCCESS) { line = __LINE__; goto error_hndl; }
314         }
315         
316         /* wait all second segments to complete */
317         ret = smpi_mpi_waitall(size, reqs, MPI_STATUSES_IGNORE);
318
319         free(reqs);
320     }
321
322     /* All done */
323
324     return MPI_SUCCESS;
325  error_hndl:
326     XBT_DEBUG( 
327                    "ERROR_HNDL: node %d file %s line %d error %d\n", 
328                    rank, __FILE__, line, ret );
329     return ret;
330 }
331
332 /*
333  * Linear functions are copied from the BASIC coll module
334  * they do not segment the message and are simple implementations
335  * but for some small number of nodes and/or small data sizes they 
336  * are just as fast as tuned/tree based segmenting operations 
337  * and as such may be selected by the decision functions
338  * These are copied into this module due to the way we select modules
339  * in V1. i.e. in V2 we will handle this differently and so will not
340  * have to duplicate code.
341  * JPG following the examples from other coll_tuned implementations. Dec06.
342  */
343
344 /* copied function (with appropriate renaming) starts here */
345 /*
346  *      gather_intra
347  *
348  *      Function:       - basic gather operation
349  *      Accepts:        - same arguments as MPI_Gather()
350  *      Returns:        - MPI_SUCCESS or error code
351  */
352 int
353 smpi_coll_tuned_gather_ompi_basic_linear(void *sbuf, int scount,
354                                           MPI_Datatype sdtype,
355                                           void *rbuf, int rcount,
356                                           MPI_Datatype rdtype,
357                                           int root,
358                                           MPI_Comm comm)
359 {
360     int i;
361     int err;
362     int rank;
363     int size;
364     char *ptmp;
365     MPI_Aint incr;
366     MPI_Aint extent;
367     MPI_Aint lb;
368
369     size = smpi_comm_size(comm);
370     rank = smpi_comm_rank(comm);
371
372     /* Everyone but root sends data and returns. */
373     XBT_DEBUG(
374                  "ompi_coll_tuned_gather_intra_basic_linear rank %d", rank);
375
376     if (rank != root) {
377         smpi_mpi_send(sbuf, scount, sdtype, root,
378                                  COLL_TAG_GATHER,
379                                   comm);
380         return MPI_SUCCESS;
381     }
382
383     /* I am the root, loop receiving the data. */
384
385     smpi_datatype_extent(rdtype, &lb, &extent);
386     incr = extent * rcount;
387     for (i = 0, ptmp = (char *) rbuf; i < size; ++i, ptmp += incr) {
388         if (i == rank) {
389             if (MPI_IN_PLACE != sbuf) {
390                 err = smpi_datatype_copy(sbuf, scount, sdtype,
391                                       ptmp, rcount, rdtype);
392             } else {
393                 err = MPI_SUCCESS;
394             }
395         } else {
396             smpi_mpi_recv(ptmp, rcount, rdtype, i,
397                                     COLL_TAG_GATHER,
398                                     comm, MPI_STATUS_IGNORE);
399             err = MPI_SUCCESS;
400         }
401         if (MPI_SUCCESS != err) {
402             return err;
403         }
404     }
405
406     /* All done */
407
408     return MPI_SUCCESS;
409 }