TIMPI
Loading...
Searching...
No Matches
serial_implementation.h
Go to the documentation of this file.
1// The TIMPI Message-Passing Parallelism Library.
2// Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19#ifndef TIMPI_SERIAL_IMPLEMENTATION_H
20#define TIMPI_SERIAL_IMPLEMENTATION_H
21
22// TIMPI includes
23#include "timpi/attributes.h"
24#include "timpi/communicator.h"
25#include "timpi/data_type.h"
27#include "timpi/message_tag.h"
28#include "timpi/op_function.h"
29#include "timpi/packing.h"
30#include "timpi/timpi_assert.h"
39#include "timpi/request.h"
40#include "timpi/status.h"
41#include "timpi/standard_type.h"
42
43// Disable libMesh logging until we decide how to port it best
44// #include "libmesh/libmesh_logging.h"
45#define TIMPI_LOG_SCOPE(f,c)
46
47// C++ includes
48#include <cstddef>
49#include <iterator>
50#include <memory>
51#include <utility>
52#include <vector>
53#include <type_traits>
54
55#ifndef TIMPI_HAVE_MPI
56
57namespace TIMPI {
58
60
64template <typename T>
65inline void Communicator::send (const unsigned int,
66 const T &,
67 const MessageTag &) const
69
70template <typename T>
71inline void Communicator::send (const unsigned int,
72 const T &,
73 Request &,
74 const MessageTag &) const
76
77template <typename T>
78inline void Communicator::send (const unsigned int,
79 const T &,
80 const DataType &,
81 const MessageTag &) const
83
84template <typename T>
85inline void Communicator::send (const unsigned int,
86 const T &,
87 const DataType &,
88 Request &,
89 const MessageTag &) const
91
92template <typename T>
93inline void Communicator::send (const unsigned int,
94 const T &,
95 const NotADataType &,
96 Request &,
97 const MessageTag &) const
99
100template <typename Context, typename Iter>
101inline void Communicator::send_packed_range(const unsigned int,
102 const Context *,
103 Iter,
104 const Iter,
105 const MessageTag &,
106 std::size_t) const
108
109template <typename Context, typename Iter>
110inline void Communicator::send_packed_range (const unsigned int,
111 const Context *,
112 Iter,
113 const Iter,
114 Request &,
115 const MessageTag &,
116 std::size_t) const
118
119template <typename Context, typename Iter>
120inline void Communicator::nonblocking_send_packed_range (const unsigned int,
121 const Context *,
122 Iter,
123 const Iter,
124 Request &,
125 const MessageTag &) const
127
128template <typename Context, typename OutputIter, typename T>
129inline void Communicator::nonblocking_receive_packed_range (const unsigned int,
130 Context *,
132 const T *,
133 Request &,
134 Status &,
135 const MessageTag &) const
137
141template <typename T>
142inline Status Communicator::receive (const unsigned int,
143 T &,
144 const MessageTag &) const
145{ timpi_not_implemented(); return Status(); }
146
147template <typename T>
148inline void Communicator::receive(const unsigned int,
149 T &,
150 Request &,
151 const MessageTag &) const
153
154template <typename T>
155inline Status Communicator::receive(const unsigned int,
156 T &,
157 const DataType &,
158 const MessageTag &) const
159{ timpi_not_implemented(); return Status(); }
160
161template <typename T>
162inline void Communicator::receive(const unsigned int,
163 T &,
164 const DataType &,
165 Request &,
166 const MessageTag &) const
168
169template <typename Context, typename OutputIter, typename T>
170inline void
171Communicator::receive_packed_range(const unsigned int,
172 Context *,
174 const T *,
175 const MessageTag &) const
177
178// template <typename Context, typename OutputIter>
179// inline void Communicator::receive_packed_range(const unsigned int, Context *, OutputIter, Request &, const MessageTag &) const
180// { timpi_not_implemented(); }
181
185template <typename T1, typename T2,
186 typename std::enable_if<std::is_base_of<DataType, StandardType<T1>>::value &&
187 std::is_base_of<DataType, StandardType<T2>>::value,
188 int>::type>
189inline void Communicator::send_receive (const unsigned int timpi_dbg_var(send_tgt),
190 const T1 & send_val,
191 const unsigned int timpi_dbg_var(recv_source),
192 T2 & recv_val,
193 const MessageTag &,
194 const MessageTag &) const
195{
199}
200
201template <typename T1, typename T2, typename A1, typename A2>
202inline
204 const std::vector<T1,A1> & send,
205 const DataType &,
206 const unsigned int timpi_dbg_var(source_processor_id),
207 std::vector<T2,A2> &recv,
208 const DataType &,
209 const MessageTag &,
210 const MessageTag &) const
211{
214 recv = send;
215}
216
217template <typename T1, typename T2, typename A1, typename A2,
218 typename std::enable_if<std::is_base_of<DataType, StandardType<T1>>::value &&
219 std::is_base_of<DataType, StandardType<T2>>::value,
220 int>::type>
221inline
223 const std::vector<T1,A1> & send,
224 const unsigned int timpi_dbg_var(source_processor_id),
225 std::vector<T2,A2> &recv,
226 const MessageTag &,
227 const MessageTag &) const
228{
231 recv = send;
232}
233
234template <typename T, typename A,
235 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
236 int>::type>
237inline
239 const std::vector<T,A> & send,
240 const unsigned int timpi_dbg_var(source_processor_id),
241 std::vector<T,A> &recv,
242 const MessageTag &,
243 const MessageTag &) const
244{
247 recv = send;
248}
249
250template <typename T1, typename T2, typename A1, typename A2,
251 typename std::enable_if<Has_buffer_type<Packing<T1>>::value &&
252 Has_buffer_type<Packing<T2>>::value, int>::type>
253inline
255 const std::vector<T1,A1> & send,
256 const unsigned int timpi_dbg_var(source_processor_id),
257 std::vector<T2,A2> &recv,
258 const MessageTag &,
259 const MessageTag &) const
260{
263 recv = send;
264}
265
266template <typename T, typename A,
267 typename std::enable_if<Has_buffer_type<Packing<T>>::value, int>::type>
268inline
270 const std::vector<T,A> & send,
271 const unsigned int timpi_dbg_var(source_processor_id),
272 std::vector<T,A> &recv,
273 const MessageTag &,
274 const MessageTag &) const
275{
278 recv = send;
279}
280
281template <typename T1, typename T2, typename A1, typename A2, typename A3, typename A4>
282inline
284 const std::vector<std::vector<T1,A1>,A2> & send,
285 const unsigned int timpi_dbg_var(source_processor_id),
286 std::vector<std::vector<T2,A3>,A4> &recv,
287 const MessageTag &,
288 const MessageTag &) const
289{
292 recv = send;
293}
294
295template <typename T, typename A1, typename A2>
296inline
298 const std::vector<std::vector<T,A1>,A2> & send,
299 const unsigned int timpi_dbg_var(source_processor_id),
300 std::vector<std::vector<T,A1>,A2> &recv,
301 const MessageTag &,
302 const MessageTag &) const
303{
306 recv = send;
307}
308
309
310
311
318template <typename Context1, typename RangeIter,
319 typename Context2, typename OutputIter, typename T>
320inline void
322 (const unsigned int timpi_dbg_var(dest_processor_id),
323 const Context1 * context1,
325 const RangeIter send_end,
326 const unsigned int timpi_dbg_var(source_processor_id),
329 const T * output_type,
330 const MessageTag &,
331 const MessageTag &,
332 std::size_t) const
333{
334 // This makes no sense on one processor unless we're deliberately
335 // sending to ourself.
338
339 // On one processor, we just need to pack the range and then unpack
340 // it again.
341 typedef typename std::iterator_traits<RangeIter>::value_type T1;
342 typedef typename Packing<T1>::buffer_type buffer_t;
343
344 // OutputIter might not have operator= implemented; for maximum
345 // compatibility we'll rely on its copy constructor.
346 std::unique_ptr<OutputIter> next_out_iter =
347 std::make_unique<OutputIter>(out_iter);
348
349 while (send_begin != send_end)
350 {
351 timpi_assert_greater (std::distance(send_begin, send_end), 0);
352
353 // We will serialize variable size objects from *range_begin to
354 // *range_end as a sequence of ints in this buffer
355 std::vector<buffer_t> buffer;
356
359
361
363
366 next_out_iter = std::make_unique<OutputIter>(return_out_iter);
367 }
368}
369
370
371
372template <typename T, typename A,
373 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value, int>::type>
374inline bool Communicator::possibly_receive (unsigned int &,
375 std::vector<T,A> &,
376 const DataType &,
377 Request &,
378 const MessageTag &) const
379{
380 // Non-blocking I/O from self to self?
382}
383
384template <typename T, typename A,
385 typename std::enable_if<Has_buffer_type<Packing<T>>::value, int>::type>
386inline bool Communicator::possibly_receive (unsigned int &,
387 std::vector<T,A> &,
388 const NotADataType &,
389 Request &,
390 const MessageTag &) const
391{
392 // Non-blocking I/O from self to self?
394}
395
396template <typename T, typename A1, typename A2>
397inline
398bool Communicator::possibly_receive (unsigned int &,
399 std::vector<std::vector<T,A1>,A2> &,
400 const DataType &,
401 Request &,
402 const MessageTag &) const
403{
404 // Non-blocking I/O from self to self?
406}
407
408template <typename T, typename A>
409inline void Communicator::allgather(const std::basic_string<T> & sendval,
410 std::vector<std::basic_string<T>,A> & recv,
411 const bool /*identical_buffer_sizes*/) const
412{
413 timpi_assert(this->size() == 1);
414
415 recv.resize(1);
416 recv[0] = sendval;
417}
418
419} // namespace TIMPI
420
421#endif // ifndef TIMPI_HAVE_MPI
422
423#endif // TIMPI_SERIAL_IMPLEMENTATION_H
void nonblocking_receive_packed_range(const unsigned int src_processor_id, Context *context, OutputIter out, const T *output_type, Request &req, Status &stat, const MessageTag &tag=any_tag) const
Non-Blocking-receive range-of-pointers from one processor.
processor_id_type size() const
void receive_packed_range(const unsigned int dest_processor_id, Context *context, OutputIter out, const T *output_type, const MessageTag &tag=any_tag) const
Blocking-receive range-of-pointers from one processor.
void nonblocking_send_packed_range(const unsigned int dest_processor_id, const Context *context, Iter range_begin, const Iter range_end, Request &req, const MessageTag &tag=no_tag) const
Similar to the above Nonblocking send_packed_range with a few important differences:
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
Blocking-receive from one processor with data-defined type.
void send_receive(const unsigned int dest_processor_id, const T1 &send_data, const unsigned int source_processor_id, T2 &recv_data, const MessageTag &send_tag=no_tag, const MessageTag &recv_tag=any_tag) const
Send data send to one processor while simultaneously receiving other data recv from a (potentially di...
bool possibly_receive(unsigned int &src_processor_id, std::vector< T, A > &buf, Request &req, const MessageTag &tag) const
Nonblocking-receive from one processor with user-defined type.
void send_packed_range(const unsigned int dest_processor_id, const Context *context, Iter range_begin, const Iter range_end, const MessageTag &tag=no_tag, std::size_t approx_buffer_size=1000000) const
Blocking-send range-of-pointers to one processor.
void send_receive_packed_range(const unsigned int dest_processor_id, const Context1 *context1, RangeIter send_begin, const RangeIter send_end, const unsigned int source_processor_id, Context2 *context2, OutputIter out, const T *output_type, const MessageTag &send_tag=no_tag, const MessageTag &recv_tag=any_tag, std::size_t approx_buffer_size=1000000) const
Send a range-of-pointers to one processor while simultaneously receiving another range from a (potent...
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
Take a vector of length this->size(), and fill in recv[processor_id] = the value of send on that proc...
void send(const unsigned int dest_processor_id, const T &buf, const MessageTag &tag=no_tag) const
Blocking-send to one processor with data-defined type.
Encapsulates the MPI_Datatype.
Definition data_type.h:51
Encapsulates the MPI tag integers.
Definition message_tag.h:47
StandardType<T>'s which do not define a way to MPI_Type T should inherit from this class.
Definition data_type.h:121
Encapsulates the MPI_Request.
Definition request.h:68
Encapsulates the MPI_Status struct.
Definition status.h:76
Define data types and (un)serialization functions for use when encoding a potentially-variable-size o...
Definition packing.h:60
Iter pack_range(const Context *context, Iter range_begin, const Iter range_end, std::vector< buffertype > &buffer, std::size_t approx_buffer_size)
Helper function for range packing.
Definition packing.h:1044
Tnew cast_int(Told oldvar)
OutputIter unpack_range(const std::vector< buffertype > &buffer, Context *context, OutputIter out_iter, const T *)
Helper function for range unpacking.
Definition packing.h:1103