KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
collectives_helpers.hpp
1// This file is part of KaMPIng.
2//
3// Copyright 2023 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#pragma once
15
19
21/// @brief Compute the required size of the recv buffer in vectorized communication (i.e. \c MPI operation that take a
22/// receive displacements). If recv displs are provided by the user the required size is the sum of the last entries of
23/// the recv_counts and the recv_displs buffers. Otherwise we have to compute the elementwise maximum of both buffers to
24/// obtain a minimum required recv buf size.
25///
26/// @tparam RecvCounts Type of the recv counts buffer.
27/// @tparam RecvDispls Type of the recv displs buffer.
28/// @param recv_counts Recv counts buffer.
29/// @param recv_displs Recv displs buffer.
30/// @param comm_size Size of the communicator.
31/// @return Required size of the recv buffer.
32template <typename RecvCounts, typename RecvDispls>
35) {
36 constexpr bool do_calculate_recv_displs = internal::has_to_be_computed<RecvDispls>;
37 if constexpr (do_calculate_recv_displs) {
38 // If recv displs are not provided as a parameter, they are monotonically increasing. In this case, it is
39 // safe to deduce the required recv_buf size by only considering the last entry of recv_counts and
40 // recv_displs.
41 int recv_buf_size = *(recv_counts.data() + comm_size - 1) + // Last element of recv_counts
42 *(recv_displs.data() + comm_size - 1); // Last element of recv_displs
44 } else {
45 // If recv displs are user provided, they do not need to be monotonically increasing. Therefore, we have to
46 // compute the maximum of recv_displs and recv_counts from each rank to provide a receive buffer large
47 // enough to be able to receive all elements. This O(p) computation is only executed if the user wants
48 // kamping to resize the receive buffer.
49 int recv_buf_size = 0;
50 for (size_t i = 0; i < comm_size; ++i) {
51 recv_buf_size = std::max(recv_buf_size, *(recv_counts.data() + i) + *(recv_displs.data() + i));
52 }
54 }
55}
56
57/// @brief Deduce the MPI_Datatype to use on the send and recv side.
58/// If \ref kamping::send_type() is given, the \c MPI_Datatype wrapped inside will be used as send_type. Otherwise, the
59/// \c MPI_datatype is derived automatically based on send_buf's underlying \c value_type.
60///
61/// If \ref kamping::recv_type()
62/// is given, the \c MPI_Datatype wrapped inside will be used as recv_type. Otherwise, the \c MPI_datatype is derived
63/// automatically based on recv_buf's underlying \c value_type.
64///
65/// @tparam send_value_type Value type of the send buffer.
66/// @tparam recv_value_type Value type of the recv buffer.
67/// @tparam recv_buf Type of the recv buffer.
68/// @tparam Args Types of all arguments passed to the wrapped MPI call.
69/// @param args All arguments passed to a wrapped MPI call.
70/// @return Return a tuple containing the \c MPI send_type wrapped in a DataBuffer, the \c MPI recv_type wrapped in a
71/// DataBuffer.
72template <typename send_value_type, typename recv_value_type, typename recv_buf, typename... Args>
73constexpr auto determine_mpi_datatypes(Args&... args) {
74 // Some assertions:
75 // If send/recv types are given, the corresponding count information has to be provided, too.
78 if constexpr (is_send_type_given_as_in_param) {
79 constexpr bool is_send_count_info_given =
83 static_assert(
85 "If a custom send type is provided, send count(s) have to be provided, too."
86 );
87 }
88 if constexpr (is_recv_type_given_as_in_param) {
89 constexpr bool is_recv_count_info_given =
93 static_assert(
95 "If a custom recv type is provided, send count(s) have to be provided, too."
96 );
97 }
98 // Recv buffer resize policy assertion
99 constexpr bool do_not_resize_recv_buf = std::remove_reference_t<recv_buf>::resize_policy == no_resize;
100 static_assert(
102 "If a custom recv type is given, kamping is not able to deduce the correct size of the recv buffer. "
103 "Therefore, a sufficiently large recv buffer (with resize policy \"no_resize\") must be provided by the user."
104 );
105
106 // Get the send/recv types
109
110 auto mpi_send_type =
111 internal::select_parameter_type_or_default<internal::ParameterType::send_type, default_mpi_send_type>(
112 std::make_tuple(),
113 args...
114 )
115 .construct_buffer_or_rebind();
116 if constexpr (!is_send_type_given_as_in_param) {
117 if constexpr (std::is_same_v<send_value_type, unused_tparam>) {
118 mpi_send_type.underlying() = MPI_DATATYPE_NULL;
119 } else {
121 }
122 }
123
124 auto mpi_recv_type =
125 internal::select_parameter_type_or_default<internal::ParameterType::recv_type, default_mpi_recv_type>(
126 std::make_tuple(),
127 args...
128 )
129 .construct_buffer_or_rebind();
130 if constexpr (!is_recv_type_given_as_in_param) {
132 }
133
134 return std::tuple{std::move(mpi_send_type), std::move(mpi_recv_type)};
135}
136
137/// @brief Deduce the MPI_Datatype to use as send_recv_type in a collective operation which accepts only one parameter
138/// of MPI_Datatype instead of (possibly) distinct send and recv types. If \ref kamping::send_recv_type() is given, the
139/// \c MPI_Datatype wrapped inside will be used as send_recv_type. Otherwise, the \c MPI_datatype is derived
140/// automatically based on send_buf's underlying \c value_type.
141///
142/// @tparam send_or_send_recv_value_type Value type of the send(_recv) buffer.
143/// @tparam recv_buf Value type of the send buffer.
144/// @tparam recv_or_send_recv_buf Type of the (send_)recv buffer.
145/// @tparam Args Types of all arguments passed to the wrapped MPI call.
146/// @param args All arguments passed to a wrapped MPI call.
147/// @return Return the \c MPI send_type wrapped in a DataBuffer. This is either an lvalue reference to the
148/// send_recv_type DataBuffer if the send_recv_type is provided by the user or a newly created send_recv_type DataBuffer
149/// otherwise.
150template <typename send_or_send_recv_value_type, typename recv_or_send_recv_buf, typename... Args>
154 decltype(kamping::send_recv_type_out())>(std::make_tuple(), args...)
155 .construct_buffer_or_rebind()) {
156 // Some assertions:
157 // If a send_recv type is given, the corresponding count information has to be provided, too.
161 constexpr bool is_send_recv_count_given =
163 static_assert(
165 "If a custom send_recv type is provided, the send_recv count has to be provided, too."
166 );
167 }
168 // Recv buffer resize policy assertion
169 constexpr bool do_not_resize_recv_buf = std::remove_reference_t<recv_or_send_recv_buf>::resize_policy == no_resize;
170 static_assert(
172 "If a custom send_recv type is given, kamping is not able to deduce the correct size of the "
173 "recv/send_recv buffer. "
174 "Therefore, a sufficiently large recv/send_recv buffer (with resize policy \"no_resize\") must be provided by "
175 "the user."
176 );
177
178 // Get the send_recv type
180
181 auto mpi_send_recv_type =
182 internal::select_parameter_type_or_default<internal::ParameterType::send_recv_type, default_mpi_send_recv_type>(
183 std::make_tuple(),
184 args...
185 )
186 .construct_buffer_or_rebind();
187
188 // assure that our expectation about the return value value category (lvalue or pr-value) is true. This ensures
189 // that the return value of the function does not become a dangling rvalue reference bound to a function-local
190 // object.
191 static_assert(
192 !std::is_rvalue_reference_v<decltype(mpi_send_recv_type)>,
193 "mpi_send_type is either a lvalue reference (in this case it returned by reference), or a non-reference type "
194 "(in "
195 "this case it is returned by value)."
196 );
197
200 }
201
202 return mpi_send_recv_type;
203}
204
205} // namespace kamping::internal
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
constexpr BufferResizePolicy no_resize
Definition data_buffer.hpp:299
auto send_recv_type_out()
Indicates to deduce the send/recv type in the underlying call and return it as part of underlying cal...
Definition named_parameters.hpp:1361
auto send_type_out()
Indicates to deduce the send type in the underlying call and return it as part of underlying call's r...
Definition named_parameters.hpp:1273
auto recv_type_out()
Indicates to deduce the receive type in the underlying call and return it as part of underlying call'...
Definition named_parameters.hpp:1316
decltype(auto) select_parameter_type_or_default(std::tuple< DefaultArguments... > default_arguments, Args &... args)
Checks if parameter with requested parameter type exists, if not constructs a default value.
Definition named_parameter_selection.hpp:239
@ recv_count
Tag used to represent the number of elements to be received.
@ recv_type
Tag used to represent a recv type in an MPI call.
@ send_type
Tag used to represent a send type in an MPI call.
@ send_count
Tag used to represent the number of elements to be sent.
Utility that maps C++ types to types that can be understood by MPI.
Template magic to check named parameters passed to wrappers at compile time.
Factory methods for buffer wrappers.
Internal namespace marking the code that is not user-facing.
Definition collectives_helpers.hpp:20
constexpr auto determine_mpi_send_recv_datatype(Args &... args) -> decltype(internal::select_parameter_type_or_default< internal::ParameterType::send_recv_type, decltype(kamping::send_recv_type_out())>(std::make_tuple(), args...) .construct_buffer_or_rebind())
Deduce the MPI_Datatype to use as send_recv_type in a collective operation which accepts only one par...
Definition collectives_helpers.hpp:151
static constexpr bool is_parameter_given_as_in_buffer
Checks if a data buffer with requested parameter type exists and it is an input parameter (i....
Definition named_parameter_check.hpp:384
size_t compute_required_recv_buf_size_in_vectorized_communication(RecvCounts const &recv_counts, RecvDispls const &recv_displs, size_t comm_size)
Compute the required size of the recv buffer in vectorized communication (i.e. MPI operation that tak...
Definition collectives_helpers.hpp:33
constexpr auto determine_mpi_datatypes(Args &... args)
Deduce the MPI_Datatype to use on the send and recv side. If kamping::send_type() is given,...
Definition collectives_helpers.hpp:73