KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
try_recv.hpp
1// This file is part of KaMPIng.
2//
3// Copyright 2023-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"
32#include "kamping/p2p/helpers.hpp"
34#include "kamping/result.hpp"
35#include "kamping/status.hpp"
36
37///// @addtogroup kamping_p2p
38/// @{
39
40// @brief Receives a message if one is available.
41///
42/// In contrast to \ref kamping::Communicator::recv(), this method does not block if no message is available. Instead,
43/// it will return a empty \c std::optional. Internally, this first does a matched probe (\c MPI_Improbe) to check if a
44/// message is available. If a message is available, it will be received using a matched receive (\c MPI_Mrecv).
45///
46/// The following parameters are optional:
47/// - \ref kamping::recv_buf() the buffer to receive the message into. The buffer's underlying storage must be large
48/// enough to hold all received elements. If no \ref kamping::recv_buf() is provided, the \c value_type of the recv
49/// buffer has to be passed as a template parameter to \c recv().
50///
51/// - \ref kamping::tag() receive message with the given tag. Defaults to receiving for an arbitrary tag, i.e. \c
52/// tag(tags::any).
53///
54/// - \ref kamping::source() receive a message sent from the given source rank. Defaults to probing for an arbitrary
55/// source, i.e. \c source(rank::any).
56///
57/// - \ref kamping::status(). Returns info about the received message by setting the
58/// appropriate fields in the status object. The status can be obtained by using \c kamping::status_out and ignored by
59/// passing \c kamping::ignore<>. This is the default.
60///
61/// - \ref kamping::recv_type() specifying the \c MPI datatype to use as the recv type. If omitted, the \c MPI datatype
62/// is derived automatically based on `recv_buf`'s underlying \c value_type.
63///
64/// @tparam recv_value_type_tparam The type that is received. Only required when no \ref kamping::recv_buf() is given.
65/// @tparam Args Automatically deduced template parameters.
66/// @param args All required and any number of the optional buffers described above.
67/// @return If no message is available return \c std::nullopt, else return a \c std::optional wrapping an \ref
68/// kamping::MPIResult. If the result object is empty, i.e. there are no owning out parameters passed to `try_recv` (see
69/// \ref docs/parameter_handling.md), returns a \c bool indicating success instead of an \c std::optional.
70///
71/// @see \ref docs/parameter_handling.md for general information about parameter handling in KaMPIng.
72/// <hr>
73/// \include{doc} docs/resize_policy.dox
74template <
75 template <typename...>
76 typename DefaultContainerType,
77 template <typename, template <typename...> typename>
78 typename... Plugins>
79template <typename recv_value_type_tparam /* = kamping::internal::unused_tparam */, typename... Args>
81 // Check parameters
83 Args,
86 );
87
88 // Get the recv buffer
90 auto&& recv_buf =
91 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
92 std::tuple(),
93 args...
94 )
96 using recv_value_type = typename std::remove_reference_t<decltype(recv_buf)>::value_type;
97 static_assert(
98 !std::is_same_v<recv_value_type, internal::unused_tparam>,
99 "No recv_buf parameter provided and no receive value given as template parameter. One of these is required."
100 );
101
102 auto&& recv_type = internal::determine_mpi_recv_datatype<recv_value_type, decltype(recv_buf)>(args...);
104
105 // Get the source parameter. If the parameter is not given, use MPI_ANY_SOURCE.
106 using default_source_buf_type = decltype(kamping::source(rank::any));
107 auto&& source_param =
108 internal::select_parameter_type_or_default<internal::ParameterType::source, default_source_buf_type>(
109 {},
110 args...
111 );
112
113 // Get the tag parameter. If the parameter is not given, use MPI_ANY_TAG.
114 using default_tag_buf_type = decltype(kamping::tag(tags::any));
115 auto&& tag_param =
116 internal::select_parameter_type_or_default<internal::ParameterType::tag, default_tag_buf_type>({}, args...);
117 constexpr auto tag_type = std::remove_reference_t<decltype(tag_param)>::tag_type;
118 if constexpr (tag_type == internal::TagType::value) {
119 int tag = tag_param.tag();
120 KASSERT(
122 "invalid tag " << tag << ", must be in range [0, " << Environment<>::tag_upper_bound() << "]"
123 );
124 }
125 // Get the status parameter.
127 auto&& status_param =
128 internal::select_parameter_type_or_default<internal::ParameterType::status, default_status_param_type>(
129 {},
130 args...
131 )
132 .construct_buffer_or_rebind();
133 KASSERT(internal::is_valid_rank_in_comm(source_param, *this, /*allow_null=*/true, /*allow_any=*/true));
134 int source = source_param.rank_signed();
135 int tag = tag_param.tag();
136
137 // Use a matched probe to check if a message with the given source and tag is available for receiving.
138 int msg_avail;
140
142 [[maybe_unused]] int err = MPI_Improbe(source, tag, _comm, &msg_avail, &message, &status.native());
143 this->mpi_error_hook(err, "MPI_Improbe");
144
145 auto construct_result = [&] {
146 return internal::make_mpi_result<std::tuple<Args...>>(
147 std::move(recv_buf),
148 std::move(status_param),
149 std::move(recv_type)
150 );
151 };
152 using result_type = decltype(construct_result());
153 // If a message is available, receive it using a matched receive.
154 if (msg_avail) {
155 size_t const count = status.count(recv_type.get_single_element());
156
157 // Ensure that we do not touch the recv buffer if MPI_PROC_NULL is passed, because this is what the standard
158 // guarantees.
159 if constexpr (std::remove_reference_t<decltype(source_param)>::rank_type != internal::RankType::null) {
160 recv_buf.resize_if_requested([&] { return count; });
161 KASSERT(
162 // If the recv type is user provided, kamping cannot make any assumptions about the required size of the
163 // recv buffer.
164 recv_type_is_in_param || recv_buf.size() >= count,
165 "Recv buffer is not large enough to hold all received elements.",
167 );
168 }
169
170 // Use a matched receive to receive exactly the message we probed. This ensures this method is thread-safe.
171 err = MPI_Mrecv(
172 recv_buf.data(), // buf
173 asserting_cast<int>(count), // count
174 recv_type.get_single_element(), // datatype
175 &message, // message
177 );
178 this->mpi_error_hook(err, "MPI_Mrecv");
179
180 // Build the result object from the parameters and return.
181 if constexpr (is_result_empty_v<result_type>) {
182 return true;
183 } else {
184 return std::optional{construct_result()};
185 }
186 } else {
187 // There was no message to receive, thus return false/std::nullopt.
188 if constexpr (is_result_empty_v<result_type>) {
189 return false;
190 } else {
191 return std::optional<result_type>{};
192 }
193 }
194}
195/// @}
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(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_type(MPI_Datatype recv_type)
Passes recv_type as recv type to the underlying call.
Definition named_parameters.hpp:1238
auto try_recv(Args... args) const
Definition try_recv.hpp:80
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
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.