KaMPIng 0.2.0
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
request_pool.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 terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
7// version. KaMPIng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
9// for more details.
10//
11// You should have received a copy of the GNU Lesser General Public License along with KaMPIng. If not, see
12// <https://www.gnu.org/licenses/>.
13
14#pragma once
15
16#include <cstddef>
17#include <vector>
18
19#include <mpi.h>
20
23#include "kamping/named_parameters_detail/status_parameters.hpp"
25#include "kamping/request.hpp"
26
27namespace kamping {
28
29/// @brief Result returned by \ref RequestPool.wait_any()
30/// @tparam IndexType Type of the stored Index.
31/// @tparam StatusType Type of the status object.
32template <typename IndexType, typename StatusType>
35 index; ///< The index of the completed operation. \ref RequestPool.index_end() if there were no active requests.
36 StatusType status; ///< The status of the complete operation.
37};
38
39/// @brief A pool for storing multiple \ref Request s and checking them for completion.
40///
41/// Requests are internally stored in a vector. The vector is resized as needed.
42/// New requests can be obtained by calling \ref get_request.
43///
44/// @tparam DefaultContainerType The default container type to use for containers created inside pool operations.
45/// Defaults to std::vector.
46template <template <typename...> typename DefaultContainerType = std::vector>
48public:
49 /// @brief Constructs a new empty \ref RequestPool.
51
52 using index_type = size_t; ///< The type used to index requests in the pool.
53
54 /// @brief Type of the default container type to use for containers created inside operations of this request pool.
55 /// @tparam Args Arguments to the container type.
56 template <typename... Args>
58
59 /// @brief The first index value. The pool is empty if `index_begin() == index_end()`.
61 return 0;
62 }
63
64 /// @brief The index value after the last one. The pool is empty if `index_begin() == index_end()`.
66 return _requests.size();
67 }
68
69 /// @brief Returns the number of requests currently stored in the pool.
70 size_t num_requests() const {
71 return _requests.size();
72 }
73
74 /// @brief Returns a pointer to the underlying MPI_Request array.
76 return _requests.data();
77 }
78
79 /// @brief Adds a new request to the pool and returns a \ref PooledRequest encapsulating it.
81 MPI_Request& req = _requests.emplace_back(MPI_REQUEST_NULL);
82 return PooledRequest<index_type>{_requests.size() - 1, req};
83 }
84
85 /// @brief Waits for all requests in the pool to complete by calling \c MPI_Waitall.
86 /// @param statuses_param A \c statuses parameter object to which the status information is written. Defaults
87 /// to \c kamping::statuses(ignore<>).
88 /// @return If \p statuses is an owning out parameter, returns the status information, otherwise returns nothing.
89 template <typename StatusesParamObjectType = decltype(kamping::statuses(ignore<>))>
91 static_assert(
92 StatusesParamObjectType::parameter_type == internal::ParameterType::statuses,
93 "Only statuses parameters are allowed."
94 );
97 if constexpr (decltype(statuses)::buffer_type == internal::BufferType::ignore) {
99 } else {
100 auto compute_requested_size = [&] {
101 return num_requests();
102 };
103 statuses.resize_if_requested(compute_requested_size);
106 "statuses buffer is not large enough to hold all status information.",
108 );
109 statuses_ptr = statuses.data();
110 }
113 if constexpr (internal::is_extractable<decltype(statuses)>) {
114 return statuses.extract();
115 }
116 }
117
118 /// @brief Tests whether all requests in the pool have completed by calling \c MPI_Testall.
119 /// @param statuses_param A \c statuses parameter object to which the status information is written. Defaults
120 /// to \c kamping::statuses(ignore<>).
121 /// @return A truthful value if all requests have completed, a falsy value otherwise.
122 /// @note By default, returns a \c bool indicated completion, but if \p statuses is an owning out parameter, returns
123 /// a \c std::optional containing the status information.
124 /// @warning If the status parameter is provided, the underlying buffer is always resized to fit all requests
125 /// according to its \c resize_policy, even if not all requests have completed yet. This is because MPI
126 /// does not allow retrieving statuses after a test succeeded.
127 template <typename StatusesParamObjectType = decltype(kamping::statuses(ignore<>))>
129 static_assert(
130 StatusesParamObjectType::parameter_type == internal::ParameterType::statuses,
131 "Only statuses parameters are allowed."
132 );
135 if constexpr (decltype(statuses)::buffer_type == internal::BufferType::ignore) {
137 } else {
138 auto compute_requested_size = [&] {
139 return num_requests();
140 };
141 statuses.resize_if_requested(compute_requested_size);
144 "statuses buffer is not large enough to hold all status information.",
146 );
147 statuses_ptr = statuses.data();
148 }
149 int succeeded = false;
150 [[maybe_unused]] int err =
153 if constexpr (internal::is_extractable<decltype(statuses)>) {
154 if (succeeded) {
155 return std::optional{statuses.extract()};
156 } else {
157 return std::optional<decltype(statuses.extract())>{};
158 }
159 } else {
160 return static_cast<bool>(succeeded);
161 }
162 }
163
164 /// @brief Waits any request in the pool to complete by calling \c MPI_Waitany.
165 /// @param status_param A \c status parameter object to which the status information about the completed operation
166 /// is written. Defaults to \c kamping::status(ignore<>).
167 /// @return By default, returns the index of the completed operation. If the pool is
168 /// empty or no request in the pool is active, returns an index equal to `index_end()`. If \p status is an owning
169 /// out parameter, also returns the status alongside the index by returning a \ref PoolAnyResult.
170 /// @see PoolAnyResult
171 template <typename StatusParamObjectType = decltype(status(ignore<>))>
173 static_assert(
174 StatusParamObjectType::parameter_type == internal::ParameterType::status,
175 "Only status parameters are allowed."
176 );
177 auto status = status_param.construct_buffer_or_rebind();
178 int index;
179 int err = MPI_Waitany(
181 request_ptr(),
182 &index,
184 );
186 if constexpr (internal::is_extractable<decltype(status)>) {
187 using status_type = decltype(status.extract());
188 if (index == MPI_UNDEFINED) {
190 } else {
191 return PoolAnyResult<index_type, status_type>{static_cast<index_type>(index), status.extract()};
192 }
193 } else {
194 if (index == MPI_UNDEFINED) {
195 return index_end();
196 } else {
197 return static_cast<index_type>(index);
198 }
199 }
200 }
201
202 /// @brief Tests if any request in the pool is completed by calling \c MPI_Testany.
203 /// @param status_param A \c status parameter object to which the status information about the completed operation
204 /// is written. Defaults to \c kamping::status(ignore<>).
205 /// @return If any request completes, returns an `std::optional` containing information about the completed request.
206 /// Otherwise, `std::nullopt`. The value contained inside the optional depends on \p status parameter and
207 /// follows the same rules as for \ref wait_any.
208 /// @see wait_any
209 template <typename StatusParamObjectType = decltype(status(ignore<>))>
211 static_assert(
212 StatusParamObjectType::parameter_type == internal::ParameterType::status,
213 "Only status parameters are allowed."
214 );
215 auto status = status_param.construct_buffer_or_rebind();
216 int index;
217 int flag;
218 int err = MPI_Testany(
220 request_ptr(),
221 &index,
222 &flag,
224 );
226 if constexpr (internal::is_extractable<decltype(status)>) {
227 using status_type = decltype(status.extract());
229 if (flag) {
230 if (index == MPI_UNDEFINED) {
231 return std::optional<return_type>{{index_end(), status.extract()}};
232 } else {
233 return std::optional<return_type>{{static_cast<index_type>(index), status.extract()}};
234 }
235 } else {
236 return std::optional<PoolAnyResult<index_type, status_type>>{};
237 }
238 } else {
239 if (flag) {
240 if (index == MPI_UNDEFINED) {
241 return std::optional{index_end()};
242 } else {
243 return std::optional{static_cast<index_type>(index)};
244 }
245 } else {
246 return std::optional<index_type>{};
247 }
248 }
249 }
250
251private:
252 std::vector<MPI_Request> _requests;
253};
254} // namespace kamping
Helper functions that make casts safer.
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
A pool for storing multiple Request s and checking them for completion.
Definition request_pool.hpp:47
auto wait_any(StatusParamObjectType status_param=kamping::status(ignore<>))
Waits any request in the pool to complete by calling MPI_Waitany.
Definition request_pool.hpp:172
index_type index_end() const
The index value after the last one. The pool is empty if index_begin() == index_end().
Definition request_pool.hpp:65
MPI_Request * request_ptr()
Returns a pointer to the underlying MPI_Request array.
Definition request_pool.hpp:75
auto test_all(StatusesParamObjectType statuses_param=kamping::statuses(ignore<>))
Tests whether all requests in the pool have completed by calling MPI_Testall.
Definition request_pool.hpp:128
RequestPool()
Constructs a new empty RequestPool.
Definition request_pool.hpp:50
auto wait_all(StatusesParamObjectType statuses_param=kamping::statuses(ignore<>))
Waits for all requests in the pool to complete by calling MPI_Waitall.
Definition request_pool.hpp:90
size_t num_requests() const
Returns the number of requests currently stored in the pool.
Definition request_pool.hpp:70
auto test_any(StatusParamObjectType status_param=kamping::status(ignore<>))
Tests if any request in the pool is completed by calling MPI_Testany.
Definition request_pool.hpp:210
PooledRequest< index_type > get_request()
Adds a new request to the pool and returns a PooledRequest encapsulating it.
Definition request_pool.hpp:80
index_type index_begin() const
The first index value. The pool is empty if index_begin() == index_end().
Definition request_pool.hpp:60
#define THROW_IF_MPI_ERROR(error_code, function)
Wrapper around THROWING_KAMPING_ASSERT for MPI errors.
Definition error_handling.hpp:34
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
auto statuses(internal::ignore_t< void >)
pass MPI_STATUSES_IGNORE to the underlying MPI call.
Definition status_parameters.hpp:60
@ status
Tag used to represent the status in a MPI call.
@ statuses
Tag used to represent a container of statuses in a MPI call.
constexpr bool is_extractable
Helper for implementing the extract_* functions in MPIResult. Is true if the passed buffer type owns ...
Definition result.hpp:48
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.
Result returned by RequestPool::wait_any()
Definition request_pool.hpp:33
IndexType index
The index of the completed operation. RequestPool::index_end() if there were no active requests.
Definition request_pool.hpp:35
StatusType status
The status of the complete operation.
Definition request_pool.hpp:36