KaMPIng 0.1.0
(Near) zero-overhead C++ MPI bindings.
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#pragma once
16
17#include <cstddef>
18#include <vector>
19
20#include <mpi.h>
21
24#include "kamping/named_parameters_detail/status_parameters.hpp"
26#include "kamping/request.hpp"
27
28namespace kamping {
29
30/// @brief Result returned by \ref RequestPool.wait_any()
31/// @tparam IndexType Type of the stored Index.
32/// @tparam StatusType Type of the status object.
33template <typename IndexType, typename StatusType>
36 index; ///< The index of the completed operation. \ref RequestPool.index_end() if there were no active requests.
37 StatusType status; ///< The status of the complete operation.
38};
39
40/// @brief A pool for storing multiple \ref Request s and checking them for completion.
41///
42/// Requests are internally stored in a vector. The vector is resized as needed.
43/// New requests can be obtained by calling \ref get_request.
44///
45/// @tparam DefaultContainerType The default container type to use for containers created inside pool operations.
46/// Defaults to std::vector.
47template <template <typename...> typename DefaultContainerType = std::vector>
49public:
50 /// @brief Constructs a new empty \ref RequestPool.
52
53 using index_type = size_t; ///< The type used to index requests in the pool.
54
55 /// @brief Type of the default container type to use for containers created inside operations of this request pool.
56 /// @tparam Args Arguments to the container type.
57 template <typename... Args>
59
60 /// @brief The first index value. The pool is empty if `index_begin() == index_end()`.
62 return 0;
63 }
64
65 /// @brief The index value after the last one. The pool is empty if `index_begin() == index_end()`.
67 return _requests.size();
68 }
69
70 /// @brief Returns the number of requests currently stored in the pool.
71 size_t num_requests() const {
72 return _requests.size();
73 }
74
75 /// @brief Returns a pointer to the underlying MPI_Request array.
77 return _requests.data();
78 }
79
80 /// @brief Adds a new request to the pool and returns a \ref PooledRequest encapsulating it.
82 MPI_Request& req = _requests.emplace_back(MPI_REQUEST_NULL);
83 return PooledRequest<index_type>{_requests.size() - 1, req};
84 }
85
86 /// @brief Waits for all requests in the pool to complete by calling \c MPI_Waitall.
87 /// @param statuses_param A \c statuses parameter object to which the status information is written. Defaults
88 /// to \c kamping::statuses(ignore<>).
89 /// @return If \p statuses is an owning out parameter, returns the status information, otherwise returns nothing.
90 template <typename StatusesParamObjectType = decltype(kamping::statuses(ignore<>))>
92 static_assert(
93 StatusesParamObjectType::parameter_type == internal::ParameterType::statuses,
94 "Only statuses parameters are allowed."
95 );
98 if constexpr (decltype(statuses)::buffer_type == internal::BufferType::ignore) {
100 } else {
101 auto compute_requested_size = [&] {
102 return num_requests();
103 };
104 statuses.resize_if_requested(compute_requested_size);
105 KASSERT(
107 "statuses buffer is not large enough to hold all status information.",
109 );
110 statuses_ptr = statuses.data();
111 }
114 if constexpr (internal::is_extractable<decltype(statuses)>) {
115 return statuses.extract();
116 }
117 }
118
119 /// @brief Tests whether all requests in the pool have completed by calling \c MPI_Testall.
120 /// @param statuses_param A \c statuses parameter object to which the status information is written. Defaults
121 /// to \c kamping::statuses(ignore<>).
122 /// @return A truthful value if all requests have completed, a falsy value otherwise.
123 /// @note By default, returns a \c bool indicated completion, but if \p statuses is an owning out parameter, returns
124 /// a \c std::optional containing the status information.
125 /// @warning If the status parameter is provided, the underlying buffer is always resized to fit all requests
126 /// according to its \c resize_policy, even if not all requests have completed yet. This is because MPI
127 /// does not allow retrieving statuses after a test succeeded.
128 template <typename StatusesParamObjectType = decltype(kamping::statuses(ignore<>))>
130 static_assert(
131 StatusesParamObjectType::parameter_type == internal::ParameterType::statuses,
132 "Only statuses parameters are allowed."
133 );
136 if constexpr (decltype(statuses)::buffer_type == internal::BufferType::ignore) {
138 } else {
139 auto compute_requested_size = [&] {
140 return num_requests();
141 };
142 statuses.resize_if_requested(compute_requested_size);
143 KASSERT(
145 "statuses buffer is not large enough to hold all status information.",
147 );
148 statuses_ptr = statuses.data();
149 }
150 int succeeded = false;
151 [[maybe_unused]] int err =
154 if constexpr (internal::is_extractable<decltype(statuses)>) {
155 if (succeeded) {
156 return std::optional{statuses.extract()};
157 } else {
158 return std::optional<decltype(statuses.extract())>{};
159 }
160 } else {
161 return static_cast<bool>(succeeded);
162 }
163 }
164
165 /// @brief Waits any request in the pool to complete by calling \c MPI_Waitany.
166 /// @param status_param A \c status parameter object to which the status information about the completed operation
167 /// is written. Defaults to \c kamping::status(ignore<>).
168 /// @return By default, returns the index of the completed operation. If the pool is
169 /// empty or no request in the pool is active, returns an index equal to `index_end()`. If \p status is an owning
170 /// out parameter, also returns the status alongside the index by returning a \ref PoolAnyResult.
171 /// @see PoolAnyResult
172 template <typename StatusParamObjectType = decltype(status(ignore<>))>
174 static_assert(
175 StatusParamObjectType::parameter_type == internal::ParameterType::status,
176 "Only status parameters are allowed."
177 );
178 auto status = status_param.construct_buffer_or_rebind();
179 int index;
180 int err = MPI_Waitany(
182 request_ptr(),
183 &index,
185 );
187 if constexpr (internal::is_extractable<decltype(status)>) {
188 using status_type = decltype(status.extract());
189 if (index == MPI_UNDEFINED) {
191 } else {
192 return PoolAnyResult<index_type, status_type>{static_cast<index_type>(index), status.extract()};
193 }
194 } else {
195 if (index == MPI_UNDEFINED) {
196 return index_end();
197 } else {
198 return static_cast<index_type>(index);
199 }
200 }
201 }
202
203 /// @brief Tests if any request in the pool is completed by calling \c MPI_Testany.
204 /// @param status_param A \c status parameter object to which the status information about the completed operation
205 /// is written. Defaults to \c kamping::status(ignore<>).
206 /// @return If any request completes, returns an `std::optional` containing information about the completed request.
207 /// Otherwise, `std::nullopt`. The value contained inside the optional depends on \p status parameter and
208 /// follows the same rules as for \ref wait_any.
209 /// @see wait_any
210 template <typename StatusParamObjectType = decltype(status(ignore<>))>
212 static_assert(
213 StatusParamObjectType::parameter_type == internal::ParameterType::status,
214 "Only status parameters are allowed."
215 );
216 auto status = status_param.construct_buffer_or_rebind();
217 int index;
218 int flag;
219 int err = MPI_Testany(
221 request_ptr(),
222 &index,
223 &flag,
225 );
227 if constexpr (internal::is_extractable<decltype(status)>) {
228 using status_type = decltype(status.extract());
230 if (flag) {
231 if (index == MPI_UNDEFINED) {
232 return std::optional<return_type>{{index_end(), status.extract()}};
233 } else {
234 return std::optional<return_type>{{static_cast<index_type>(index), status.extract()}};
235 }
236 } else {
237 return std::optional<PoolAnyResult<index_type, status_type>>{};
238 }
239 } else {
240 if (flag) {
241 if (index == MPI_UNDEFINED) {
242 return std::optional{index_end()};
243 } else {
244 return std::optional{static_cast<index_type>(index)};
245 }
246 } else {
247 return std::optional<index_type>{};
248 }
249 }
250 }
251
252private:
253 std::vector<MPI_Request> _requests;
254};
255} // 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:48
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:173
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:66
MPI_Request * request_ptr()
Returns a pointer to the underlying MPI_Request array.
Definition request_pool.hpp:76
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:129
RequestPool()
Constructs a new empty RequestPool.
Definition request_pool.hpp:51
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:91
size_t num_requests() const
Returns the number of requests currently stored in the pool.
Definition request_pool.hpp:71
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:211
PooledRequest< index_type > get_request()
Adds a new request to the pool and returns a PooledRequest encapsulating it.
Definition request_pool.hpp:81
index_type index_begin() const
The first index value. The pool is empty if index_begin() == index_end().
Definition request_pool.hpp:61
#define THROW_IF_MPI_ERROR(error_code, function)
Wrapper around THROWING_KASSERT for MPI errors.
Definition error_handling.hpp:33
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
auto statuses(internal::ignore_t< void >)
pass MPI_STATUSES_IGNORE to the underlying MPI call.
Definition status_parameters.hpp:58
@ 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:34
IndexType index
The index of the completed operation. RequestPool::index_end() if there were no active requests.
Definition request_pool.hpp:36
StatusType status
The status of the complete operation.
Definition request_pool.hpp:37