KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
alltoall_grid.hpp
Go to the documentation of this file.
1// This file is part of KaMPIng.
2//
3// Copyright 2024 The KaMPIng Authors
4//
5// KaMPIng is free software : you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
7// version. KaMPIng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
9// for more details.
10//
11// You should have received a copy of the GNU Lesser General Public License along with KaMPIng. If not, see
12// <https://www.gnu.org/licenses/>.
13
14/// @file
15/// @brief Plugin to enable grid communication.
16
17#include <numeric>
18
20#include "kamping/collectives/alltoall.hpp"
21#include "kamping/communicator.hpp"
23#include "kamping/plugin/plugin_helpers.hpp"
24
25#pragma once
26
27namespace kamping::plugin {
28
29/// @brief Descriptor for different levels for message envelopes used in indirect communication.
31 no_envelope, ///< do not use an envelope at all (if possible)
32 source, ///< only additionally add the source PE in the envelope (if possible)
33 source_and_destination ///< add source and destination PE in the envelope
34};
35
36namespace grid_plugin_helpers {
37
38/// @brief Mixin for \ref MessageEnvelope to store a source PE.
39struct Source {
40 /// @brief Get destination PE.
41 [[nodiscard]] size_t get_source() const {
43 }
44
45 /// @brief Get destination PE.
46 [[nodiscard]] int get_source_signed() const {
47 return source;
48 }
49
50 /// @brief Set destination PE.
51 void set_source(int value) {
52 source = value;
53 }
54 int source; ///< Rank of source PE.
55};
56
57/// @brief Mixin for \ref MessageEnvelope to store a destination PE.
59 /// @brief Get destination PE.
60 [[nodiscard]] size_t get_destination() const {
62 }
63
64 /// @brief Get destination PE.
66 return destination;
67 }
68
69 /// @brief Set destination PE.
70 void set_destination(int value) {
71 destination = value;
72 }
73 int destination; ///< Rank of destination PE.
74};
75
76/// @brief Augments a plain message with additional information via \tparam Attributes
77/// @tparam PayloadType Plain message type.
78/// @tparam Attributes source or destination information
79template <typename PayloadType, typename... Attributes>
80struct MessageEnvelope : public Attributes... {
81 using Payload = PayloadType; ///< Underlying Type of message.
82 static constexpr bool has_source_information =
83 internal::type_list<Attributes...>::template contains<Source>; ///< Indicates whether the envelope contains the
84 ///< source PE.
85 static constexpr bool has_destination_information =
86 internal::type_list<Attributes...>::template contains<Destination>; ///< Indicates whether the envelope contains
87 ///< the destination PE.
88 /// @brief Default constructor.
89 MessageEnvelope() = default;
90
91 /// @brief Constructor for wrapping a message.
93
94 /// @brief Return reference to payload.
96 return _payload;
97 }
98
99 /// @brief Return const reference to payload.
100 Payload const& get_payload() const {
101 return _payload;
102 }
103
104 /// @brief Output operator.
105 friend std::ostream& operator<<(std::ostream& out, MessageEnvelope const& msg) {
106 out << "(payload: " << msg.get_payload();
108 out << ", source: " << msg.get_source();
109 }
111 out << ", destination: " << msg.get_destination();
112 }
113 out << ")";
114 return out;
115 }
116
117 Payload _payload; ///< payload
118};
119
120/// @brief Select the right MessageEnvelope depending on the provided MsgEnvelopeLevel.
121template <MessageEnvelopeLevel level, typename T>
122using MessageEnvelopeType = std::conditional_t<
123 level == MessageEnvelopeLevel::no_envelope,
124 T,
125 std::conditional_t<
126 level == MessageEnvelopeLevel::source,
129
130/// @brief Class representing a position within a logical two-dimensional processor grid.
132 size_t row_index; ///< Row position.
133 size_t col_index; ///< Column position.
134};
135
136} // namespace grid_plugin_helpers
137
138namespace grid {
139/// @brief Object returned by \ref plugin::GridCommunicator::make_grid_communicator() representing a grid
140/// communicator which enables alltoall communication with a latency in `sqrt(p)` where p is the size of the
141/// original communicator.
142/// @tparam DefaultContainerType Container type of the original communicator.
143template <template <typename...> typename DefaultContainerType>
145public:
146 using LevelCommunicator = kamping::Communicator<DefaultContainerType>; ///< Type of row and column communicator.
147
148 /// @brief Creates a two dimensional grid by splitting the given communicator of size `p` into a row and a column
149 /// communicator each of size about `sqrt(p)`.
150 /// @tparam Comm Type of the communicator.
151 /// @param comm Communicator to be split into a two-dimensional grid.
152 template <
153 template <typename...> typename = DefaultContainerType,
154 template <typename, template <typename...> typename>
155 typename... Plugins>
157 : _size_of_orig_comm{comm.size()},
158 _rank_in_orig_comm{comm.rank()} {
159 double const sqrt = std::sqrt(comm.size());
160 size_t const floor_sqrt = static_cast<size_t>(std::floor(sqrt));
161 size_t const ceil_sqrt = static_cast<size_t>(std::ceil(sqrt));
162 // We want to ensure that #columns + 1 >= #rows >= #columns.
163 // Therefore, use floor(sqrt(comm.size())) columns unless we have enough PEs to begin another row when using
164 // ceil(sqrt(comm.size()) columns.
165 size_t const threshold = floor_sqrt * ceil_sqrt;
166 _num_columns = (comm.size() >= threshold) ? ceil_sqrt : floor_sqrt;
167 size_t const num_ranks_in_incomplete_column = comm.size() / _num_columns;
168 auto [row, col] = pos_in_complete_grid(comm.rank()); // assume that we have a complete grid,
169 _size_complete_rectangle = _num_columns * num_ranks_in_incomplete_column;
170 if (comm.rank() >= _size_complete_rectangle) {
171 row = comm.rank() % _num_columns; // rank() is member of last incomplete row,
172 // therefore append it to one of the first
173 }
174 {
175 auto split_comm = comm.split(static_cast<int>(row), comm.rank_signed());
176 _row_comm = LevelCommunicator(split_comm.disown_mpi_communicator(), split_comm.root_signed(), true);
177 }
178 {
179 auto split_comm = comm.split(static_cast<int>(col), comm.rank_signed());
180 _column_comm = LevelCommunicator(split_comm.disown_mpi_communicator(), split_comm.root_signed(), true);
181 }
182 }
183
184 /// @brief Indirect two dimensional grid based personalized alltoall exchange.
185 /// The following parameters are required:
186 /// - \ref kamping::send_buf() containing the data that is sent to each rank. The size of this buffer has to be at
187 /// least the sum of the send_counts argument.
188 /// - \ref kamping::send_counts() containing the number of elements to send to each rank.
189 /// - \ref kamping::send_displs() containing the number of elements to send to each rank.
190 ///
191 /// The following parameters are optional:
192 /// - \ref kamping::send_displs() containing the offsets of the messages in send_buf. The `send_counts[i]` elements
193 /// starting at `send_buf[send_displs[i]]` will be sent to rank `i`. If omitted, this is calculated as the exclusive
194 /// prefix-sum of `send_counts`.
195 ///
196 /// Internally, each element in the send buffer is wrapped in an envelope to facilitate the indirect routing. The
197 /// envelope consists at least of the destination PE of each element but can be extended to also hold the
198 /// source PE of the element. The caller can specify whether they want to keep this information also in the output
199 /// via the \tparam envelope_level.
200 ///
201 /// @tparam envelope_level Determines the contents of the envelope of each returned element (no_envelope = use the
202 /// actual data type of an exchanged element, source = augment the actual data type with the source PE,
203 /// source_and_destination = argument the actual data type with the source and destination PE).
204 /// @tparam Args Automatically deducted template parameters.
205 /// @param args All required and any number of the optional buffers described above.
206 /// @returns
207 template <MessageEnvelopeLevel envelope_level = MessageEnvelopeLevel::no_envelope, typename... Args>
210 Args,
213 );
214 // Get send_buf
215 auto const& send_buf =
216 internal::select_parameter_type<internal::ParameterType::send_buf>(args...).construct_buffer_or_rebind();
217 // Get send_counts
218 auto const& send_counts = internal::select_parameter_type<internal::ParameterType::send_counts>(args...)
220
222 auto&& send_displs =
223 internal::select_parameter_type_or_default<internal::ParameterType::send_displs, default_send_displs_type>(
224 std::tuple(),
225 args...
226 )
228 // Calculate send_displs if necessary
230 if constexpr (do_calculate_send_displs) {
231 send_displs.resize_if_requested([&]() { return _size_of_orig_comm; });
232 std::exclusive_scan(send_counts.data(), send_counts.data() + _size_of_orig_comm, send_displs.data(), 0);
233 }
236 }
237
238 /// @brief Indirect two dimensional grid based personalized alltoall exchange.
239 /// The following parameters are required:
240 /// - \ref kamping::send_buf() containing the data that is sent to each rank. The size of this buffer has to be at
241 /// least the sum of the send_counts argument.
242 ///
243 /// - \ref kamping::send_counts() containing the number of elements to send to each rank.
244 ///
245 /// The following parameters are optional:
246 /// - \ref kamping::send_displs() containing the offsets of the messages in send_buf. The `send_counts[i]` elements
247 /// starting at `send_buf[send_displs[i]]` will be sent to rank `i`. If omitted, this is calculated as the exclusive
248 /// prefix-sum of `send_counts`.
249 ///
250 /// - \ref kamping::recv_counts() containing the number of elements to receive from each rank.
251 ///
252 /// - \ref kamping::recv_buf() containing a buffer for the output. Afterwards, this buffer will contain
253 ///
254 /// the data received as specified for send_buf. The buffer will be resized according to the buffer's
255 /// kamping::BufferResizePolicy. If resize policy is kamping::BufferResizePolicy::no_resize, the buffer's underlying
256 /// storage must be large enough to store all received elements.
257 ///
258 /// Internally, \ref alltoallv_with_envelope() is called.
259 ///
260 /// @tparam envelope_level Determines the contents of the envelope of each returned element (no_envelope = use the
261 /// actual data type of an exchanged element, source = augment the actual data type with the source PE,
262 /// source_and_destination = argument the actual data type with the source and destination PE).
263 /// @tparam Args Automatically deducted template parameters.
264 /// @param args All required and any number of the optional buffers described above.
265 /// @return Result type wrapping the output buffer and recv_counts (if requested).
266 template <typename... Args>
267 auto alltoallv(Args... args) const {
269 Args,
272 );
273 constexpr MessageEnvelopeLevel envelope_level = MessageEnvelopeLevel::source;
274 // get send_buf
275 auto& send_buf = internal::select_parameter_type<internal::ParameterType::send_buf>(args...);
276 using send_value_type = typename std::remove_reference_t<decltype(send_buf)>::value_type;
277 using default_recv_value_type = std::remove_const_t<send_value_type>;
278 // get send_counts
279 auto const& send_counts = internal::select_parameter_type<internal::ParameterType::send_counts>(args...)
281
283 auto&& send_displs =
284 internal::select_parameter_type_or_default<internal::ParameterType::send_displs, default_send_displs_type>(
285 std::tuple(),
286 args...
287 )
289 // Calculate send_displs if necessary
291 if constexpr (do_calculate_send_displs) {
292 send_displs.resize_if_requested([&]() { return _size_of_orig_comm; });
293 std::exclusive_scan(send_counts.data(), send_counts.data() + _size_of_orig_comm, send_displs.data(), 0);
294 }
295
296 // perform the actual message exchange
298 std::move(send_buf),
299 kamping::send_counts(send_counts.underlying()),
301 );
302
303 // post-processing (fixing ordering problems etc.)
304 // Get recv counts
306 auto&& recv_counts =
307 internal::select_parameter_type_or_default<internal::ParameterType::recv_counts, default_recv_counts_type>(
308 std::tuple(),
309 args...
310 )
313
314 if constexpr (do_calculate_recv_counts) {
315 recv_counts.resize_if_requested([&]() { return _size_of_orig_comm; });
316 KASSERT(recv_counts.size() >= _size_of_orig_comm, "Recv counts buffer is not large enough.", assert::light);
318 std::fill(recv_counts_span.begin(), recv_counts_span.end(), 0);
319
320 for (size_t i = 0; i < grid_recv_buf.size(); ++i) {
321 ++recv_counts_span[grid_recv_buf[i].get_source()];
322 }
323 } else {
324 KASSERT(recv_counts.size() >= this->size(), "Recv counts buffer is not large enough.", assert::light);
325 }
326
327 // Get recv displs
329 auto&& recv_displs =
330 internal::select_parameter_type_or_default<internal::ParameterType::recv_displs, default_recv_displs_type>(
331 std::tuple(),
332 args...
333 )
336
337 if constexpr (do_calculate_recv_displs) {
338 recv_displs.resize_if_requested([&]() { return _size_of_orig_comm; });
339 KASSERT(recv_displs.size() >= _size_of_orig_comm, "Recv displs buffer is not large enough.", assert::light);
342 std::exclusive_scan(recv_counts_span.begin(), recv_counts_span.end(), recv_displs_span.begin(), 0);
343 }
344
345 // get recv_buf
348 auto&& recv_buf =
349 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
350 std::tuple(),
351 args...
352 )
354
355 write_recv_buffer(grid_recv_buf, recv_buf, recv_counts, recv_displs);
356
357 return internal::make_mpi_result<std::tuple<Args...>>(
358 std::move(send_displs),
359 std::move(recv_buf),
360 std::move(recv_counts),
361 std::move(recv_displs)
362 );
363 }
364
365private:
366 template <typename GridRecvBuffer, typename RecvBuffer, typename RecvCounts, typename RecvDispls>
367 void write_recv_buffer(
370 RecvCounts const& recv_counts,
372 ) const {
373 auto write_pos = recv_displs.underlying();
374 Span write_pos_span(write_pos.data(), write_pos.size());
375 auto compute_required_recv_buf_size = [&]() {
378 };
379
380 recv_buf.resize_if_requested(compute_required_recv_buf_size);
381 KASSERT(
383 "Recv buffer is not large enough to hold all received elements.",
385 );
386
387 Span recv_buf_span(recv_buf.data(), recv_buf.size());
389 for (auto const& elem: grid_recv_buf_span) {
390 size_t const pos = asserting_cast<size_t>(write_pos_span[elem.get_source()]++);
391 recv_buf_span[pos] = std::move(elem.get_payload());
392 }
393 }
394
395 template <typename SendCounts>
396 [[nodiscard]] auto compute_row_send_counts(SendCounts const& send_counts) const {
397 DefaultContainerType<int> row_send_counts(_row_comm.size(), 0);
398 for (size_t i = 0; i < send_counts.size(); ++i) {
399 size_t const destination_pe = get_destination_in_rowwise_exchange(i);
400 row_send_counts.data()[destination_pe] += send_counts.data()[i];
401 }
402 return row_send_counts;
403 }
404
405 [[nodiscard]] grid_plugin_helpers::GridPosition pos_in_complete_grid(size_t rank) const {
406 return grid_plugin_helpers::GridPosition{rank / _num_columns, rank % _num_columns};
407 }
408
409 [[nodiscard]] size_t get_destination_in_rowwise_exchange(size_t destination_rank) const {
410 return pos_in_complete_grid(destination_rank).col_index;
411 }
412
413 [[nodiscard]] size_t get_destination_in_colwise_exchange(size_t destination_rank) const {
414 return pos_in_complete_grid(destination_rank).row_index;
415 }
416
417 template <MessageEnvelopeLevel envelope_level, typename SendBuffer, typename SendCounts, typename SendDispls>
418 auto
419 rowwise_exchange(SendBuffer const& send_buf, SendCounts const& send_counts, SendDispls const& send_displs) const {
420 using namespace grid_plugin_helpers;
421 auto const row_send_counts = compute_row_send_counts(send_counts.underlying());
422 DefaultContainerType<int> row_send_displs(_row_comm.size());
423 Span row_send_counts_span(row_send_counts.data(), row_send_counts.size());
424 Span row_send_displs_span(row_send_displs.data(), row_send_displs.size());
425 std::exclusive_scan(
426 row_send_counts_span.begin(),
427 row_send_counts_span.end(),
428 row_send_displs_span.begin(),
429 int(0)
430 );
431 auto index_displacements = row_send_displs;
432 auto const total_send_count = static_cast<size_t>(row_send_displs_span.back() + row_send_counts_span.back());
433
434 using value_type = typename SendBuffer::value_type;
435 using MsgType = std::conditional_t<
436 envelope_level == MessageEnvelopeLevel::no_envelope,
437 MessageEnvelope<value_type, Destination>,
438 MessageEnvelope<value_type, Source, Destination>>;
439 DefaultContainerType<MsgType> rowwise_send_buf(total_send_count);
440
441 for (size_t i = 0; i < send_counts.size(); ++i) {
442 size_t const send_count = asserting_cast<size_t>(send_counts.underlying().data()[i]);
443 if (send_count == 0) {
444 continue;
445 }
446 int const destination = asserting_cast<int>(i);
447 auto const destination_in_row = get_destination_in_rowwise_exchange(asserting_cast<size_t>(i));
448 size_t const cur_displacement = asserting_cast<size_t>(send_displs.data()[i]);
449 for (std::size_t ii = 0; ii < send_count; ++ii) {
450 auto elem = send_buf.data()[cur_displacement + ii];
451 auto const idx = index_displacements[destination_in_row]++;
452 auto& entry = rowwise_send_buf[static_cast<size_t>(idx)];
453 entry = MsgType(std::move(elem));
454 entry.set_destination(destination
455 ); // this has to be done independently of the envelope level, otherwise routing is not possible
456 //
457 if constexpr (envelope_level != MessageEnvelopeLevel::no_envelope) {
458 entry.set_source(asserting_cast<int>(_rank_in_orig_comm));
459 }
460 }
461 }
462 return _row_comm.alltoallv(
463 kamping::send_buf(rowwise_send_buf),
464 kamping::send_counts(row_send_counts),
465 kamping::send_displs(row_send_displs)
466 );
467 }
468
469 template <
470 MessageEnvelopeLevel envelope_level,
471 template <typename...>
472 typename RowwiseRecvBuf,
473 typename... EnvelopeArgs>
474 auto columnwise_exchange(RowwiseRecvBuf<grid_plugin_helpers::MessageEnvelope<EnvelopeArgs...>>&& rowwise_recv_buf
475 ) const {
476 using namespace grid_plugin_helpers;
477 using IndirectMessageType = MessageEnvelope<EnvelopeArgs...>;
478 using Payload = typename IndirectMessageType::Payload;
479
480 DefaultContainerType<int> send_counts(_column_comm.size(), 0);
481 for (auto const& elem: rowwise_recv_buf) {
482 ++send_counts[get_destination_in_colwise_exchange(elem.get_destination())];
483 }
484 DefaultContainerType<int> send_offsets = send_counts;
485 Span send_counts_span(send_counts.data(), send_counts.size());
486 Span send_offsets_span(send_offsets.data(), send_offsets.size());
487 std::exclusive_scan(send_counts_span.begin(), send_counts_span.end(), send_offsets_span.begin(), int(0));
488 DefaultContainerType<int> send_displacements = send_offsets;
489
490 using MsgType = MessageEnvelopeType<envelope_level, Payload>;
491 DefaultContainerType<MsgType> colwise_send_buf(rowwise_recv_buf.size());
492 for (auto& elem: rowwise_recv_buf) {
493 auto const dst_in_column = get_destination_in_colwise_exchange(elem.get_destination());
494 auto& entry = colwise_send_buf[static_cast<std::size_t>(send_offsets[dst_in_column]++)];
495 entry = MsgType(std::move(elem.get_payload()));
496 if constexpr (envelope_level == MessageEnvelopeLevel::no_envelope) {
497 // nothing to be done
498 } else if constexpr (envelope_level == MessageEnvelopeLevel::source) {
499 entry.set_source(elem.get_source_signed());
500 } else if constexpr (envelope_level == MessageEnvelopeLevel::source_and_destination) {
501 entry.set_source(elem.get_source_signed());
502 entry.set_destination(elem.get_destination_signed());
503 } else {
504 static_assert(
505 envelope_level == MessageEnvelopeLevel::source_and_destination /*always false*/,
506 "This branch is never used"
507 );
508 }
509 }
510 {
511 // deallocate rowwise_recv_buf as it is not needed anymore
512 rowwise_recv_buf.clear();
513 auto tmp = std::move(rowwise_recv_buf);
514 }
515 return _column_comm.alltoallv(
516 kamping::send_buf(colwise_send_buf),
518 kamping::send_displs(send_displacements)
519 );
520 }
521
522private:
523 size_t _size_of_orig_comm;
524 size_t _rank_in_orig_comm;
525 size_t _size_complete_rectangle;
526 size_t _num_columns;
529};
530} // namespace grid
531
532/// @brief Plugin adding a two dimensional communication grid to the communicator.
533///
534/// PEs are row-major and abs(`#row - #columns`) <= 1
535/// 0 1 2 3
536/// 4 5 6 7
537/// 8 9 10 11
538/// 12 13 14 15
539///
540/// If `#PE != #row * #column` then the PEs of the last incomplete row are transposed and appended to
541/// the first rows and do not form an own row based communicator.
542/// 0 1 2 3 16
543/// 4 5 6 7 17
544/// 8 9 10 11
545/// 12 13 14 15
546/// (16 17)
547/// This enables personalized alltoall exchanges with a latency in about `sqrt(#PE)`.
548template <typename Comm, template <typename...> typename DefaultContainerType>
549class GridCommunicator : public plugin::PluginBase<Comm, DefaultContainerType, GridCommunicator> {
550public:
551 /// @brief Returns a \ref kamping::plugin::GridCommunicator.
553 return grid::GridCommunicator<DefaultContainerType>(this->to_communicator());
554 }
555};
556
557} // namespace kamping::plugin
MessageEnvelopeLevel
Descriptor for different levels for message envelopes used in indirect communication.
Definition alltoall_grid.hpp:30
@ no_envelope
do not use an envelope at all (if possible)
Definition alltoall_grid.hpp:31
@ source
only additionally add the source PE in the envelope (if possible)
Definition alltoall_grid.hpp:32
@ source_and_destination
add source and destination PE in the envelope
Definition alltoall_grid.hpp:33
std::conditional_t< level==MessageEnvelopeLevel::no_envelope, T, std::conditional_t< level==MessageEnvelopeLevel::source, MessageEnvelope< T, Source >, MessageEnvelope< T, Source, Destination > > > MessageEnvelopeType
Select the right MessageEnvelope depending on the provided MsgEnvelopeLevel.
Definition alltoall_grid.hpp:122
Helper functions that make casts safer.
size_t size() const
Number of MPI processes in this communicator as size_t.
Definition communicator.hpp:168
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
A span modeled after C++20's std::span.
Definition span.hpp:52
Plugin adding a two dimensional communication grid to the communicator.
Definition alltoall_grid.hpp:549
auto make_grid_communicator() const
Returns a kamping::plugin::GridCommunicator.
Definition alltoall_grid.hpp:552
Object returned by plugin::GridCommunicator::make_grid_communicator() representing a grid communicato...
Definition alltoall_grid.hpp:144
GridCommunicator(kamping::Communicator< DefaultContainerType, Plugins... > const &comm)
Creates a two dimensional grid by splitting the given communicator of size p into a row and a column ...
Definition alltoall_grid.hpp:156
auto alltoallv(Args... args) const
Indirect two dimensional grid based personalized alltoall exchange. The following parameters are requ...
Definition alltoall_grid.hpp:267
auto alltoallv_with_envelope(Args... args) const
Indirect two dimensional grid based personalized alltoall exchange. The following parameters are requ...
Definition alltoall_grid.hpp:208
kamping::Communicator< DefaultContainerType > LevelCommunicator
Type of row and column communicator.
Definition alltoall_grid.hpp:146
Wrapper for MPI functions that don't require a communicator.
constexpr int light
Assertion level for lightweight assertions.
Definition assertion_levels.hpp:13
auto alltoallv(Args... args) const
Wrapper for MPI_Alltoallv.
Definition alltoall.hpp:335
static constexpr auto alloc_new
Convenience wrapper for creating library allocated containers. See AllocNewT for details.
Definition data_buffer.hpp:194
auto destination(int rank)
Passes rank as destination rank to the underlying call. This parameter is needed in point-to-point ex...
Definition named_parameters.hpp:999
auto send_count(int count)
Passes count as send count to the underlying call.
Definition named_parameters.hpp:321
auto recv_counts(Container &&container)
Passes a container as recv counts to the underlying call, i.e. the container's storage must contain t...
Definition named_parameters.hpp:366
auto recv_buf(Container &&container)
Passes a container, into which the received elements will be written, to the underlying call....
Definition named_parameters.hpp:859
auto send_buf(internal::ignore_t< Data > ignore)
Generates a dummy send buf that wraps a nullptr.
Definition named_parameters.hpp:51
auto recv_counts_out()
Indicates to construct a container with type kamping::Communicator::default_container_type<int>,...
Definition named_parameters.hpp:478
auto recv_displs_out()
Indicates to construct a container with type kamping::Communicator::default_container_type<int>,...
Definition named_parameters.hpp:802
auto send_counts(Container &&container)
Passes a container as send counts to the underlying call, i.e. the container's storage must contain t...
Definition named_parameters.hpp:203
auto recv_displs(Container &&container)
Passes a container as receive displacements to the underlying call, i.e. the container's storage must...
Definition named_parameters.hpp:697
auto send_displs_out()
Indicates to construct a container with type kamping::Communicator::default_container_type<int>,...
Definition named_parameters.hpp:679
auto send_displs(Container &&container)
Passes a container as send displacements to the underlying call, i.e. the container's storage must co...
Definition named_parameters.hpp:574
#define KAMPING_REQUIRED_PARAMETERS(...)
Wrapper to pass (possibly empty) list of parameter type names as required parameters to KAMPING_CHECK...
Definition named_parameter_check.hpp:52
#define KAMPING_OPTIONAL_PARAMETERS(...)
Wrapper to pass (possibly empty) list of parameter type names as optional parameters to KAMPING_CHECK...
Definition named_parameter_check.hpp:58
#define KAMPING_CHECK_PARAMETERS(args, required, optional)
Assertion macro that checks if passed parameters are correct, i.e., all parameter types are unique,...
Definition named_parameter_check.hpp:80
auto make_mpi_result(Buffers &&... buffers)
Construct result object for a wrapped MPI call. Four different cases are handled: a) The recv_buffer ...
Definition result.hpp:1017
static constexpr bool has_to_be_computed
Checks if the buffer has to be computed by kamping, i.e. if it is an output parameter or the buffer h...
Definition named_parameter_check.hpp:398
STL namespace.
Helper type for representing a type list.
Definition parameter_objects.hpp:326
Helper class for using CRTP for mixins. Which are used to implement kamping plugins.
Definition plugin_helpers.hpp:32
Mixin for MessageEnvelope to store a destination PE.
Definition alltoall_grid.hpp:58
size_t get_destination() const
Get destination PE.
Definition alltoall_grid.hpp:60
int get_destination_signed() const
Get destination PE.
Definition alltoall_grid.hpp:65
int destination
Rank of destination PE.
Definition alltoall_grid.hpp:73
void set_destination(int value)
Set destination PE.
Definition alltoall_grid.hpp:70
Class representing a position within a logical two-dimensional processor grid.
Definition alltoall_grid.hpp:131
size_t col_index
Column position.
Definition alltoall_grid.hpp:133
size_t row_index
Row position.
Definition alltoall_grid.hpp:132
Augments a plain message with additional information via.
Definition alltoall_grid.hpp:80
static constexpr bool has_source_information
Definition alltoall_grid.hpp:82
MessageEnvelope(PayloadType payload)
Constructor for wrapping a message.
Definition alltoall_grid.hpp:92
static constexpr bool has_destination_information
Definition alltoall_grid.hpp:85
Payload & get_payload()
Return reference to payload.
Definition alltoall_grid.hpp:95
Payload _payload
payload
Definition alltoall_grid.hpp:117
friend std::ostream & operator<<(std::ostream &out, MessageEnvelope const &msg)
Output operator.
Definition alltoall_grid.hpp:105
Payload const & get_payload() const
Return const reference to payload.
Definition alltoall_grid.hpp:100
Mixin for MessageEnvelope to store a source PE.
Definition alltoall_grid.hpp:39
size_t get_source() const
Get destination PE.
Definition alltoall_grid.hpp:41
int source
Rank of source PE.
Definition alltoall_grid.hpp:54
int get_source_signed() const
Get destination PE.
Definition alltoall_grid.hpp:46
void set_source(int value)
Set destination PE.
Definition alltoall_grid.hpp:51