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