19 #ifndef TIMPI_COMMUNICATOR_H 20 #define TIMPI_COMMUNICATOR_H 28 #include "timpi/timpi_config.h" 37 #include <type_traits> 44 #include <unordered_map> 53 #if TIMPI_PROCESSOR_ID_BYTES == 1 55 #elif TIMPI_PROCESSOR_ID_BYTES == 2 57 #elif TIMPI_PROCESSOR_ID_BYTES == 4 59 #elif TIMPI_PROCESSOR_ID_BYTES == 8 64 DIE A HORRIBLE DEATH HERE...
85 static_cast<unsigned int>(MPI_ANY_SOURCE);
98 #endif // TIMPI_HAVE_MPI 210 #ifdef TIMPI_HAVE_MPI 256 template <
typename Map,
257 typename std::enable_if<std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
258 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value,
260 void map_sum(Map & data)
const;
267 template <
typename Map,
268 typename std::enable_if<!(std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
269 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value),
271 void map_sum(Map & data)
const;
277 template <
typename Map,
278 typename std::enable_if<std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
279 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value,
282 const unsigned int root_id,
283 const bool identical_sizes)
const;
291 template <
typename Map,
292 typename std::enable_if<!(std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
293 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value),
296 const unsigned int root_id,
297 const bool identical_sizes)
const;
304 template <
typename Map,
305 typename std::enable_if<std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
306 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value,
308 void map_max(Map & data)
const;
315 template <
typename Map,
316 typename std::enable_if<!(std::is_base_of<DataType, StandardType<typename Map::key_type>>::value &&
317 std::is_base_of<DataType, StandardType<typename Map::mapped_type>>::value),
319 void map_max(Map & data)
const;
323 template <
typename T,
typename A1,
typename A2>
324 std::size_t
packed_size_of(
const std::vector<std::vector<T,A1>,A2> & buf,
375 template <
typename T>
378 bool verify(
const T & r)
const;
390 template <
typename T>
399 template <
typename T>
401 void min(
const T & r, T & o,
Request & req)
const;
407 template <
typename T>
409 void min(T & r)
const;
416 template <
typename T>
419 unsigned int & min_id)
const;
426 template <
typename T,
typename A1,
typename A2>
428 void minloc(std::vector<T,A1> & r,
429 std::vector<unsigned int,A2> & min_id)
const;
435 template <
typename T>
437 void max(
const T & r, T & o,
Request & req)
const;
443 template <
typename T>
445 void max(T & r)
const;
452 template <
typename T>
455 unsigned int & max_id)
const;
462 template <
typename T,
typename A1,
typename A2>
464 void maxloc(std::vector<T,A1> & r,
465 std::vector<unsigned int,A2> & max_id)
const;
471 template <
typename T>
473 void sum(T & r)
const;
479 template <
typename T>
481 void sum(
const T & r, T & o,
Request & req)
const;
497 template <
typename T>
499 void set_union(T & data,
const unsigned int root_id)
const;
510 template <
typename T>
533 template <
typename T>
542 template <
typename T>
544 void send (
const unsigned int dest_processor_id,
551 template <
typename T>
553 void send (
const unsigned int dest_processor_id,
565 template <
typename T>
567 void send (
const unsigned int dest_processor_id,
579 template <
typename T>
581 void send (
const unsigned int dest_processor_id,
591 template <
typename T>
593 void send (
const unsigned int dest_processor_id,
602 template <
typename T>
611 template <
typename T>
613 void receive (
const unsigned int dest_processor_id,
625 template <
typename T>
639 template <
typename T>
641 void receive (
const unsigned int dest_processor_id,
665 template <
typename T,
typename A,
666 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type = 0>
669 std::vector<T,A> & buf,
681 template <
typename T,
typename A,
682 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type = 0>
685 std::vector<T,A> & buf,
703 template <
typename T,
typename A,
typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type = 0>
706 std::vector<T,A> & buf,
723 template <
typename T,
typename A,
724 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type = 0>
727 std::vector<T,A> & buf,
755 template <
typename Context,
typename OutputIter,
typename T>
759 const T * output_type,
782 template <
typename Context,
typename Iter>
785 const Context * context,
787 const Iter range_end,
789 std::size_t approx_buffer_size = 1000000)
const;
810 template <
typename Context,
typename Iter>
813 const Context * context,
815 const Iter range_end,
818 std::size_t approx_buffer_size = 1000000)
const;
828 template <
typename Context,
typename Iter>
831 const Context * context,
833 const Iter range_end,
846 template <
typename Context,
typename Iter>
849 const Context * context,
851 const Iter range_end,
853 std::shared_ptr<std::vector<
typename TIMPI::Packing<
typename std::iterator_traits<Iter>::value_type>::buffer_type>> & buffer,
882 template <
typename Context,
typename OutputIter,
typename T>
887 const T * output_type,
902 template <
typename Context,
typename OutputIter,
typename T>
907 const T * output_type,
924 template <
typename Context,
typename OutputIter,
typename T>
929 const T * output_type,
943 template <
typename T1,
typename T2,
944 typename std::enable_if<std::is_base_of<DataType, StandardType<T1>>::value &&
945 std::is_base_of<DataType, StandardType<T2>>::value,
949 const T1 & send_data,
950 const unsigned int source_processor_id,
991 template <
typename Context1,
typename RangeIter,
typename Context2,
992 typename OutputIter,
typename T>
995 const Context1 * context1,
996 RangeIter send_begin,
997 const RangeIter send_end,
998 const unsigned int source_processor_id,
1001 const T * output_type,
1004 std::size_t approx_buffer_size = 1000000)
const;
1011 template <
typename T1,
typename T2>
1013 void send_receive(
const unsigned int dest_processor_id,
1014 const T1 & send_data,
1016 const unsigned int source_processor_id,
1026 template <
typename T,
typename A>
1027 inline void gather(
const unsigned int root_id,
1028 const T & send_data,
1029 std::vector<T,A> & recv)
const;
1036 template <
typename T,
typename A>
1037 inline void gather(
const unsigned int root_id,
1038 const std::basic_string<T> & send_data,
1039 std::vector<std::basic_string<T>,A> & recv_data,
1040 const bool identical_buffer_sizes=
false)
const;
1068 template <
typename T,
typename A,
1069 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type = 0>
1070 inline void gather(
const unsigned int root_id,
1071 std::vector<T,A> & r)
const;
1073 template <
typename T,
typename A,
1074 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type = 0>
1075 inline void gather(
const unsigned int root_id,
1076 std::vector<T,A> & r)
const;
1083 template <
typename T,
typename A,
typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
1085 inline void allgather(
const T & send_data,
1086 std::vector<T,A> & recv_data)
const;
1094 template <
typename T,
typename A,
typename std::enable_if<Has_buffer_type<Packing<T>>::value,
1096 inline void allgather(
const T & send_data,
1097 std::vector<T,A> & recv_data)
const;
1104 template <
typename T,
typename A>
1105 inline void allgather(
const std::basic_string<T> & send_data,
1106 std::vector<std::basic_string<T>,A> & recv_data,
1107 const bool identical_buffer_sizes=
false)
const;
1133 template <
typename T,
typename A,
1134 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type = 0>
1135 inline void allgather(std::vector<T,A> & r,
1136 const bool identical_buffer_sizes =
false)
const;
1145 template <
typename T,
typename A1,
typename A2,
1146 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type = 0>
1147 inline void allgather(
const std::vector<T,A1> & send_data,
1148 std::vector<std::vector<T,A1>, A2> & recv_data,
1149 const bool identical_buffer_sizes =
false)
const;
1155 template <
typename T,
typename A1,
typename A2,
1156 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type = 0>
1157 inline void allgather(
const std::vector<T,A1> & send_data,
1158 std::vector<std::vector<T,A1>, A2> & recv_data,
1159 const bool identical_buffer_sizes =
false)
const;
1185 template <
typename T,
typename A,
1186 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type = 0>
1187 inline void allgather(std::vector<T,A> & r,
1188 const bool identical_buffer_sizes =
false)
const;
1193 template <
typename T,
typename A>
1194 inline void allgather(std::vector<std::basic_string<T>,A> & r,
1195 const bool identical_buffer_sizes =
false)
const;
1202 template <
typename T,
typename A>
1203 inline void scatter(
const std::vector<T,A> & data,
1205 const unsigned int root_id=0)
const;
1213 template <
typename T,
typename A>
1214 inline void scatter(
const std::vector<T,A> & data,
1215 std::vector<T,A> & recv,
1216 const unsigned int root_id=0)
const;
1224 template <
typename T,
typename A1,
typename A2>
1225 inline void scatter(
const std::vector<T,A1> & data,
1226 const std::vector<CountType,A2> counts,
1227 std::vector<T,A1> & recv,
1228 const unsigned int root_id=0)
const;
1230 #ifdef TIMPI_HAVE_MPI 1235 template <
typename T,
typename A1,
typename A2>
1236 inline void scatter(
const std::vector<T,A1> & data,
1237 const std::vector<int,A2> counts,
1238 std::vector<T,A1> & recv,
1239 const unsigned int root_id=0)
const;
1248 template <
typename T,
typename A1,
typename A2>
1249 inline void scatter(
const std::vector<std::vector<T,A1>,A2> & data,
1250 std::vector<T,A1> & recv,
1251 const unsigned int root_id=0,
1252 const bool identical_buffer_sizes=
false)
const;
1270 template <
typename Context,
typename Iter,
typename OutputIter>
1274 const Iter range_end,
1276 std::size_t approx_buffer_size = 1000000)
const;
1293 template <
typename Context,
typename Iter,
typename OutputIter>
1296 const Iter range_end,
1298 std::size_t approx_buffer_size = 1000000)
const;
1305 template <
typename T,
typename A>
1306 inline void alltoall(std::vector<T,A> & r)
const;
1319 template <
typename T
1320 #ifdef TIMPI_HAVE_MPI 1322 typename std::enable_if<std::is_base_of<DataType, StandardType<T>>::value,
int>::type = 0
1325 inline void broadcast(T & data,
const unsigned int root_id=0,
1326 const bool identical_sizes=
false)
const;
1328 #ifdef TIMPI_HAVE_MPI 1340 template <
typename T,
1341 typename std::enable_if<Has_buffer_type<Packing<T>>::value,
int>::type = 0>
1342 inline void broadcast(T & data,
const unsigned int root_id=0,
1343 const bool identical_sizes=
false)
const;
1369 template <
typename Context,
typename OutputContext,
typename Iter,
typename OutputIter>
1372 const Iter range_end,
1373 OutputContext * context2,
1375 const unsigned int root_id = 0,
1376 std::size_t approx_buffer_size = 1000000)
const;
1385 #include "timpi/parallel_communicator_specializations" 1395 namespace Parallel {
1409 #endif // TIMPI_COMMUNICATOR_H void gather_packed_range(const unsigned int root_id, Context *context, Iter range_begin, const Iter range_end, OutputIter out, std::size_t approx_buffer_size=1000000) const
Take a range of local variables, combine it with ranges from all processors, and write the output to ...
void send_mode(const SendMode sm)
Explicitly sets the SendMode type used for send operations.
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: ...
void broadcast_packed_range(const Context *context1, Iter range_begin, const Iter range_end, OutputContext *context2, OutputIter out, const unsigned int root_id=0, std::size_t approx_buffer_size=1000000) const
Blocking-broadcast range-of-pointers to one processor.
Status packed_range_probe(const unsigned int src_processor_id, const MessageTag &tag, bool &flag) const
Non-Blocking message probe for a packed range message.
void scatter(const std::vector< T, A > &data, T &recv, const unsigned int root_id=0) const
Take a vector of local variables and scatter the ith item to the ith processor in the communicator...
communicator _communicator
void sync_type(const SyncType st)
Explicitly sets the SyncType used for sync operations.
MPI_Info info
Info object used by some MPI-3 methods.
void map_max(Map &data) const
Private implementation function called by the map-based max() specializations.
std::map< int, unsigned int > used_tag_values
void minloc(T &r, unsigned int &min_id) const
Take a local variable and replace it with the minimum of it's values on all processors, returning the minimum rank of a processor which originally held the minimum value.
void gather(const unsigned int root_id, const T &send_data, std::vector< T, A > &recv) const
Take a vector of length comm.size(), and on processor root_id fill in recv[processor_id] = the value ...
MessageTag get_unique_tag(int tagvalue=MessageTag::invalid_tag) const
Get a tag that is unique to this Communicator.
const MessageTag any_tag
Default message tag ids.
void sum(T &r) const
Take a local variable and replace it with the sum of it's values on all processors.
void alltoall(std::vector< T, A > &r) const
Effectively transposes the input vector across all processors.
void barrier() const
Pause execution until all processors reach a certain point.
processor_id_type rank() const
SyncType sync_type() const
Gets the user-requested SyncType.
Encapsulates the MPI_Datatype.
void allgather_packed_range(Context *context, Iter range_begin, const Iter range_end, OutputIter out, std::size_t approx_buffer_size=1000000) const
Take a range of local variables, combine it with ranges from all processors, and write the output to ...
void map_broadcast(Map &data, const unsigned int root_id, const bool identical_sizes) const
Private implementation function called by the map-based broadcast() specializations.
void clear()
Free and reset this communicator.
void assign(const communicator &comm)
Utility function for setting our member variables from an MPI communicator.
Define data types and (un)serialization functions for use when encoding a potentially-variable-size o...
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.
Communicator(const TIMPI::communicator &comm)
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.
const unsigned int any_source
Processor id meaning "Accept from any source".
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.
Encapsulates the MPI_Comm object.
processor_id_type size() const
std::size_t packed_size_of(const std::vector< std::vector< T, A1 >, A2 > &buf, const DataType &type) const
uint8_t processor_id_type
SendMode
Whether to use default or synchronous sends?
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.
static const int invalid_tag
Invalid tag, to allow for default construction.
Encapsulates the MPI tag integers.
void min(const T &r, T &o, Request &req) const
Non-blocking minimum of the local value r into o with the request req.
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.
constexpr processor_id_type size() const
status probe(const unsigned int src_processor_id, const MessageTag &tag=any_tag) const
Blocking message probe.
void split(int color, int key, Communicator &target) const
Communicator & operator=(const Communicator &)=delete
SyncType
What algorithm to use for parallel synchronization?
void maxloc(T &r, unsigned int &max_id) const
Take a local variable and replace it with the maximum of it's values on all processors, returning the minimum rank of a processor which originally held the maximum value.
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_packed_range(unsigned int &src_processor_id, Context *context, OutputIter out, const T *output_type, Request &req, const MessageTag &tag) const
Nonblocking packed range receive from one processor with user-defined type.
timpi_pure bool semiverify(const T *r) const
Check whether a local pointer points to the same value on all processors where it is not null...
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
Take a local value and broadcast it to all processors.
StandardType<T>'s which do not define a way to MPI_Type T should inherit from this class...
void split_by_type(int split_type, int key, info i, Communicator &target) const
void map_sum(Map &data) const
Private implementation function called by the map-based sum() specializations.
Encapsulates the MPI_Request.
Communicator & operator=(const Communicator &)=delete
timpi_pure bool verify(const T &r) const
Check whether a local variable has the same value on all processors, returning true if it does or fal...
void max(const T &r, T &o, Request &req) const
Non-blocking maximum of the local value r into o with the request req.
DIE A HORRIBLE DEATH HERE typedef MPI_Comm communicator
Communicator object for talking with subsets of processors.
Communicator()
Default Constructor.
void dereference_unique_tag(int tagvalue) const
Dereference an already-acquired tag, and see if we can re-release it.
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.
SendMode send_mode() const
Gets the user-requested SendMode.
void reference_unique_tag(int tagvalue) const
Reference an already-acquired tag, so that we know it will be dereferenced multiple times before we c...
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.
void duplicate(const Communicator &comm)
void nonblocking_barrier(Request &req) const
Start a barrier that doesn't block.
void set_union(T &data, const unsigned int root_id) const
Take a container (set, map, unordered_set, multimap, etc) of local variables on each processor...