KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
alltoall_sparse.hpp
Go to the documentation of this file.
2#include "kamping/collectives/alltoall.hpp"
3#include "kamping/collectives/barrier.hpp"
4#include "kamping/collectives/ibarrier.hpp"
5#include "kamping/communicator.hpp"
7#include "kamping/named_parameter_filtering.hpp"
10#include "kamping/p2p/iprobe.hpp"
11#include "kamping/p2p/isend.hpp"
12#include "kamping/p2p/recv.hpp"
13#include "kamping/plugin/plugin_helpers.hpp"
14#include "kamping/request_pool.hpp"
15#include "kamping/result.hpp"
16
17/// @file
18/// @brief File containing the SparseAlltoall plugin.
19
20#pragma once
21namespace kamping::plugin {
22
23namespace sparse_alltoall {
24/// @brief Class encapsulating a probed message that is ready to be received in a sparse alltoall exchange.
25template <typename T, typename Communicator>
27public:
28 /// @brief Constructor of a probed message.
29 ProbedMessage(Status&& status, Communicator const& comm) : _status(std::move(status)), _comm(comm) {}
30
31 /// @brief Actually receive the probed message into a contiguous memory either provided by the user or allocated by
32 /// the library.
33 template <typename recv_value_type_tparam = T, typename... Args>
34 auto recv(Args... args) const {
36
39 typename Communicator::template default_container_type<recv_value_type_tparam>>)
40 );
41 auto&& recv_buf =
42 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
43 std::tuple(),
44 args...
45 )
47 using recv_buf_type = std::remove_reference_t<decltype(recv_buf)>;
48
49 using recv_value_type = typename std::remove_reference_t<decltype(recv_buf)>::value_type;
50 auto&& recv_type = internal::determine_mpi_recv_datatype<recv_value_type, decltype(recv_buf)>(args...);
51 auto repack_recv_type = [&]() {
52 // we cannot simply forward recv_type as kamping::recv_type as there are checks within recv() depending on
53 // whether recv_type is caller provided or not
54 if constexpr (internal::has_to_be_computed<decltype(recv_type)>) {
55 return kamping::recv_type_out(recv_type.underlying());
56 } else {
57 return kamping::recv_type(recv_type.underlying());
58 }
59 };
60 _comm.recv(
65 tag(_status.tag())
66 );
67
68 return internal::make_mpi_result<std::tuple<Args...>>(std::move(recv_buf), std::move(recv_type));
69 }
70
71 /// @brief Computes the size of the probed message depending on the used datatype.
78
79 /// @brief Computes the size of the probed message depending on the used datatype.
83
84 /// @brief Returns the source of the probed message.
85 int source_signed() const {
86 return _status.source_signed();
87 }
88
89 /// @brief Returns the source of the probed message.
90 size_t source() const {
91 return _status.source();
92 }
93
94private:
95 Status _status;
96 Communicator const& _comm;
97};
98
99/// @brief Parameter types used for the SparseAlltoall plugin.
100enum class ParameterType {
101 sparse_send_buf, ///< Tag used to represent a sparse send buffer, i.e. a buffer containing destination-message
102 ///< pairs.
103 on_message ///< Tag used to represent a call back function operation on a \ref sparse_alltoall::ProbedMessage object
104 ///< in alltoallv_sparse.
105};
106
107namespace internal {
108/// @brief Predicate to check whether an argument provided to sparse_alltoall shall be discarded in the internal calls
109/// to \ref Communicator::issend().
111 /// @brief Function to check whether an argument provided to \ref SparseAlltoall::alltoallv_sparse() shall be
112 /// discarded in the send call.
113 ///
114 /// @tparam Arg Argument to be checked.
115 /// @return \c True (i.e. discard) iff Arg's parameter_type is `sparse_send_buf`, `on_message` or `destination`.
116 template <typename Arg>
117 static constexpr bool discard() {
118 using namespace kamping::internal;
120 std::integral_constant<sparse_alltoall::ParameterType, sparse_alltoall::ParameterType::sparse_send_buf>,
121 std::integral_constant<sparse_alltoall::ParameterType, sparse_alltoall::ParameterType::on_message>,
122 std::integral_constant<kamping::internal::ParameterType, kamping::internal::ParameterType::tag>,
123 std::integral_constant<kamping::internal::ParameterType, kamping::internal::ParameterType::destination>>;
124 using ptype_entry = std::integral_constant<parameter_type_t<Arg>, parameter_type_v<Arg>>;
125 return ptypes_to_ignore::contains<ptype_entry>;
126 }
127};
128
129} // namespace internal
130
131/// @brief Generates buffer wrapper based on the data in the sparse send buffer.
132/// \param data is a container consisting of destination-message pairs. Each
133/// such pair has to be decomposable via structured bindings with the first parameter being convertible to int and the
134/// second parameter being the actual message to be sent for which we require the usual send_buf properties (i.e.,
135/// either scalar types or existance of a `data()` and `size()` member function and the exposure of a `value_type`))
136///
137/// @tparam Data Data type representing the element(s) to send.
138/// @return Object referring to the storage containing the data elements to send.
139template <typename Data>
140auto sparse_send_buf(Data&& data) {
141 using namespace kamping::internal;
142 constexpr BufferOwnership ownership =
143 std::is_rvalue_reference_v<Data&&> ? BufferOwnership::owning : BufferOwnership::referencing;
144
145 return GenericDataBuffer<
146 std::remove_reference_t<Data>,
148 sparse_alltoall::ParameterType::sparse_send_buf,
149 BufferModifiability::constant,
150 ownership,
151 BufferType::in_buffer>(std::forward<Data>(data));
152}
153
154/// @brief Generates wrapper for an callback to be called on the probed messages in \ref
155/// SparseAlltoall::alltoallv_sparse(). Its call operator has to accept a \ref ProbedMessage as sole parameter.
156template <typename Callback>
158 using namespace kamping::internal;
159 constexpr BufferOwnership ownership =
160 std::is_rvalue_reference_v<Callback&&> ? BufferOwnership::owning : BufferOwnership::referencing;
161
162 constexpr BufferModifiability modifiability = std::is_const_v<std::remove_reference_t<Callback>>
163 ? BufferModifiability::constant
164 : BufferModifiability::modifiable;
165
166 return GenericDataBuffer<
167 std::remove_reference_t<Callback>,
169 sparse_alltoall::ParameterType::on_message,
171 ownership,
172 BufferType::in_buffer>(std::forward<Callback>(cb));
173}
174} // namespace sparse_alltoall
175
176/// @brief Plugin providing a sparse alltoall exchange method.
177/// @see \ref SparseAlltoall::alltoallv_sparse() for more information.
178template <typename Comm, template <typename...> typename DefaultContainerType>
179class SparseAlltoall : public plugin::PluginBase<Comm, DefaultContainerType, SparseAlltoall> {
180public:
181 template <typename... Args>
182 void alltoallv_sparse(Args... args) const;
183};
184
185/// @brief Sparse alltoall exchange using the NBX algorithm(Hoefler et al., "Scalable communication protocols for
186/// dynamic sparse data", ACM Sigplan Noctices 45.5, 2010.)
187///
188/// This function provides a sparse interface for personalized all-to-all communication using
189/// direct message exchange and thus achieving linear complexity in the number of messages to be sent (in
190/// contrast to \c MPI_Alltoallv which exhibits complexity (at least) linear in the size of the communicator due to its
191/// interface). To achieve this time complexity we can no longer rely on an array of size of the communicator for send
192/// counts. Instead we use a sparse representation of the data to be sent.
193///
194/// The following parameters are required:
195/// - \ref sparse_alltoall::sparse_send_buf() containing the messages to be sent to other ranks.
196/// Differently from plain alltoallv, in alltoallv_sparse \c send_buf() encapsulates a container consisting of
197/// destination-message pairs. Each such pair has to be decomposable via structured bindings with the first parameter
198/// being convertible to int and the second parameter being the actual message to be sent for which we require the usual
199/// send_buf properties (i.e., either scalar types or existance `data()` and `size()` member function and the exposure
200/// of a `value_type`)). Messages of size 0 are not sent.
201/// - \ref sparse_alltoall::on_message() containing a callback function `cb` which is responsible to
202/// process the received messages via a \ref sparse_alltoall::ProbedMessage object. The callback function `cb` gets
203/// called for each probed message ready to be received via `cb(probed_message)`. See \ref
204/// sparse_alltoall::ProbedMessage for the member functions to be called on the object.
205///
206/// The following buffers are optional:
207/// - \ref kamping::send_type() specifying the \c MPI datatype to use as send type. If omitted, the \c MPI datatype is
208/// derived automatically based on each message's underlying \c value_type.
209/// - \ref kamping::tag() the tag added to the directly exchanged messages. Defaults to the communicator's default tag
210/// (\ref Communicator::default_tag()) if not present.
211///
212/// @tparam Args Automatically deducted template parameters.
213/// @param args All required and any number of the optional parameters described above.
214template <typename Comm, template <typename...> typename DefaultContainerType>
215template <typename... Args>
217 auto& self = this->to_communicator();
218 // Get send_buf
219 using send_buf_param_type =
220 std::integral_constant<sparse_alltoall::ParameterType, sparse_alltoall::ParameterType::sparse_send_buf>;
221 auto const& dst_message_container = kamping::internal::select_parameter_type<send_buf_param_type>(args...);
223 typename std::remove_reference_t<decltype(dst_message_container.underlying())>::value_type;
224 using message_type = typename std::tuple_element_t<1, dst_message_container_type>;
225 // support message_type being a single element.
226 using message_value_type = typename kamping::internal::
227 ValueTypeWrapper<kamping::internal::has_data_member_v<message_type>, message_type>::value_type;
228
229 // Get tag
230 using default_tag_buf_type = decltype(kamping::tag(self.default_tag()));
233 default_tag_buf_type>(std::tuple(self.default_tag()), args...);
234
235 //// Get callback
237 std::integral_constant<sparse_alltoall::ParameterType, sparse_alltoall::ParameterType::on_message>;
238 auto const& on_message_cb = kamping::internal::select_parameter_type<on_message_param_type>(args...);
239
241 for (auto const& [dst, msg]: dst_message_container.underlying()) {
243
244 if (send_buf.size() > 0) {
245 int dst_ = dst; // cannot capture structured binding variable
246 int const send_count = asserting_cast<int>(send_buf.size());
247 auto callable = [&](auto... argsargs) {
248 self.issend(
249 std::move(send_buf),
252 request(request_pool.get_request()),
253 tag(tag_param.tag()),
254 std::move(argsargs)...
255 );
256 };
257 std::apply(
258 callable,
260 );
261 }
262 }
263
266 while (true) {
267 bool const got_message = self.iprobe(status_out(status), tag(tag_param.tag()));
268 if (got_message) {
270 on_message_cb.underlying()(probed_message);
271 }
272 if (!barrier_request.is_null()) {
273 if (barrier_request.test()) {
274 break;
275 }
276 } else {
277 if (request_pool.test_all()) {
278 self.ibarrier(request(barrier_request));
279 }
280 }
281 }
282 self.barrier();
283}
284
285} // namespace kamping::plugin
ParameterType
Parameter types used for the SparseAlltoall plugin.
Definition alltoall_sparse.hpp:100
auto on_message(Callback &&cb)
Generates wrapper for an callback to be called on the probed messages in SparseAlltoall::alltoallv_sp...
Definition alltoall_sparse.hpp:157
auto sparse_send_buf(Data &&data)
Generates buffer wrapper based on the data in the sparse send buffer.
Definition alltoall_sparse.hpp:140
Helper functions that make casts safer.
Wrapper for MPI communicator providing access to rank() and size() of the communicator....
Definition communicator.hpp:49
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
Wrapper for MPI request handles (aka. MPI_Request).
Definition request.hpp:145
Wrapper for MPI_Status.
Definition status.hpp:28
int tag() const
Definition status.hpp:47
int source_signed() const
Definition status.hpp:37
size_t source() const
Definition status.hpp:42
int count_signed(MPI_Datatype data_type) const
Definition status.hpp:54
A more generic version of a DataBuffer which stores an object of type.
Definition data_buffer.hpp:641
Plugin providing a sparse alltoall exchange method.
Definition alltoall_sparse.hpp:179
void alltoallv_sparse(Args... args) const
Sparse alltoall exchange using the NBX algorithm(Hoefler et al., "Scalable communication protocols fo...
Definition alltoall_sparse.hpp:216
Class encapsulating a probed message that is ready to be received in a sparse alltoall exchange.
Definition alltoall_sparse.hpp:26
ProbedMessage(Status &&status, Communicator const &comm)
Constructor of a probed message.
Definition alltoall_sparse.hpp:29
size_t source() const
Returns the source of the probed message.
Definition alltoall_sparse.hpp:90
auto recv(Args... args) const
Actually receive the probed message into a contiguous memory either provided by the user or allocated...
Definition alltoall_sparse.hpp:34
size_t recv_count(MPI_Datatype datatype=MPI_DATATYPE_NULL) const
Computes the size of the probed message depending on the used datatype.
Definition alltoall_sparse.hpp:80
int recv_count_signed(MPI_Datatype datatype=MPI_DATATYPE_NULL) const
Computes the size of the probed message depending on the used datatype.
Definition alltoall_sparse.hpp:72
int source_signed() const
Returns the source of the probed message.
Definition alltoall_sparse.hpp:85
Wrapper for MPI functions that don't require a communicator.
auto status_out()
Constructs a status object internally, which may then be retrieved from kamping::MPIResult returned b...
Definition status_parameters.hpp:43
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 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_count(int count)
Passes count as send count to the underlying call.
Definition named_parameters.hpp:321
auto recv_type_out()
Indicates to deduce the receive type in the underlying call and return it as part of underlying call'...
Definition named_parameters.hpp:1252
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 request()
Internally allocate a request object and return it to the user.
Definition named_parameters.hpp:1122
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 send_buf(internal::ignore_t< Data > ignore)
Generates a dummy send buf that wraps a nullptr.
Definition named_parameters.hpp:51
auto recv_count(int count)
Passes count as recv count to the underlying call.
Definition named_parameters.hpp:490
auto recv_type(MPI_Datatype recv_type)
Passes recv_type as recv type to the underlying call.
Definition named_parameters.hpp:1238
auto recv(Args... args) const
Definition recv.hpp:83
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
@ tag
Tag used to represent the message tag in a MPI call.
#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.
Internal namespace marking the code that is not user-facing.
Definition collectives_helpers.hpp:20
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
BufferOwnership
Enum to specify whether a buffer owns its data.
Definition data_buffer.hpp:277
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
BufferModifiability
Enum to specify whether a buffer is modifiable.
Definition data_buffer.hpp:275
STL namespace.
Some functions and types simplifying/enabling the development of wrapped MPI calls in KaMPIng.
Helper type for representing a type list.
Definition parameter_objects.hpp:326
Helper class for using CRTP for mixins. Which are used to implement kamping plugins.
Definition plugin_helpers.hpp:32
Predicate to check whether an argument provided to sparse_alltoall shall be discarded in the internal...
Definition alltoall_sparse.hpp:110
static constexpr bool discard()
Function to check whether an argument provided to SparseAlltoall::alltoallv_sparse() shall be discard...
Definition alltoall_sparse.hpp:117