KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
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"
26#include "kamping/implementation_helpers.hpp"
31#include "kamping/p2p/helpers.hpp"
32#include "kamping/p2p/probe.hpp"
34#include "kamping/result.hpp"
35#include "kamping/status.hpp"
36
37//// @addtogroup kamping_p2p
38/// @{
39
40// @brief Wrapper for \c MPI_Recv.
41///
42/// This wraps \c MPI_Irecv. This operation performs a standard non-blocking receive.
43/// If the \ref kamping::recv_counts() parameter is not specified, this first performs a (blocking) probe, followed by a
44/// (non-blocking) receive of the probed message with the probed message size.
45/// The call is associated with a \ref kamping::Request (either allocated by KaMPIng or provided by the user). Before
46/// accessing the result the user has to complete the request.
47///
48/// The following parameters are optional:
49/// - \ref kamping::recv_buf() the buffer to receive the message into.
50/// If no \ref kamping::recv_buf() is provided, the \c value_type of the recv
51/// buffer has to be passed as a template parameter to \c recv().
52///
53/// - \ref kamping::tag() recv message with this tag. Defaults to receiving for an arbitrary tag, i.e. \c
54/// tag(tags::any).
55///
56/// - \ref kamping::source() receive a message sent from this source rank. Defaults to probing for an arbitrary source,
57/// i.e. \c source(rank::any).
58///
59// - \ref kamping::recv_type() specifying the \c MPI datatype to use as recv type. If omitted, the \c MPI datatype is
60/// derived automatically based on recv_buf's underlying \c value_type.
61///
62/// - \ref kamping::request() The request object to associate this operation with. Defaults to a library allocated
63/// request object, which can be access via the returned result.
64///
65/// The following parameter is optional, but leads to an additional call to \c MPI_Probe if not present:
66/// - \ref kamping::recv_count() the number of elements to receive. Will be probed before receiving if not given.
67/// Keep in mind that this introduces an additional blocking operation call.
68///
69/// @tparam Args Automatically deduced template parameters.
70/// @param args All required and any number of the optional parameters described above.
71/// @return Result object wrapping the output parameters to be returned by value.
72///
73/// @see \ref docs/parameter_handling.md for general information about parameter handling in KaMPIng.
74/// <hr>
75/// \include{doc} docs/resize_policy.dox
76template <
77 template <typename...>
78 typename DefaultContainerType,
79 template <typename, template <typename...> typename>
80 typename... Plugins>
81template <typename recv_value_type_tparam /* = kamping::internal::unused_tparam */, typename... Args>
84 Args,
87 );
89 auto recv_buf =
90 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
91 std::tuple(),
92 args...
93 )
95 using recv_value_type = typename std::remove_reference_t<decltype(recv_buf)>::value_type;
96 static_assert(
97 !std::is_same_v<recv_value_type, internal::unused_tparam>,
98 "No recv_buf parameter provided and no receive value given as template parameter. One of these is required."
99 );
100
101 auto recv_type = internal::determine_mpi_recv_datatype<recv_value_type, decltype(recv_buf)>(args...);
103
104 using default_request_param = decltype(kamping::request());
105 auto&& request_param =
106 internal::select_parameter_type_or_default<internal::ParameterType::request, default_request_param>(
107 std::tuple{},
108 args...
109 );
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
133 // Get the optional recv_count parameter. If the parameter is not given,
134 // allocate a new container.
136 auto recv_count_param =
137 internal::select_parameter_type_or_default<internal::ParameterType::recv_count, default_recv_count_type>(
138 std::tuple(),
139 args...
140 )
141 .construct_buffer_or_rebind();
142
144 int source = source_param.rank_signed();
145 int tag = tag_param.tag();
146 if constexpr (internal::has_to_be_computed<decltype(recv_count_param)>) {
147 Status probe_status = this->probe(source_param.clone(), tag_param.clone(), status_out()).extract_status();
148 source = probe_status.source_signed();
149 tag = probe_status.tag();
150 recv_count_param.underlying() = asserting_cast<int>(probe_status.count(recv_type.get_single_element()));
151 }
152
153 // Ensure that we do not touch the recv buffer if MPI_PROC_NULL is passed,
154 // because this is what the standard guarantees.
155 if constexpr (std::remove_reference_t<decltype(source_param)>::rank_type != internal::RankType::null) {
157 return asserting_cast<size_t>(recv_count_param.get_single_element());
158 };
159 recv_buf.resize_if_requested(compute_required_recv_buf_size);
160 KASSERT(
161 // if the recv type is user provided, kamping cannot make any assumptions about the required size of the
162 // recv buffer
164 "Recv buffer is not large enough to hold all received elements.",
166 );
167 }
168
169 // store all parameters/buffers for which we have to ensure pointer stability until completion of the immediate MPI
170 // call on the heap.
171 auto buffers_on_heap = move_buffer_to_heap(std::move(recv_buf), std::move(recv_count_param), std::move(recv_type));
172
173 [[maybe_unused]] int err = MPI_Irecv(
174 internal::select_parameter_type_in_tuple<internal::ParameterType::recv_buf>(*buffers_on_heap)
175 .data(), // recvbuf,
176 internal::select_parameter_type_in_tuple<internal::ParameterType::recv_count>(*buffers_on_heap)
177 .get_single_element(), // count,
178 internal::select_parameter_type_in_tuple<internal::ParameterType::recv_type>(*buffers_on_heap)
179 .get_single_element(), // datatype
180 source, // source
181 tag, // tag
182 this->mpi_communicator(), // comm
183 request_param.underlying().request_ptr() // request
184 );
185 this->mpi_error_hook(err, "MPI_Irecv");
186
187 return internal::make_nonblocking_result<std::tuple<Args...>>(std::move(request_param), std::move(buffers_on_heap));
188}
189/// @}
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
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:45
static constexpr auto alloc_new
Convenience wrapper for creating library allocated containers. See AllocNewT for details.
Definition data_buffer.hpp:194
auto request()
Internally allocate a request object and return it to the user.
Definition named_parameters.hpp:1186
auto tag(internal::any_tag_t)
Indicates to use MPI_ANY_TAG as tag in the underlying call.
Definition named_parameters.hpp:1066
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:1030
auto recv_count(int count)
Passes count as recv count to the underlying call.
Definition named_parameters.hpp:492
auto recv_buf(Container &&container)
Passes a container, into which the received elements will be written, to the underlying call....
Definition named_parameters.hpp:861
auto recv_type(MPI_Datatype recv_type)
Passes recv_type as recv type to the underlying call.
Definition named_parameters.hpp:1302
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:518
auto irecv(Args... args) const
Definition irecv.hpp:82
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.
@ 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
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
auto make_nonblocking_result(RequestDataBuffer &&request, std::unique_ptr< std::tuple< Buffers... > > buffers_on_heap)
Factory for creating a kamping::NonBlockingResult.
Definition result.hpp:1308
Parameter objects return by named parameter factory functions.
Some functions and types simplifying/enabling the development of wrapped MPI calls in KaMPIng.