Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Update copyright lines for 2022.
[simgrid.git] / src / smpi / colls / allgather / allgather-3dmesh.cpp
1 /* Copyright (c) 2013-2022. 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 #include "../colls_private.hpp"
8
9 /*****************************************************************************
10
11 Copyright (c) 2006, Ahmad Faraj & Xin Yuan,
12 All rights reserved.
13
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions are met:
16
17   * Redistributions of source code must retain the above copyright notice,
18     this list of conditions and the following disclaimer.
19
20   * Redistributions in binary form must reproduce the above copyright notice,
21     this list of conditions and the following disclaimer in the documentation
22     and/or other materials provided with the distribution.
23
24   * Neither the name of the Florida State University nor the names of its
25     contributors may be used to endorse or promote products derived from this
26     software without specific prior written permission.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
32 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
35 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39   *************************************************************************
40   *     Any results obtained from executing this software require the     *
41   *     acknowledgment and citation of the software and its owners.       *
42   *     The full citation is given below:                                 *
43   *                                                                       *
44   *     A. Faraj and X. Yuan. "Automatic Generation and Tuning of MPI     *
45   *     Collective Communication Routines." The 19th ACM International    *
46   *     Conference on Supercomputing (ICS), Cambridge, Massachusetts,     *
47   *     June 20-22, 2005.                                                 *
48   *************************************************************************
49
50 *****************************************************************************/
51
52 /*****************************************************************************
53  * Function: is_3dmesh
54  * return: bool
55  * num: the number of processors in a communicator
56  * i: x dimension
57  * j: y dimension
58  * k: z dimension
59  * descp: takes a number and tries to find a factoring of x*y*z mesh out of it
60  ****************************************************************************/
61 #ifndef THREED
62 #define THREED
63 static bool is_3dmesh(int num, int* i, int* j, int* k)
64 {
65   int x, max = num / 3;
66   x = cbrt(num);
67   *i = *j = *k = 0;
68   while (x <= max) {
69     if ((num % (x * x)) == 0) {
70       *i = *j = x;
71       *k = num / (x * x);
72       return true;
73     }
74     x++;
75   }
76   return false;
77 }
78 #endif
79 /*****************************************************************************
80  * Function: allgather_3dmesh_shoot
81  * return: int
82  * send_buff: send input buffer
83  * send_count: number of elements to send
84  * send_type: data type of elements being sent
85  * recv_buff: receive output buffer
86  * recv_count: number of elements to received
87  * recv_type: data type of elements being received
88  * comm: communication
89  * Descrp: Function realizes the allgather operation using the 2dmesh
90  * algorithm. Allgather ommunication occurs first in the x dimension, y
91  * dimension, and then in the z dimension. Communication in each dimension
92  * follows "simple"
93  * Author: Ahmad Faraj
94 ****************************************************************************/
95 namespace simgrid{
96 namespace smpi{
97
98
99 int allgather__3dmesh(const void *send_buff, int send_count,
100                       MPI_Datatype send_type, void *recv_buff,
101                       int recv_count, MPI_Datatype recv_type,
102                       MPI_Comm comm)
103 {
104   MPI_Aint extent;
105
106   int i, src, dst, rank, num_procs, block_size, my_z_base;
107   int my_z, X, Y, Z, send_offset, recv_offset;
108   int two_dsize, my_row_base, my_col_base, src_row_base, src_z_base, num_reqs;
109   int tag = COLL_TAG_ALLGATHER;
110
111   rank = comm->rank();
112   num_procs = comm->size();
113   extent = send_type->get_extent();
114
115   if (not is_3dmesh(num_procs, &X, &Y, &Z))
116     throw std::invalid_argument("allgather_3dmesh algorithm can't be used with this number of processes!");
117
118   num_reqs = X;
119
120   if (Y > X)
121     num_reqs = Y;
122   if (Z > Y)
123     num_reqs = Z;
124
125   two_dsize = X * Y;
126   my_z = rank / two_dsize;
127
128   my_row_base = (rank / X) * X;
129   my_col_base = (rank % Y) + (my_z * two_dsize);
130   my_z_base = my_z * two_dsize;
131
132   block_size = extent * send_count;
133
134   auto* req            = new MPI_Request[num_reqs];
135   MPI_Request* req_ptr = req;
136
137   // do local allgather/local copy
138   recv_offset = rank * block_size;
139   Datatype::copy(send_buff, send_count, send_type, (char *)recv_buff + recv_offset,
140                  recv_count, recv_type);
141
142   // do rowwise comm
143   for (i = 0; i < Y; i++) {
144     src = i + my_row_base;
145     if (src == rank)
146       continue;
147     recv_offset = src * block_size;
148     *(req_ptr++) = Request::irecv((char *)recv_buff + recv_offset, send_count, recv_type, src, tag,
149                comm);
150   }
151
152   for (i = 0; i < Y; i++) {
153     dst = i + my_row_base;
154     if (dst == rank)
155       continue;
156     Request::send(send_buff, send_count, send_type, dst, tag, comm);
157   }
158
159   Request::waitall(Y - 1, req, MPI_STATUSES_IGNORE);
160   req_ptr = req;
161
162   // do colwise comm, it does not matter here if i*X or i *Y since X == Y
163
164   for (i = 0; i < X; i++) {
165     src = (i * Y + my_col_base);
166     if (src == rank)
167       continue;
168
169     src_row_base = (src / X) * X;
170     recv_offset = src_row_base * block_size;
171     *(req_ptr++) = Request::irecv((char *)recv_buff + recv_offset, recv_count * Y, recv_type, src, tag,
172                comm);
173   }
174
175   send_offset = my_row_base * block_size;
176
177   for (i = 0; i < X; i++) {
178     dst = (i * Y + my_col_base);
179     if (dst == rank)
180       continue;
181     Request::send((char *)recv_buff + send_offset, send_count * Y, send_type, dst, tag,
182               comm);
183   }
184
185   Request::waitall(X - 1, req, MPI_STATUSES_IGNORE);
186   req_ptr = req;
187
188   for (i = 1; i < Z; i++) {
189     src = (rank + i * two_dsize) % num_procs;
190     src_z_base = (src / two_dsize) * two_dsize;
191
192     recv_offset = (src_z_base * block_size);
193
194     *(req_ptr++) = Request::irecv((char *)recv_buff + recv_offset, recv_count * two_dsize, recv_type,
195                src, tag, comm);
196   }
197
198   for (i = 1; i < Z; i++) {
199     dst = (rank + i * two_dsize) % num_procs;
200     send_offset = my_z_base * block_size;
201     Request::send((char *)recv_buff + send_offset, send_count * two_dsize, send_type,
202               dst, tag, comm);
203   }
204   Request::waitall(Z - 1, req, MPI_STATUSES_IGNORE);
205
206   delete[] req;
207
208   return MPI_SUCCESS;
209 }
210
211
212 }
213 }