Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Update copyright lines with new year.
[simgrid.git] / src / smpi / colls / reduce / reduce-mvapich-knomial.cpp
1 /* Copyright (c) 2013-2020. 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-2012 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  * Copyright (c) 2009      University of Houston. All rights reserved.
20  *
21  * Additional copyrights may follow
22  */
23
24 /*
25  *
26  *  (C) 2001 by Argonne National Laboratory.
27  *      See COPYRIGHT in top-level directory.
28  */
29 /* Copyright (c) 2001-2014, The Ohio State University. All rights
30  * reserved.
31  *
32  * This file is part of the MVAPICH2 software package developed by the
33  * team members of The Ohio State University's Network-Based Computing
34  * Laboratory (NBCL), headed by Professor Dhabaleswar K. (DK) Panda.
35  *
36  * For detailed copyright and licensing information, please refer to the
37  * copyright file COPYRIGHT in the top level MVAPICH2 directory.
38  *
39  */
40
41 #include "../colls_private.hpp"
42 #include <algorithm>
43
44 extern int mv2_reduce_intra_knomial_factor;
45 extern int mv2_reduce_inter_knomial_factor;
46
47 #define SMPI_DEFAULT_KNOMIAL_FACTOR 4
48
49 //        int mv2_reduce_knomial_factor = 2;
50
51
52
53 static int MPIR_Reduce_knomial_trace(int root, int reduce_knomial_factor,
54         MPI_Comm comm, int *dst, int *expected_send_count,
55         int *expected_recv_count, int **src_array)
56 {
57     int mask=0x1, k, comm_size, src, rank, relative_rank, lroot=0;
58     int orig_mask=0x1;
59     int recv_iter=0, send_iter=0;
60     int *knomial_reduce_src_array=NULL;
61     comm_size =  comm->size();
62     rank = comm->rank();
63
64     lroot = root;
65     relative_rank = (rank - lroot + comm_size) % comm_size;
66
67     /* First compute to whom we need to send data */
68     while (mask < comm_size) {
69         if (relative_rank % (reduce_knomial_factor*mask)) {
70             *dst = relative_rank/(reduce_knomial_factor*mask)*
71                 (reduce_knomial_factor*mask)+root;
72             if (*dst >= comm_size) {
73                 *dst -= comm_size;
74             }
75             send_iter++;
76             break;
77         }
78         mask *= reduce_knomial_factor;
79     }
80     mask /= reduce_knomial_factor;
81
82     /* Now compute how many children we have in the knomial-tree */
83     orig_mask = mask;
84     while (mask > 0) {
85         for(k=1;k<reduce_knomial_factor;k++) {
86             if (relative_rank + mask*k < comm_size) {
87                 recv_iter++;
88             }
89         }
90         mask /= reduce_knomial_factor;
91     }
92
93     /* Finally, fill up the src array */
94     if(recv_iter > 0) {
95       knomial_reduce_src_array = new int[recv_iter];
96     }
97
98     mask = orig_mask;
99     recv_iter=0;
100     while (mask > 0) {
101         for(k=1;k<reduce_knomial_factor;k++) {
102             if (relative_rank + mask*k < comm_size) {
103                 src = rank + mask*k;
104                 if (src >= comm_size) {
105                     src -= comm_size;
106                 }
107                 knomial_reduce_src_array[recv_iter++] = src;
108             }
109         }
110         mask /= reduce_knomial_factor;
111     }
112
113     *expected_recv_count = recv_iter;
114     *expected_send_count = send_iter;
115     *src_array = knomial_reduce_src_array;
116     return 0;
117 }
118
119 namespace simgrid {
120 namespace smpi {
121 int reduce__mvapich2_knomial(
122         const void *sendbuf,
123         void *recvbuf,
124         int count,
125         MPI_Datatype datatype,
126         MPI_Op op,
127         int root,
128         MPI_Comm comm)
129 {
130     int mpi_errno = MPI_SUCCESS;
131     int rank;
132     int src, k;
133     MPI_Request send_request;
134     int index=0;
135     MPI_Aint true_lb, true_extent, extent;
136     MPI_Status status;
137     int recv_iter=0, dst=-1, expected_send_count, expected_recv_count;
138     int *src_array=NULL;
139
140     if (count == 0) return MPI_SUCCESS;
141
142     rank = comm->rank();
143
144     /* Create a temporary buffer */
145
146     datatype->extent(&true_lb, &true_extent);
147     extent = datatype->get_extent();
148
149     bool is_commutative = (op == MPI_OP_NULL || op->is_commutative());
150
151     if (rank != root) {
152         recvbuf = (void*)smpi_get_tmp_recvbuffer(count * std::max(extent, true_extent));
153         recvbuf = (void *)((char*)recvbuf - true_lb);
154     }
155
156     if ((rank != root) || (sendbuf != MPI_IN_PLACE)) {
157         mpi_errno = Datatype::copy(sendbuf, count, datatype, recvbuf,
158                 count, datatype);
159     }
160
161
162     if(mv2_reduce_intra_knomial_factor<0)
163       {
164         mv2_reduce_intra_knomial_factor = SMPI_DEFAULT_KNOMIAL_FACTOR;
165       }
166     if(mv2_reduce_inter_knomial_factor<0)
167       {
168         mv2_reduce_inter_knomial_factor = SMPI_DEFAULT_KNOMIAL_FACTOR;
169       }
170
171
172     MPIR_Reduce_knomial_trace(root, mv2_reduce_intra_knomial_factor, comm,
173            &dst, &expected_send_count, &expected_recv_count, &src_array);
174
175     if(expected_recv_count > 0 ) {
176       unsigned char** tmp_buf = new unsigned char*[expected_recv_count];
177       MPI_Request* requests = new MPI_Request[expected_recv_count];
178       for (k = 0; k < expected_recv_count; k++) {
179         tmp_buf[k] = smpi_get_tmp_sendbuffer(count * std::max(extent, true_extent));
180         tmp_buf[k] = tmp_buf[k] - true_lb;
181         }
182
183         while(recv_iter  < expected_recv_count) {
184             src = src_array[expected_recv_count - (recv_iter+1)];
185
186             requests[recv_iter]=Request::irecv (tmp_buf[recv_iter], count, datatype ,src,
187                     COLL_TAG_REDUCE, comm);
188             recv_iter++;
189
190         }
191
192         recv_iter=0;
193         while(recv_iter < expected_recv_count) {
194             index=Request::waitany(expected_recv_count, requests,
195                     &status);
196             recv_iter++;
197
198             if (is_commutative) {
199               if(op!=MPI_OP_NULL) op->apply( tmp_buf[index], recvbuf, &count, datatype);
200             }
201         }
202
203         for(k=0; k < expected_recv_count; k++ ) {
204             smpi_free_tmp_buffer(tmp_buf[k]);
205         }
206         delete[] tmp_buf;
207         delete[] requests;
208     }
209
210     if(src_array != NULL) {
211       delete[] src_array;
212     }
213
214     if(rank != root) {
215         send_request=Request::isend(recvbuf,count, datatype, dst,
216                 COLL_TAG_REDUCE,comm);
217
218         Request::waitall(1, &send_request, &status);
219
220         smpi_free_tmp_buffer(static_cast<unsigned char*>(recvbuf) + true_lb);
221     }
222
223     /* --END ERROR HANDLING-- */
224
225     return mpi_errno;
226 }
227 }
228 }