ALL 0.9.4
A Loadbalacing Library
Loading...
Searching...
No Matches
ALL_Tensor.hpp
Go to the documentation of this file.
1/*
2Copyright 2018-2026 Rene Halver, Forschungszentrum Juelich GmbH, Germany
3Copyright 2018-2026 Godehard Sutmann, Forschungszentrum Juelich GmbH, Germany
4Copyright 2026-2026 Jonas Kroschewski, Forschungszentrum Juelich GmbH, Germany
5
6Redistribution and use in source and binary forms, with or without modification,
7are permitted provided that the following conditions are met:
8
91. Redistributions of source code must retain the above copyright notice, this
10 list of conditions and the following disclaimer.
11
122. Redistributions in binary form must reproduce the above copyright notice,
13this list of conditions and the following disclaimer in the documentation and/or
14 other materials provided with the distribution.
15
163. Neither the name of the copyright holder nor the names of its contributors
17may be used to endorse or promote products derived from this software without
18 specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*/
31
32#ifndef ALL_TENSOR_HEADER_INCLUDED
33#define ALL_TENSOR_HEADER_INCLUDED
34
36#include "ALL_Defines.h"
37#include "ALL_Functions.hpp"
38#include "ALL_LB.hpp"
39#include <exception>
40#include <mpi.h>
41
42namespace ALL {
43
54template <class T, class W> class Tensor_LB : public LB<T, W> {
55public:
62 Tensor_LB(int d, W w, T g) : LB<T, W>(d, g) {
63 this->setWork(w);
64 // need the lower and upper bounds
65 // of the domain for the tensor-based
66 // load-balancing scheme
67
68 // array of MPI communicators for each direction (to collect work
69 // on each plane)
70 communicators.resize(d);
71 nNeighbors.resize(2 * d);
72 //by default automatic calculation of gamma is turned on
73 this->gammaAutoCalc = true;
74 }
75
77 ~Tensor_LB() = default;
78
80 void setup() override;
81
84 virtual void balance(int step) override {balance(step, MPI_SUM);}
85
86 // getter for variables (passed by reference to avoid
87 // direct access to private members of the object)
88
92 virtual std::vector<int> &getNeighbors() override;
93
96 virtual void setAdditionalData(known_unused const void *data) override {}
97
100 virtual void balance(int step, MPI_Op reductionMode);
101
105 virtual W getEstimatedEfficiency() override {return (W)-1;};
106
107private:
108 // type for MPI communication
109 MPI_Datatype MPIDataTypeT;
110 MPI_Datatype MPIDataTypeW;
111
112 // array of MPI communicators for each direction (to collect work
113 // on each plane)
114 std::vector<MPI_Comm> communicators;
115
116 // list of neighbors
117 std::vector<int> neighbors;
118 std::vector<int> nNeighbors;
119
120protected:
121
122
123};
124
125// setup routine for the tensor-based load-balancing scheme
126// requires:
127// this->globalComm (int): cartesian MPI communicator, from
128// which separate sub communicators
129// are derived in order to represent
130// each plane of domains in the system
131template <class T, class W> void Tensor_LB<T, W>::setup() {
132 int status;
133
134 // check if Communicator is cartesian
135 MPI_Topo_test(this->globalComm, &status);
136 if (status != MPI_CART) {
138 __FILE__, __func__, __LINE__,
139 "Cartesian MPI communicator required, passed communicator not "
140 "cartesian");
141 }
142
143 int dim = this->getDimension();
144
145 // get the local coordinates, periodicity and global size from the MPI
146 // communicator
147 MPI_Cart_get(this->globalComm, dim, this->global_dims.data(),
148 this->periodicity.data(), this->local_coords.data());
149
150 // get the local rank from the MPI communicator
151 MPI_Cart_rank(this->globalComm, this->local_coords.data(), &this->localRank);
152
153 // create sub-communicators
154 for (int i = 0; i < dim; ++i) {
155 MPI_Comm_split(this->globalComm, this->local_coords.at(i), 0,
156 &communicators[i]);
157 }
158
159 // determine correct MPI data type for template T
160 if (std::is_same<T, double>::value)
161 MPIDataTypeT = MPI_DOUBLE;
162 else if (std::is_same<T, float>::value)
163 MPIDataTypeT = MPI_FLOAT;
164 else if (std::is_same<T, int>::value)
165 MPIDataTypeT = MPI_INT;
166 else if (std::is_same<T, long>::value)
167 MPIDataTypeT = MPI_LONG;
168
169 // determine correct MPI data type for template W
170 if (std::is_same<W, double>::value)
171 MPIDataTypeW = MPI_DOUBLE;
172 else if (std::is_same<W, float>::value)
173 MPIDataTypeW = MPI_FLOAT;
174 else if (std::is_same<W, int>::value)
175 MPIDataTypeW = MPI_INT;
176 else if (std::is_same<W, long>::value)
177 MPIDataTypeW = MPI_LONG;
178
179 // calculate neighbors
180 int rank_left, rank_right;
181
182 neighbors.clear();
183 for (int i = 0; i < dim; ++i) {
184 MPI_Cart_shift(this->globalComm, i, 1, &rank_left, &rank_right);
185 neighbors.push_back(rank_left);
186 neighbors.push_back(rank_right);
187 nNeighbors[2 * i] = 1;
188 nNeighbors[2 * i + 1] = 1;
189 }
190}
191
192template <class T, class W> void Tensor_LB<T, W>::balance(int step, MPI_Op reductionMode) {
193 int dim = this->getDimension();
194 std::vector<Point<T>> newVertices = this->vertices;
195 this->prevVertices = this->vertices;
196
197 bool localIsSum = reductionMode == MPI_SUM;
198 bool localIsMax = reductionMode == MPI_MAX;
199
200 // loop over all available dimensions
201 for (int i = 0; i < dim; ++i) {
202 W work_local_plane;
203 // collect work from all processes in the same plane
204 MPI_Allreduce(this->getWork().data(), &work_local_plane, 1, MPIDataTypeW,
205 reductionMode, communicators.at(i));
206
207 // correct right border:
208
209 W remote_work;
210 T local_size;
211 T remote_size;
212 // determine neighbors
213 int rank_left, rank_right;
214
215 MPI_Cart_shift(this->globalComm, i, 1, &rank_left, &rank_right);
216
217 // collect work from right neighbor plane
218 MPI_Request sreq, rreq;
219 MPI_Status sstat, rstat;
220
221 MPI_Irecv(&remote_work, 1, MPIDataTypeW, rank_right, 0, this->globalComm,
222 &rreq);
223 MPI_Isend(&work_local_plane, 1, MPIDataTypeW, rank_left, 0,
224 this->globalComm, &sreq);
225 MPI_Wait(&sreq, &sstat);
226 MPI_Wait(&rreq, &rstat);
227
228 // collect size in dimension from right neighbor plane
229
230 local_size = this->prevVertices.at(1)[i] - this->prevVertices.at(0)[i];
231
232 MPI_Irecv(&remote_size, 1, MPIDataTypeT, rank_right, 0, this->globalComm,
233 &rreq);
234 MPI_Isend(&local_size, 1, MPIDataTypeT, rank_left, 0, this->globalComm,
235 &sreq);
236 MPI_Wait(&sreq, &sstat);
237 MPI_Wait(&rreq, &rstat);
238
239 // automatic selection of gamma to guarantee stability of method (choice of
240 // user gamma ignored)
241 if(this->gammaAutoCalc == true) {
242 this->gamma =
243 std::max(4.1, 2.0 * (1.0 + std::max(local_size, remote_size) /
244 std::min(local_size, remote_size)));
245 }
246
247 T shift = Functions::borderShift1d(
248 rank_right, this->local_coords.at(i), this->global_dims.at(i),
249 work_local_plane, remote_work, local_size, remote_size, this->gamma,
250 this->minSize[i]);
251
252 // send shift to right neighbors
253 T remote_shift = (T)0;
254
255 MPI_Irecv(&remote_shift, 1, MPIDataTypeT, rank_left, 0, this->globalComm,
256 &rreq);
257 MPI_Isend(&shift, 1, MPIDataTypeT, rank_right, 0, this->globalComm, &sreq);
258 MPI_Wait(&sreq, &sstat);
259 MPI_Wait(&rreq, &rstat);
260
261 // if a left neighbor exists: shift left border
262 if (rank_left != MPI_PROC_NULL && this->local_coords[i] != 0)
263 newVertices.at(0)[i] = this->prevVertices.at(0)[i] + remote_shift;
264 else
265 newVertices.at(0)[i] = this->prevVertices.at(0)[i];
266
267 // if a right neighbor exists: shift right border
268 if (rank_right != MPI_PROC_NULL &&
269 this->local_coords[i] != this->global_dims[i] - 1)
270 newVertices.at(1)[i] = this->prevVertices.at(1)[i] + shift;
271 else
272 newVertices.at(1)[i] = this->prevVertices.at(1)[i];
273 }
274
275 this->setVertices(newVertices);
276}
277
278// provide list of neighbors
279template <class T, class W> std::vector<int> &Tensor_LB<T, W>::getNeighbors() {
280 return neighbors;
281}
282
294template <class T, class W> class TensorMax_LB : public Tensor_LB<T, W> {
295public:
297 TensorMax_LB(int d, W w, T g) : Tensor_LB<T, W>(d, w, g) {}
298 virtual void balance(int step) override {Tensor_LB<T,W>::balance(step, MPI_MAX);}
299};
300
301} // namespace ALL
302
303#endif
#define known_unused
Definition ALL_Defines.h:49
LB(const int dim, const T g)
Definition ALL_LB.hpp:50
virtual void setVertices(const std::vector< Point< T > > &vertices_in)
Definition ALL_LB.hpp:77
MPI_Comm globalComm
used MPI communicator
Definition ALL_LB.hpp:227
std::vector< int > global_dims
dimensions of the global process grid
Definition ALL_LB.hpp:242
virtual void setWork(const std::vector< W > &w)
Definition ALL_LB.hpp:121
bool gammaAutoCalc
turn on/off autocalculation of gamma factor if present
Definition ALL_LB.hpp:223
virtual std::vector< W > & getWork()
Definition ALL_LB.hpp:159
T gamma
correction factor
Definition ALL_LB.hpp:221
virtual int getDimension()
Definition ALL_LB.hpp:100
std::vector< int > local_coords
cartesian coordinates of the local domain in the process grid
Definition ALL_LB.hpp:244
std::vector< Point< T > > prevVertices
original vertices before previous balancing step
Definition ALL_LB.hpp:240
std::vector< Point< T > > vertices
local vertices after previous balancing step
Definition ALL_LB.hpp:238
virtual void balance(int step) override
TensorMax_LB(int d, W w, T g)
virtual W getEstimatedEfficiency() override
~Tensor_LB()=default
default destructor
void setup() override
setup internal data structures and parameters
Tensor_LB()
default constuctor
virtual void setAdditionalData(known_unused const void *data) override
virtual std::vector< int > & getNeighbors() override
Tensor_LB(int d, W w, T g)
virtual void balance(int step) override
T borderShift1d(const int remote_rank, const int local_coord, const int global_dim, const W local_work, const W remote_work, const T local_size, const T remote_size, const T gamma, const T minSize)
Definition ALL.hpp:78