KaMPIng 0.1.0
(Near) zero-overhead C++ MPI bindings.
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 If the given type T is an rvalue reference,i.e. T = U&&, the type alias refers to U. Otherwise the type alias
58/// refers to T (which possibly can be an lvalue reference).
59/// @tparam T Type for which a possible rvalue reference is removed.
60template <typename T>
61using remove_rvalue_reference_t = std::conditional_t<std::is_rvalue_reference_v<T>, std::remove_reference_t<T>, T>;
62
63/// @brief Deduce the MPI_Datatype to use on the send and recv side.
64/// If \ref kamping::send_type() is given, the \c MPI_Datatype wrapped inside will be used as send_type. Otherwise, the
65/// \c MPI_datatype is derived automatically based on send_buf's underlying \c value_type.
66///
67/// If \ref kamping::recv_type()
68/// is given, the \c MPI_Datatype wrapped inside will be used as recv_type. Otherwise, the \c MPI_datatype is derived
69/// automatically based on recv_buf's underlying \c value_type.
70///
71/// @tparam send_value_type Value type of the send buffer.
72/// @tparam recv_value_type Value type of the recv buffer.
73/// @tparam recv_buf Type of the recv buffer.
74/// @tparam Args Types of all arguments passed to the wrapped MPI call.
75/// @param args All arguments passed to a wrapped MPI call.
76/// @return Return a tuple containing the \c MPI send_type wrapped in a DataBuffer, the \c MPI recv_type wrapped in a
77/// DataBuffer.
78template <typename send_value_type, typename recv_value_type, typename recv_buf, typename... Args>
79constexpr auto determine_mpi_datatypes(Args&... args) {
80 // Some assertions:
81 // If send/recv types are given, the corresponding count information has to be provided, too.
84 if constexpr (is_send_type_given_as_in_param) {
85 constexpr bool is_send_count_info_given =
89 static_assert(
91 "If a custom send type is provided, send count(s) have to be provided, too."
92 );
93 }
94 if constexpr (is_recv_type_given_as_in_param) {
95 constexpr bool is_recv_count_info_given =
99 static_assert(
101 "If a custom recv type is provided, send count(s) have to be provided, too."
102 );
103 }
104 // Recv buffer resize policy assertion
105 constexpr bool do_not_resize_recv_buf = std::remove_reference_t<recv_buf>::resize_policy == no_resize;
106 static_assert(
108 "If a custom recv type is given, kamping is not able to deduce the correct size of the recv buffer. "
109 "Therefore, a sufficiently large recv buffer (with resize policy \"no_resize\") must be provided by the user."
110 );
111
112 // Get the send/recv types
115
116 auto&& mpi_send_type =
117 internal::select_parameter_type_or_default<internal::ParameterType::send_type, default_mpi_send_type>(
118 std::make_tuple(),
119 args...
120 )
121 .construct_buffer_or_rebind();
122 if constexpr (!is_send_type_given_as_in_param) {
123 if constexpr (std::is_same_v<send_value_type, unused_tparam>) {
124 mpi_send_type.underlying() = MPI_DATATYPE_NULL;
125 } else {
127 }
128 }
129
130 auto&& mpi_recv_type =
131 internal::select_parameter_type_or_default<internal::ParameterType::recv_type, default_mpi_recv_type>(
132 std::make_tuple(),
133 args...
134 )
135 .construct_buffer_or_rebind();
136 if constexpr (!is_recv_type_given_as_in_param) {
138 }
139
140 // If the send/recv types are user provided we can refer to the corresponding buffers contained in args and only
141 // need to store an lvalue reference bound to them in the return tuple. Otherwise the send/recv type buffers are
142 // constructed in this function and have to be returned by value (and therefore be non-reference members of the
143 // return tuple).
144 using ForwardingTuple = std::
146 return ForwardingTuple(
147 std::forward<decltype(mpi_send_type)>(mpi_send_type),
148 std::forward<decltype(mpi_recv_type)>(mpi_recv_type)
149 );
150}
151
152/// @brief Deduce the MPI_Datatype to use as send_recv_type in a collective operation which accepts only one parameter
153/// of MPI_Datatype instead of (possibly) distinct send and recv types. If \ref kamping::send_recv_type() is given, the
154/// \c MPI_Datatype wrapped inside will be used as send_recv_type. Otherwise, the \c MPI_datatype is derived
155/// automatically based on send_buf's underlying \c value_type.
156///
157/// @tparam send_or_send_recv_value_type Value type of the send(_recv) buffer.
158/// @tparam recv_buf Value type of the send buffer.
159/// @tparam recv_or_send_recv_buf Type of the (send_)recv buffer.
160/// @tparam Args Types of all arguments passed to the wrapped MPI call.
161/// @param args All arguments passed to a wrapped MPI call.
162/// @return Return the \c MPI send_type wrapped in a DataBuffer. This is either an lvalue reference to the
163/// send_recv_type DataBuffer if the send_recv_type is provided by the user or a newly created send_recv_type DataBuffer
164/// otherwise.
165template <typename send_or_send_recv_value_type, typename recv_or_send_recv_buf, typename... Args>
169 decltype(kamping::send_recv_type_out())>(std::make_tuple(), args...)
170 .construct_buffer_or_rebind()) {
171 // Some assertions:
172 // If a send_recv type is given, the corresponding count information has to be provided, too.
176 constexpr bool is_send_recv_count_given =
178 static_assert(
180 "If a custom send_recv type is provided, the send_recv count has to be provided, too."
181 );
182 }
183 // Recv buffer resize policy assertion
184 constexpr bool do_not_resize_recv_buf = std::remove_reference_t<recv_or_send_recv_buf>::resize_policy == no_resize;
185 static_assert(
187 "If a custom send_recv type is given, kamping is not able to deduce the correct size of the "
188 "recv/send_recv buffer. "
189 "Therefore, a sufficiently large recv/send_recv buffer (with resize policy \"no_resize\") must be provided by "
190 "the user."
191 );
192
193 // Get the send_recv type
195
196 // decltype(auto) becomes an lvalue reference type if the initializer is an lvalue and a non-reference type if the
197 // the initializer is a pr-value (e.g. a function call returning by value). These are the only two value categories
198 // we accept for the return value of select_parameter_type_or_default.
199 decltype(auto) mpi_send_recv_type =
200 internal::select_parameter_type_or_default<internal::ParameterType::send_recv_type, default_mpi_send_recv_type>(
201 std::make_tuple(),
202 args...
203 )
204 .construct_buffer_or_rebind();
205
206 // assure that our expectation about the return value value category (lvalue or pr-value) is true. This ensures
207 // that the return value of the function does not become a dangling rvalue reference bound to a function-local
208 // object.
209 static_assert(
210 !std::is_rvalue_reference_v<decltype(mpi_send_recv_type)>,
211 "mpi_send_type is either a lvalue reference (in this case it returned by reference), or a non-reference type "
212 "(in "
213 "this case it is returned by value)."
214 );
215
218 }
219
220 return mpi_send_recv_type;
221}
222
223} // 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:270
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:1252
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:1297
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:1209
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:166
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
std::conditional_t< std::is_rvalue_reference_v< T >, std::remove_reference_t< T >, T > remove_rvalue_reference_t
If the given type T is an rvalue reference,i.e. T = U&&, the type alias refers to U....
Definition collectives_helpers.hpp:61
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:79