20#include "kamping/collectives/alltoall.hpp"
21#include "kamping/communicator.hpp"
23#include "kamping/plugin/plugin_helpers.hpp"
27namespace kamping::plugin {
36namespace grid_plugin_helpers {
79template <
typename PayloadType,
typename... Attributes>
106 out <<
"(payload: " <<
msg.get_payload();
108 out <<
", source: " <<
msg.get_source();
111 out <<
", destination: " <<
msg.get_destination();
121template <MessageEnvelopeLevel level,
typename T>
123 level == MessageEnvelopeLevel::no_envelope,
126 level == MessageEnvelopeLevel::source,
154 template <
typename,
template <
typename...>
typename>
157 : _size_of_orig_comm{
comm.size()},
158 _rank_in_orig_comm{
comm.rank()} {
159 double const sqrt = std::sqrt(
comm.size());
161 size_t const ceil_sqrt =
static_cast<size_t>(std::ceil(
sqrt));
168 auto [
row,
col] = pos_in_complete_grid(
comm.rank());
170 if (
comm.rank() >= _size_complete_rectangle) {
171 row =
comm.rank() % _num_columns;
216 internal::select_parameter_type<internal::ParameterType::send_buf>(
args...).construct_buffer_or_rebind();
218 auto const&
send_counts = internal::select_parameter_type<internal::ParameterType::send_counts>(
args...)
223 internal::select_parameter_type_or_default<internal::ParameterType::send_displs, default_send_displs_type>(
231 send_displs.resize_if_requested([&]() {
return _size_of_orig_comm; });
266 template <
typename...
Args>
275 auto&
send_buf = internal::select_parameter_type<internal::ParameterType::send_buf>(
args...);
279 auto const&
send_counts = internal::select_parameter_type<internal::ParameterType::send_counts>(
args...)
284 internal::select_parameter_type_or_default<internal::ParameterType::send_displs, default_send_displs_type>(
292 send_displs.resize_if_requested([&]() {
return _size_of_orig_comm; });
307 internal::select_parameter_type_or_default<internal::ParameterType::recv_counts, default_recv_counts_type>(
315 recv_counts.resize_if_requested([&]() {
return _size_of_orig_comm; });
330 internal::select_parameter_type_or_default<internal::ParameterType::recv_displs, default_recv_displs_type>(
338 recv_displs.resize_if_requested([&]() {
return _size_of_orig_comm; });
349 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
366 template <
typename Gr
idRecvBuffer,
typename RecvBuffer,
typename RecvCounts,
typename RecvDispls>
367 void write_recv_buffer(
383 "Recv buffer is not large enough to hold all received elements.",
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);
399 size_t const destination_pe = get_destination_in_rowwise_exchange(i);
400 row_send_counts.data()[destination_pe] +=
send_counts.data()[i];
402 return row_send_counts;
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};
409 [[nodiscard]]
size_t get_destination_in_rowwise_exchange(
size_t destination_rank)
const {
410 return pos_in_complete_grid(destination_rank).
col_index;
413 [[nodiscard]]
size_t get_destination_in_colwise_exchange(
size_t destination_rank)
const {
414 return pos_in_complete_grid(destination_rank).
row_index;
417 template <MessageEnvelopeLevel envelope_level,
typename SendBuffer,
typename SendCounts,
typename SendDispls>
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());
426 row_send_counts_span.begin(),
427 row_send_counts_span.end(),
428 row_send_displs_span.begin(),
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());
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);
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));
457 if constexpr (envelope_level != MessageEnvelopeLevel::no_envelope) {
458 entry.set_source(asserting_cast<int>(_rank_in_orig_comm));
471 template <
typename...>
472 typename RowwiseRecvBuf,
473 typename... EnvelopeArgs>
474 auto columnwise_exchange(RowwiseRecvBuf<grid_plugin_helpers::MessageEnvelope<EnvelopeArgs...>>&& rowwise_recv_buf
476 using namespace grid_plugin_helpers;
477 using IndirectMessageType = MessageEnvelope<EnvelopeArgs...>;
478 using Payload =
typename IndirectMessageType::Payload;
481 for (
auto const& elem: rowwise_recv_buf) {
482 ++
send_counts[get_destination_in_colwise_exchange(elem.get_destination())];
484 DefaultContainerType<int> send_offsets =
send_counts;
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;
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) {
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());
505 envelope_level == MessageEnvelopeLevel::source_and_destination ,
506 "This branch is never used"
512 rowwise_recv_buf.clear();
513 auto tmp = std::move(rowwise_recv_buf);
523 size_t _size_of_orig_comm;
524 size_t _rank_in_orig_comm;
525 size_t _size_complete_rectangle;
548template <
typename Comm,
template <
typename...>
typename DefaultContainerType>
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
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
MessageEnvelope()=default
Default constructor.
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