KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
recv.hpp
1// This file is part of KaMPIng.
2//
3// Copyright 2022-2024 The KaMPIng Authors
4//
5// KaMPIng is free software : you can redistribute it and/or modify it under the
6// terms of the GNU Lesser General Public License as published by the Free
7// Software Foundation, either version 3 of the License, or (at your option) any
8// later version. KaMPIng is distributed in the hope that it will be useful, but
9// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11// for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with KaMPIng. If not, see <https://www.gnu.org/licenses/>.
15
16#pragma once
17
18#include <type_traits>
19#include <utility>
20
21#include <kassert/kassert.hpp>
22#include <mpi.h>
23
24#include "kamping/communicator.hpp"
27#include "kamping/implementation_helpers.hpp"
33#include "kamping/p2p/helpers.hpp"
34#include "kamping/p2p/probe.hpp"
36#include "kamping/result.hpp"
37#include "kamping/status.hpp"
38
39///// @addtogroup kamping_p2p
40/// @{
41
42// @brief Wrapper for \c MPI_Recv.
43///
44/// This wraps \c MPI_Recv. This operation performs a standard blocking receive.
45/// If the \ref kamping::recv_counts() parameter is not specified, this first performs a probe, followed by a receive of
46/// the probed message with the probed message size.
47///
48/// The following parameter is optional, but leads to an additional call to \c MPI_Probe if not present:
49/// - \ref kamping::recv_count() the number of elements to receive. Will be probed before receiving if not given.
50///
51/// The following parameters are optional:
52/// - \ref kamping::recv_buf() the buffer to receive the message into. The buffer's underlying
53/// storage must be large enough to hold all received elements. If no \ref kamping::recv_buf() is provided, the \c
54/// value_type of the recv buffer has to be passed as a template parameter to \c recv().
55///
56// - \ref kamping::recv_type() specifying the \c MPI datatype to use as recv type. If omitted, the \c MPI datatype is
57/// derived automatically based on recv_buf's underlying \c value_type.
58///
59/// - \ref kamping::source() receive a message sent from this source rank. Defaults to probing for an arbitrary source,
60/// i.e. \c source(rank::any).
61///
62/// - \ref kamping::tag() recv message with this tag. Defaults to receiving for an arbitrary tag, i.e. \c
63/// tag(tags::any).
64///
65/// - \c kamping::status(ignore<>) or \ref kamping::status_out(). Returns info about the received message by setting the
66/// appropriate fields in the status object passed by the user. If \ref kamping::status_out() is passed, constructs a
67/// status object which may be retrieved by the user. The status can be ignored by passing \c
68/// kamping::status(kamping::ignore<>). This is the default.
69///
70/// @tparam Args Automatically deduced template parameters.
71/// @param args All required and any number of the optional parameters described above.
72/// @return Result object wrapping the output parameters to be returned by value.
73///
74/// @see \ref docs/parameter_handling.md for general information about parameter handling in KaMPIng.
75/// <hr>
76/// \include{doc} docs/resize_policy.dox
77template <
78 template <typename...>
79 typename DefaultContainerType,
80 template <typename, template <typename...> typename>
81 typename... Plugins>
82template <typename recv_value_type_tparam /* = kamping::internal::unused_tparam */, typename... Args>
84 using namespace kamping::internal;
86 Args,
89 );
91 auto&& recv_buf =
92 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
93 std::tuple(),
94 args...
95 )
98 if constexpr (is_serialization_used) {
101 }
102 using recv_value_type = typename std::remove_reference_t<decltype(recv_buf)>::value_type;
103 static_assert(
104 !std::is_same_v<recv_value_type, internal::unused_tparam>,
105 "No recv_buf parameter provided and no receive value given as template parameter. One of these is required."
106 );
107
108 auto&& recv_type = internal::determine_mpi_recv_datatype<recv_value_type, decltype(recv_buf)>(args...);
110
111 using default_source_buf_type = decltype(kamping::source(rank::any));
112
113 auto&& source_param =
114 internal::select_parameter_type_or_default<internal::ParameterType::source, default_source_buf_type>(
115 {},
116 args...
117 );
118
119 using default_tag_buf_type = decltype(kamping::tag(tags::any));
120
121 auto&& tag_param =
122 internal::select_parameter_type_or_default<internal::ParameterType::tag, default_tag_buf_type>({}, args...);
123
124 constexpr auto tag_type = std::remove_reference_t<decltype(tag_param)>::tag_type;
125 if constexpr (tag_type == internal::TagType::value) {
126 int tag = tag_param.tag();
127 KASSERT(
129 "invalid tag " << tag << ", must be in range [0, " << Environment<>::tag_upper_bound() << "]"
130 );
131 }
132
134
135 auto&& status =
136 internal::select_parameter_type_or_default<internal::ParameterType::status, default_status_param_type>(
137 {},
138 args...
139 )
140 .construct_buffer_or_rebind();
141
142 // Get the optional recv_count parameter. If the parameter is not given,
143 // allocate a new container.
145 auto&& recv_count_param =
146 internal::select_parameter_type_or_default<internal::ParameterType::recv_count, default_recv_count_type>(
147 std::tuple(),
148 args...
149 )
150 .construct_buffer_or_rebind();
151
153 int source = source_param.rank_signed();
154 int tag = tag_param.tag();
155 if constexpr (internal::has_to_be_computed<decltype(recv_count_param)>) {
156 Status probe_status = this->probe(source_param.clone(), tag_param.clone(), status_out()).extract_status();
157 source = probe_status.source_signed();
158 tag = probe_status.tag();
159 recv_count_param.underlying() = asserting_cast<int>(probe_status.count(recv_type.get_single_element()));
160 }
161
162 // Ensure that we do not touch the recv buffer if MPI_PROC_NULL is passed,
163 // because this is what the standard guarantees.
164 if constexpr (std::remove_reference_t<decltype(source_param)>::rank_type != internal::RankType::null) {
166 return asserting_cast<size_t>(recv_count_param.get_single_element());
167 };
168 recv_buf.resize_if_requested(compute_required_recv_buf_size);
169 KASSERT(
170 // if the recv type is user provided, kamping cannot make any assumptions about the required size of the
171 // recv buffer
173 "Recv buffer is not large enough to hold all received elements.",
175 );
176 }
177
178 [[maybe_unused]] int err = MPI_Recv(
179 recv_buf.data(), // buf
180 recv_count_param.get_single_element(), // count
181 recv_type.get_single_element(), // datatype
182 source, // source
183 tag, // tag
184 this->mpi_communicator(), // comm
186 );
187 this->mpi_error_hook(err, "MPI_Recv");
188
189 return internal::make_mpi_result<std::tuple<Args...>>(
191 std::move(recv_count_param),
192 std::move(status),
193 std::move(recv_type)
194 );
195}
196
197/// @brief Convience wrapper for receiving single values via \c MPI_Recv.
198///
199/// This wraps \c MPI_Recv. This operation performs a standard blocking receive with a receive count of 1 and returns
200/// the received value.
201///
202/// The following parameters are optional:
203/// - \ref kamping::source() receive a message sent from this source rank. Defaults to
204/// <code>kamping::source(kamping::rank::any)</code>.
205/// - \ref kamping::tag() recv message with this tag. Defaults to receiving for an arbitrary tag, i.e.
206/// <code>tag(tags::any)</code>.
207/// - \ref kamping::status() Returns info about the received message by setting the appropriate fields in the status
208/// object passed by the user. The status can be ignored by passing \c kamping::status(kamping::ignore<>). This is the
209/// default.
210///
211/// @tparam recv_value_type_tparam The type of the message to be received.
212/// @tparam Args Automatically deduced template parameters.
213/// @param args All required and any number of the optional buffers described above.
214/// @return The received value of type \c recv_value_type_tparam.
215template <
216 template <typename...>
217 typename DefaultContainerType,
218 template <typename, template <typename...> typename>
219 typename... Plugins>
220template <typename recv_value_type_tparam, typename... Args>
223
224 using default_source_buf_type = decltype(kamping::source(rank::any));
225 using source_param_type = std::remove_reference_t<decltype(internal::select_parameter_type_or_default<
227 default_source_buf_type>({}, args...))>;
228 static_assert(
229 source_param_type::rank_type != internal::RankType::null,
230 "You cannot receive an element from source kamping::rank::null."
231 );
232
234 using status_param_type = std::remove_reference_t<decltype(internal::select_parameter_type_or_default<
237 static_assert(
238 !internal::is_extractable<status_param_type>,
239 "KaMPIng cannot allocate a status object for you here, because we have no way of returning it. Pass a "
240 "reference to a status object instead."
241 );
242 return recv(recv_count(1), recv_buf(alloc_new<recv_value_type_tparam>), std::forward<Args>(args)...);
243}
244/// @}
Wrapper for MPI functions that don't require a communicator. If the template parameter init_finalize_...
Definition environment.hpp:52
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
T value_type
The value type.
Definition allocator.hpp:53
Wrapper for MPI_Status.
Definition status.hpp:28
Code for error handling.
constexpr int light
Assertion level for lightweight assertions.
Definition assertion_levels.hpp:13
auto status_out()
Constructs a status object internally, which may then be retrieved from kamping::MPIResult returned b...
Definition status_parameters.hpp:43
auto status(internal::ignore_t< void >)
pass MPI_STATUS_IGNORE to the underlying MPI call.
Definition status_parameters.hpp:52
static constexpr auto alloc_new
Convenience wrapper for creating library allocated containers. See AllocNewT for details.
Definition data_buffer.hpp:194
auto tag(internal::any_tag_t)
Indicates to use MPI_ANY_TAG as tag in the underlying call.
Definition named_parameters.hpp:1064
auto source(int rank)
Passes rank as source rank to the underlying call. This parameter is needed in point-to-point exchang...
Definition named_parameters.hpp:1028
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 recv_count(int count)
Passes count as recv count to the underlying call.
Definition named_parameters.hpp:490
auto recv_type(MPI_Datatype recv_type)
Passes recv_type as recv type to the underlying call.
Definition named_parameters.hpp:1238
auto recv_count_out()
Indicates to deduce the recv count and return it to the caller as part of the underlying call's resul...
Definition named_parameters.hpp:516
auto recv(Args... args) const
Definition recv.hpp:83
auto recv_single(Args... args) const
Convience wrapper for receiving single values via MPI_Recv.
Definition recv.hpp:221
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
@ source
Tag used to represent the sending PE in a MPI call.
@ status
Tag used to represent the status in a MPI call.
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.
#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
Template magic to implement named parameters in cpp.
File containing the parameter types used by the KaMPIng library.
Factory methods for buffer wrappers.
Internal namespace marking the code that is not user-facing.
Definition collectives_helpers.hpp:20
static constexpr bool buffer_uses_serialization
Checks if DataBufferType is a serialization buffer.
Definition named_parameter_check.hpp:415
@ value
holds an actual value
@ null
holds MPI_PROC_NULL
constexpr bool is_valid_rank_in_comm(RankDataBufferClass const &rank_data_buffer, Comm const &comm, bool const allow_null=false, bool const allow_any=false)
Checks whether a RankDataBuffer contains a valid rank in the given communicator.
Definition implementation_helpers.hpp:30
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
static MPI_Status * status_param_to_native_ptr(StatusParam &param)
returns a pointer to the MPI_Status encapsulated by the provided status parameter object.
Definition parameter_objects.hpp:489
Parameter objects return by named parameter factory functions.
Some functions and types simplifying/enabling the development of wrapped MPI calls in KaMPIng.