TIMPI
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"
26 #include "timpi/timpi_call_mpi.h"
27 #include "timpi/message_tag.h"
28 #include "timpi/op_function.h"
29 #include "timpi/packing.h"
30 #include "timpi/timpi_assert.h"
38 #include "timpi/post_wait_work.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 
57 namespace TIMPI {
58 
60 
64 template <typename T>
65 inline void Communicator::send (const unsigned int,
66  const T &,
67  const MessageTag &) const
68 { timpi_not_implemented(); }
69 
70 template <typename T>
71 inline void Communicator::send (const unsigned int,
72  const T &,
73  Request &,
74  const MessageTag &) const
75 { timpi_not_implemented(); }
76 
77 template <typename T>
78 inline void Communicator::send (const unsigned int,
79  const T &,
80  const DataType &,
81  const MessageTag &) const
82 { timpi_not_implemented(); }
83 
84 template <typename T>
85 inline void Communicator::send (const unsigned int,
86  const T &,
87  const DataType &,
88  Request &,
89  const MessageTag &) const
90 { timpi_not_implemented(); }
91 
92 template <typename T>
93 inline void Communicator::send (const unsigned int,
94  const T &,
95  const NotADataType &,
96  Request &,
97  const MessageTag &) const
98 { timpi_not_implemented(); }
99 
100 template <typename Context, typename Iter>
101 inline void Communicator::send_packed_range(const unsigned int,
102  const Context *,
103  Iter,
104  const Iter,
105  const MessageTag &,
106  std::size_t) const
107 { timpi_not_implemented(); }
108 
109 template <typename Context, typename Iter>
110 inline 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
117 { timpi_not_implemented(); }
118 
119 template <typename Context, typename Iter>
120 inline void Communicator::nonblocking_send_packed_range (const unsigned int,
121  const Context *,
122  Iter,
123  const Iter,
124  Request &,
125  const MessageTag &) const
126 { timpi_not_implemented(); }
127 
128 template <typename Context, typename OutputIter, typename T>
129 inline void Communicator::nonblocking_receive_packed_range (const unsigned int,
130  Context *,
131  OutputIter,
132  const T *,
133  Request &,
134  Status &,
135  const MessageTag &) const
136 { timpi_not_implemented(); }
137 
141 template <typename T>
142 inline Status Communicator::receive (const unsigned int,
143  T &,
144  const MessageTag &) const
145 { timpi_not_implemented(); return Status(); }
146 
147 template <typename T>
148 inline void Communicator::receive(const unsigned int,
149  T &,
150  Request &,
151  const MessageTag &) const
152 { timpi_not_implemented(); }
153 
154 template <typename T>
155 inline Status Communicator::receive(const unsigned int,
156  T &,
157  const DataType &,
158  const MessageTag &) const
159 { timpi_not_implemented(); return Status(); }
160 
161 template <typename T>
162 inline void Communicator::receive(const unsigned int,
163  T &,
164  const DataType &,
165  Request &,
166  const MessageTag &) const
167 { timpi_not_implemented(); }
168 
169 template <typename Context, typename OutputIter, typename T>
170 inline void
171 Communicator::receive_packed_range(const unsigned int,
172  Context *,
173  OutputIter,
174  const T *,
175  const MessageTag &) const
176 { timpi_not_implemented(); }
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 
185 template <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>
189 inline 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 {
196  timpi_assert_equal_to (send_tgt, 0);
197  timpi_assert_equal_to (recv_source, 0);
198  recv_val = send_val;
199 }
200 
201 template <typename T1, typename T2, typename A1, typename A2>
202 inline
203 void Communicator::send_receive(const unsigned int timpi_dbg_var(dest_processor_id),
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 {
212  timpi_assert_equal_to (dest_processor_id, 0);
213  timpi_assert_equal_to (source_processor_id, 0);
214  recv = send;
215 }
216 
217 template <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>
221 inline
222 void Communicator::send_receive(const unsigned int timpi_dbg_var(dest_processor_id),
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 {
229  timpi_assert_equal_to (dest_processor_id, 0);
230  timpi_assert_equal_to (source_processor_id, 0);
231  recv = send;
232 }
233 
234 template <typename T, typename A,
235  typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
236  int>::type>
237 inline
238 void Communicator::send_receive(const unsigned int timpi_dbg_var(dest_processor_id),
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 {
245  timpi_assert_equal_to (dest_processor_id, 0);
246  timpi_assert_equal_to (source_processor_id, 0);
247  recv = send;
248 }
249 
250 template <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>
253 inline
254 void Communicator::send_receive(const unsigned int timpi_dbg_var(dest_processor_id),
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 {
261  timpi_assert_equal_to (dest_processor_id, 0);
262  timpi_assert_equal_to (source_processor_id, 0);
263  recv = send;
264 }
265 
266 template <typename T, typename A,
267  typename std::enable_if<Has_buffer_type<Packing<T>>::value, int>::type>
268 inline
269 void Communicator::send_receive(const unsigned int timpi_dbg_var(dest_processor_id),
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 {
276  timpi_assert_equal_to (dest_processor_id, 0);
277  timpi_assert_equal_to (source_processor_id, 0);
278  recv = send;
279 }
280 
281 template <typename T1, typename T2, typename A1, typename A2, typename A3, typename A4>
282 inline
283 void Communicator::send_receive(const unsigned int timpi_dbg_var(dest_processor_id),
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 {
290  timpi_assert_equal_to (dest_processor_id, 0);
291  timpi_assert_equal_to (source_processor_id, 0);
292  recv = send;
293 }
294 
295 template <typename T, typename A1, typename A2>
296 inline
297 void Communicator::send_receive(const unsigned int timpi_dbg_var(dest_processor_id),
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 {
304  timpi_assert_equal_to (dest_processor_id, 0);
305  timpi_assert_equal_to (source_processor_id, 0);
306  recv = send;
307 }
308 
309 
310 
311 
318 template <typename Context1, typename RangeIter,
319  typename Context2, typename OutputIter, typename T>
320 inline void
322  (const unsigned int timpi_dbg_var(dest_processor_id),
323  const Context1 * context1,
324  RangeIter send_begin,
325  const RangeIter send_end,
326  const unsigned int timpi_dbg_var(source_processor_id),
327  Context2 * context2,
328  OutputIter out_iter,
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.
336  timpi_assert_equal_to(dest_processor_id, 0);
337  timpi_assert_equal_to(source_processor_id, 0);
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 
357  const RangeIter next_send_begin = pack_range
358  (context1, send_begin, send_end, buffer);
359 
360  timpi_assert_greater (std::distance(send_begin, next_send_begin), 0);
361 
362  send_begin = next_send_begin;
363 
364  auto return_out_iter = unpack_range
365  (buffer, context2, *next_out_iter, output_type);
366  next_out_iter = std::make_unique<OutputIter>(return_out_iter);
367  }
368 }
369 
370 
371 
372 template <typename T, typename A,
373  typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value, int>::type>
374 inline 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?
381  timpi_not_implemented();
382 }
383 
384 template <typename T, typename A,
385  typename std::enable_if<Has_buffer_type<Packing<T>>::value, int>::type>
386 inline 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?
393  timpi_not_implemented();
394 }
395 
396 template <typename T, typename A1, typename A2>
397 inline
398 bool 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?
405  timpi_not_implemented();
406 }
407 
408 template <typename T, typename A>
409 inline 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 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 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: ...
OutputIter unpack_range(const std::vector< buffertype > &buffer, Context *context, OutputIter out_iter, const T *)
Helper function for range unpacking.
Definition: packing.h:1103
Encapsulates the MPI_Datatype.
Definition: data_type.h:50
Define data types and (un)serialization functions for use when encoding a potentially-variable-size o...
Definition: packing.h:60
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 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.
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.
processor_id_type size() const
Definition: communicator.h:211
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.
Encapsulates the MPI tag integers.
Definition: message_tag.h:46
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.
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
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...
StandardType<T>&#39;s which do not define a way to MPI_Type T should inherit from this class...
Definition: data_type.h:120
Encapsulates the MPI_Request.
Definition: request.h:67
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.
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...
Encapsulates the MPI_Status struct.
Definition: status.h:75