KaMPIng 0.1.0
(Near) zero-overhead C++ MPI bindings.
Loading...
Searching...
No Matches
isend.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
20#include <kassert/kassert.hpp>
21#include <mpi.h>
22
23#include "kamping/communicator.hpp"
25#include "kamping/implementation_helpers.hpp"
31#include "kamping/p2p/helpers.hpp"
33#include "kamping/request.hpp"
34#include "kamping/result.hpp"
35
36///// @addtogroup kamping_p2p
37/// @{
38
39// @brief Wrapper for \c MPI_Isend.
40///
41/// This wraps \c MPI_Isend. This operation sends the elements in the input buffer provided via \c
42/// kamping::send_buf() to the specified receiver rank using standard send mode without blocking. The call is associated
43/// with a \ref kamping::Request (either allocated by KaMPIng or provided by the user). Before accessing the result the
44/// user has to complete the request.
45///
46/// The following parameters are required:
47/// - \ref kamping::send_buf() containing the data that is sent.
48///
49/// - \ref kamping::destination() the receiving rank.
50///
51/// The following parameters are optional:
52/// - \ref kamping::send_count() specifying how many elements of the buffer are sent.
53/// If omitted, the size of the send buffer is used as a default. This parameter is mandatory if \ref
54/// kamping::send_type() is given.
55///
56/// - \ref kamping::send_type() specifying the \c MPI datatype to use as send type. If omitted, the \c MPI datatype is
57/// derived automatically based on send_buf's underlying \c value_type.
58///
59/// - \ref kamping::tag() the tag added to the message. Defaults to the communicator's default tag (\ref
60/// Communicator::default_tag()) if not present.
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/// - \ref kamping::send_mode() the send mode to use. Defaults to standard MPI_Send.
66///
67/// @tparam Args Automatically deduced template parameters.
68/// @param args All required and any number of the optional parameters described above.
69/// @return Result object wrapping the output parameters to be returned by value.
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... Args>
81 using namespace kamping::internal;
83 Args,
86 );
87
88 auto&& send_buf =
89 internal::select_parameter_type<internal::ParameterType::send_buf>(args...).construct_buffer_or_rebind();
90 using send_value_type = typename std::remove_reference_t<decltype(send_buf)>::value_type;
91
92 auto&& send_type = internal::determine_mpi_send_datatype<send_value_type>(args...);
93
95 auto&& send_count =
96 internal::select_parameter_type_or_default<internal::ParameterType::send_count, default_send_count_type>(
97 {},
98 args...
99 )
100 .construct_buffer_or_rebind();
101 if constexpr (has_to_be_computed<decltype(send_count)>) {
102 send_count.underlying() = asserting_cast<int>(send_buf.size());
103 }
104
105 auto const& destination = internal::select_parameter_type<internal::ParameterType::destination>(args...);
106 constexpr auto rank_type = std::remove_reference_t<decltype(destination)>::rank_type;
107 static_assert(
108 rank_type == RankType::value || rank_type == RankType::null,
109 "Please provide an explicit destination or destination(ranks::null)."
110 );
111 using default_request_param = decltype(kamping::request());
112 auto&& request_param =
113 internal::select_parameter_type_or_default<internal::ParameterType::request, default_request_param>(
114 std::tuple{},
115 args...
116 );
117
118 using default_tag_buf_type = decltype(kamping::tag(0));
119
120 auto&& tag_param = internal::select_parameter_type_or_default<internal::ParameterType::tag, default_tag_buf_type>(
121 std::tuple(this->default_tag()),
122 args...
123 );
124
125 // this ensures that the user does not try to pass MPI_ANY_TAG, which is not allowed for sends
126 static_assert(
127 std::remove_reference_t<decltype(tag_param)>::tag_type == TagType::value,
128 "Please provide a tag for the message."
129 );
130 int tag = tag_param.tag();
131 KASSERT(
133 "invalid tag " << tag << ", must be in range [0, " << Environment<>::tag_upper_bound() << "]"
134 );
135
139 using send_mode = typename std::remove_reference_t<send_mode_obj_type>::send_mode;
140
141 // RankType::null is valid, RankType::any is not.
142 KASSERT(is_valid_rank_in_comm(destination, *this, true, false), "Invalid destination rank.");
143 auto result = make_nonblocking_result<std::tuple<Args...>>(std::move(send_buf), std::move(request_param));
144
145 // quick and dirty access to the underlying send_buf
146 auto send_buf_ptr = [&]() {
147 if constexpr (std::remove_reference_t<decltype(send_buf)>::buffer_type == BufferType::in_out_buffer) {
148 auto const& result_ = result.get_result();
149 using result_type = std::remove_reference_t<decltype(result_)>;
150 if constexpr (is_mpi_result_v<result_type>) {
151 return result_.get_send_buffer().data();
152 } else {
153 // this branch is taken if make_result directly returns a buffer, i.e. when the user only provided
154 // send_buf_out. then we access the data directly
155 if constexpr (has_data_member_v<decltype(result_)>) {
156 return result_.data();
157 } else {
158 // if it is a single element, we do not have .data()
159 return &result_;
160 }
161 }
162 } else {
163 return send_buf.data();
164 }
165 };
166
167 if constexpr (std::is_same_v<send_mode, internal::standard_mode_t>) {
168 [[maybe_unused]] int err = MPI_Isend(
169 send_buf_ptr(), // send_buf
170 send_count.get_single_element(), // send_count
171 send_type.get_single_element(), // send_type
172 destination.rank_signed(), // destination
173 tag, // tag
174 this->mpi_communicator(), // comm
175 result.get_request_ptr() // request
176 );
177 this->mpi_error_hook(err, "MPI_Isend");
178 } else if constexpr (std::is_same_v<send_mode, internal::buffered_mode_t>) {
179 [[maybe_unused]] int err = MPI_Ibsend(
180 send_buf_ptr(), // send_buf
181 send_count.get_single_element(), // send_count
182 send_type.get_single_element(), // send_type
183 destination.rank_signed(), // destination
184 tag, // tag
185 this->mpi_communicator(), // comm
186 result.get_request_ptr() // request
187 );
188 this->mpi_error_hook(err, "MPI_Ibsend");
189 } else if constexpr (std::is_same_v<send_mode, internal::synchronous_mode_t>) {
190 [[maybe_unused]] int err = MPI_Issend(
191 send_buf_ptr(), // send_buf
192 send_count.get_single_element(), // send_count
193 send_type.get_single_element(), // send_type
194 destination.rank_signed(), // destination
195 tag, // tag
196 this->mpi_communicator(), // comm
197 result.get_request_ptr() // request
198 );
199 this->mpi_error_hook(err, "MPI_Issend");
200 } else if constexpr (std::is_same_v<send_mode, internal::ready_mode_t>) {
201 [[maybe_unused]] int err = MPI_Irsend(
202 send_buf_ptr(), // send_buf
203 send_count.get_single_element(), // send_count
204 send_type.get_single_element(), // send_type
205 destination.rank_signed(), // destination
206 tag, // tag
207 this->mpi_communicator(), // comm
208 result.get_request_ptr() // request
209 );
210 this->mpi_error_hook(err, "MPI_Irsend");
211 }
212 return result;
213}
214
215/// @brief Convenience wrapper for MPI_Ibsend. Calls \ref kamping::Communicator::isend() with the appropriate send mode
216/// set.
217template <
218 template <typename...>
219 typename DefaultContainerType,
220 template <typename, template <typename...> typename>
221 typename... Plugins>
222template <typename... Args>
224 return this->isend(std::forward<Args>(args)..., send_mode(send_modes::buffered));
225}
226
227/// @brief Convenience wrapper for MPI_Issend. Calls \ref kamping::Communicator::isend() with the appropriate send mode
228/// set.
229template <
230 template <typename...>
231 typename DefaultContainerType,
232 template <typename, template <typename...> typename>
233 typename... Plugins>
234template <typename... Args>
236 return this->isend(std::forward<Args>(args)..., send_mode(send_modes::synchronous));
237}
238
239/// @brief Convenience wrapper for MPI_Irsend. Calls \ref kamping::Communicator::isend() with the appropriate send mode
240/// set.
241template <
242 template <typename...>
243 typename DefaultContainerType,
244 template <typename, template <typename...> typename>
245 typename... Plugins>
246template <typename... Args>
248 return this->isend(std::forward<Args>(args)..., send_mode(send_modes::ready));
249}
250/// @}
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
auto tag(internal::any_tag_t)
Indicates to use MPI_ANY_TAG as tag in the underlying call.
Definition named_parameters.hpp:1064
auto destination(int rank)
Passes rank as destination rank to the underlying call. This parameter is needed in point-to-point ex...
Definition named_parameters.hpp:999
auto send_mode(SendModeTag)
Passes the send mode parameter for point to point communication to the underlying call....
Definition named_parameters.hpp:1137
auto send_count(int count)
Passes count as send count to the underlying call.
Definition named_parameters.hpp:321
auto request()
Internally allocate a request object and return it to the user.
Definition named_parameters.hpp:1122
auto send_type(MPI_Datatype send_type)
Passes send_type as send type to the underlying call.
Definition named_parameters.hpp:1195
auto send_buf(internal::ignore_t< Data > ignore)
Generates a dummy send buf that wraps a nullptr.
Definition named_parameters.hpp:51
auto send_count_out()
Indicates to deduce the send count and return it to the caller as part of the underlying call's resul...
Definition named_parameters.hpp:347
auto ibsend(Args... args) const
Convenience wrapper for MPI_Ibsend. Calls kamping::Communicator::isend() with the appropriate send mo...
Definition isend.hpp:223
auto issend(Args... args) const
Convenience wrapper for MPI_Issend. Calls kamping::Communicator::isend() with the appropriate send mo...
Definition isend.hpp:235
auto isend(Args... args) const
Definition isend.hpp:80
auto irsend(Args... args) const
Convenience wrapper for MPI_Irsend. Calls kamping::Communicator::isend() with the appropriate send mo...
Definition isend.hpp:247
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
@ send_mode
Tag used to represent the send mode used by a send operation.
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
Parameter objects return by named parameter factory functions.
Some functions and types simplifying/enabling the development of wrapped MPI calls in KaMPIng.
Parameter object for send_mode encapsulating the send mode compile-time tag.
Definition parameter_objects.hpp:478