KaMPIng 0.1.0
(Near) zero-overhead C++ MPI bindings.
Loading...
Searching...
No Matches
irecv.hpp
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
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/request.hpp"
37#include "kamping/result.hpp"
38#include "kamping/status.hpp"
39
40//// @addtogroup kamping_p2p
41/// @{
42
43// @brief Wrapper for \c MPI_Recv.
44///
45/// This wraps \c MPI_Irecv. This operation performs a standard non-blocking receive.
46/// If the \ref kamping::recv_counts() parameter is not specified, this first performs a (blocking) probe, followed by a
47/// (non-blocking) receive of the probed message with the probed message size.
48/// The call is associated with a \ref kamping::Request (either allocated by KaMPIng or provided by the user). Before
49/// accessing the result the user has to complete the request.
50///
51/// The following parameters are optional:
52/// - \ref kamping::recv_buf() the buffer to receive the message into.
53/// If no \ref kamping::recv_buf() is provided, the \c value_type of the recv
54/// buffer has to be passed as a template parameter to \c recv().
55///
56/// - \ref kamping::tag() recv message with this tag. Defaults to receiving for an arbitrary tag, i.e. \c
57/// tag(tags::any).
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::recv_type() specifying the \c MPI datatype to use as recv type. If omitted, the \c MPI datatype is
63/// derived automatically based on recv_buf's underlying \c value_type.
64///
65/// - \ref kamping::request() The request object to associate this operation with. Defaults to a library allocated
66/// request object, which can be access via the returned result.
67///
68/// The following parameter is optional, but leads to an additional call to \c MPI_Probe if not present:
69/// - \ref kamping::recv_count() the number of elements to receive. Will be probed before receiving if not given.
70/// Keep in mind that this introduces an additional blocking operation call.
71///
72/// @tparam Args Automatically deduced template parameters.
73/// @param args All required and any number of the optional parameters described above.
74/// @return Result object wrapping the output parameters to be returned by value.
75///
76/// @see \ref docs/parameter_handling.md for general information about parameter handling in KaMPIng.
77/// <hr>
78/// \include{doc} docs/resize_policy.dox
79template <
80 template <typename...>
81 typename DefaultContainerType,
82 template <typename, template <typename...> typename>
83 typename... Plugins>
84template <typename recv_value_type_tparam /* = kamping::internal::unused_tparam */, typename... Args>
87 Args,
90 );
92 auto&& recv_buf =
93 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
94 std::tuple(),
95 args...
96 )
98 using recv_value_type = typename std::remove_reference_t<decltype(recv_buf)>::value_type;
99 static_assert(
100 !std::is_same_v<recv_value_type, internal::unused_tparam>,
101 "No recv_buf parameter provided and no receive value given as template parameter. One of these is required."
102 );
103
104 auto&& recv_type = internal::determine_mpi_recv_datatype<recv_value_type, decltype(recv_buf)>(args...);
106
107 using default_request_param = decltype(kamping::request());
108 auto&& request_param =
109 internal::select_parameter_type_or_default<internal::ParameterType::request, default_request_param>(
110 std::tuple{},
111 args...
112 );
113
114 using default_source_buf_type = decltype(kamping::source(rank::any));
115
116 auto&& source_param =
117 internal::select_parameter_type_or_default<internal::ParameterType::source, default_source_buf_type>(
118 {},
119 args...
120 );
121
122 using default_tag_buf_type = decltype(kamping::tag(tags::any));
123
124 auto&& tag_param =
125 internal::select_parameter_type_or_default<internal::ParameterType::tag, default_tag_buf_type>({}, args...);
126
127 constexpr auto tag_type = std::remove_reference_t<decltype(tag_param)>::tag_type;
128 if constexpr (tag_type == internal::TagType::value) {
129 int tag = tag_param.tag();
130 KASSERT(
132 "invalid tag " << tag << ", must be in range [0, " << Environment<>::tag_upper_bound() << "]"
133 );
134 }
135
136 // Get the optional recv_count parameter. If the parameter is not given,
137 // allocate a new container.
139 auto&& recv_count_param =
140 internal::select_parameter_type_or_default<internal::ParameterType::recv_count, default_recv_count_type>(
141 std::tuple(),
142 args...
143 )
144 .construct_buffer_or_rebind();
145
147 int source = source_param.rank_signed();
148 int tag = tag_param.tag();
149 if constexpr (internal::has_to_be_computed<decltype(recv_count_param)>) {
150 Status probe_status = this->probe(source_param.clone(), tag_param.clone(), status_out()).extract_status();
151 source = probe_status.source_signed();
152 tag = probe_status.tag();
153 recv_count_param.underlying() = asserting_cast<int>(probe_status.count(recv_type.get_single_element()));
154 }
155
156 // Ensure that we do not touch the recv buffer if MPI_PROC_NULL is passed,
157 // because this is what the standard guarantees.
158 if constexpr (std::remove_reference_t<decltype(source_param)>::rank_type != internal::RankType::null) {
160 return asserting_cast<size_t>(recv_count_param.get_single_element());
161 };
162 recv_buf.resize_if_requested(compute_required_recv_buf_size);
163 KASSERT(
164 // if the recv type is user provided, kamping cannot make any assumptions about the required size of the
165 // recv buffer
167 "Recv buffer is not large enough to hold all received elements.",
169 );
170 }
171
172 auto result = internal::make_nonblocking_result<std::tuple<Args...>>(
173 std::move(recv_buf),
174 std::move(recv_count_param),
175 std::move(recv_type),
176 std::move(request_param)
177 );
178
179 auto recv_buf_ptr = [&] {
180 if constexpr (std::remove_reference_t<decltype(recv_buf)>::is_owning) {
181 auto& result_ = result.get_result();
182 using result_type = std::remove_reference_t<decltype(result_)>;
183 if constexpr (is_mpi_result_v<result_type>) {
184 return result_.get_recv_buffer().data();
185 } else {
186 // this branch is taken if make_result directly returns a buffer, i.e. when only the recv_buf is
187 // returned then we access the data directly
188 if constexpr (internal::has_data_member_v<decltype(result_)>) {
189 return result_.data();
190 } else {
191 // if it is a single element, we do not have .data()
192 return &result_;
193 }
194 }
195 } else {
196 return recv_buf.data();
197 }
198 };
199
200 [[maybe_unused]] int err = MPI_Irecv(
201 recv_buf_ptr(), // buf
202 recv_count_param.get_single_element(), // count
203 recv_type.get_single_element(), // datatype
204 source, // source
205 tag, // tag
206 this->mpi_communicator(), // comm
207 result.get_request_ptr() // request
208 );
209 this->mpi_error_hook(err, "MPI_Irecv");
210
211 return result;
212}
213/// @}
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
static constexpr auto alloc_new
Convenience wrapper for creating library allocated containers. See AllocNewT for details.
Definition data_buffer.hpp:170
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 request()
Internally allocate a request object and return it to the user.
Definition named_parameters.hpp:1122
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 irecv(Args... args) const
Definition irecv.hpp:85
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.
constexpr bool has_data_member_v
Boolean value helping to decide if data type has .data() method.
Definition data_buffer.hpp:248
@ 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_nonblocking_result(Args... args)
Factory for creating a kamping::NonBlockingResult.
Definition result.hpp:1121
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
Parameter objects return by named parameter factory functions.
Some functions and types simplifying/enabling the development of wrapped MPI calls in KaMPIng.