Ginkgo  Generated from pipelines/3035309441 branch based on develop. Ginkgo version 2.0.0
A numerical linear algebra library targeting many-core architectures
mpi.hpp
1 // SPDX-FileCopyrightText: 2017 - 2026 The Ginkgo authors
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #ifndef GKO_PUBLIC_CORE_BASE_MPI_HPP_
6 #define GKO_PUBLIC_CORE_BASE_MPI_HPP_
7 
8 
9 #include <memory>
10 #include <type_traits>
11 #include <utility>
12 
13 #include <ginkgo/config.hpp>
14 #include <ginkgo/core/base/exception.hpp>
15 #include <ginkgo/core/base/exception_helpers.hpp>
16 #include <ginkgo/core/base/executor.hpp>
17 #include <ginkgo/core/base/half.hpp>
18 #include <ginkgo/core/base/types.hpp>
19 #include <ginkgo/core/base/utils_helper.hpp>
20 
21 
22 #if GINKGO_BUILD_MPI
23 
24 
25 #include <mpi.h>
26 
27 
28 namespace gko {
29 namespace experimental {
35 namespace mpi {
36 
37 
41 inline constexpr bool is_gpu_aware()
42 {
43 #if GINKGO_HAVE_GPU_AWARE_MPI
44  return true;
45 #else
46  return false;
47 #endif
48 }
49 
50 
58 int map_rank_to_device_id(MPI_Comm comm, int num_devices);
59 
60 
61 #define GKO_REGISTER_MPI_TYPE(input_type, mpi_type) \
62  template <> \
63  struct type_impl<input_type> { \
64  static MPI_Datatype get_type() { return mpi_type; } \
65  }
66 
75 template <typename T>
76 struct type_impl {};
77 
78 
79 GKO_REGISTER_MPI_TYPE(char, MPI_CHAR);
80 GKO_REGISTER_MPI_TYPE(unsigned char, MPI_UNSIGNED_CHAR);
81 GKO_REGISTER_MPI_TYPE(unsigned, MPI_UNSIGNED);
82 GKO_REGISTER_MPI_TYPE(int, MPI_INT);
83 GKO_REGISTER_MPI_TYPE(unsigned short, MPI_UNSIGNED_SHORT);
84 GKO_REGISTER_MPI_TYPE(unsigned long, MPI_UNSIGNED_LONG);
85 GKO_REGISTER_MPI_TYPE(long, MPI_LONG);
86 GKO_REGISTER_MPI_TYPE(long long, MPI_LONG_LONG_INT);
87 GKO_REGISTER_MPI_TYPE(unsigned long long, MPI_UNSIGNED_LONG_LONG);
88 GKO_REGISTER_MPI_TYPE(float, MPI_FLOAT);
89 GKO_REGISTER_MPI_TYPE(double, MPI_DOUBLE);
90 GKO_REGISTER_MPI_TYPE(long double, MPI_LONG_DOUBLE);
91 #if GINKGO_ENABLE_HALF
92 // OpenMPI 5.0 have support from MPIX_C_FLOAT16 and MPICHv3.4a1 MPIX_C_FLOAT16
93 // Only OpenMPI support complex float16
94 // TODO: use native type when mpi is configured with half feature
95 GKO_REGISTER_MPI_TYPE(half, MPI_UNSIGNED_SHORT);
96 GKO_REGISTER_MPI_TYPE(std::complex<half>, MPI_FLOAT);
97 #endif // GKO_ENABLE_HALF
98 #if GINKGO_ENABLE_BFLOAT16
99 GKO_REGISTER_MPI_TYPE(bfloat16, MPI_UNSIGNED_SHORT);
100 GKO_REGISTER_MPI_TYPE(std::complex<bfloat16>, MPI_FLOAT);
101 #endif // GKO_ENABLE_BFLOAT16
102 GKO_REGISTER_MPI_TYPE(std::complex<float>, MPI_C_FLOAT_COMPLEX);
103 GKO_REGISTER_MPI_TYPE(std::complex<double>, MPI_C_DOUBLE_COMPLEX);
104 
105 
113 public:
120  contiguous_type(int count, MPI_Datatype old_type) : type_(MPI_DATATYPE_NULL)
121  {
122  GKO_ASSERT_NO_MPI_ERRORS(MPI_Type_contiguous(count, old_type, &type_));
123  GKO_ASSERT_NO_MPI_ERRORS(MPI_Type_commit(&type_));
124  }
125 
129  contiguous_type() : type_(MPI_DATATYPE_NULL) {}
130 
134  contiguous_type(const contiguous_type&) = delete;
135 
139  contiguous_type& operator=(const contiguous_type&) = delete;
140 
146  contiguous_type(contiguous_type&& other) noexcept : type_(MPI_DATATYPE_NULL)
147  {
148  *this = std::move(other);
149  }
150 
159  {
160  if (this != &other) {
161  this->type_ = std::exchange(other.type_, MPI_DATATYPE_NULL);
162  }
163  return *this;
164  }
165 
170  {
171  if (type_ != MPI_DATATYPE_NULL) {
172  MPI_Type_free(&type_);
173  }
174  }
175 
181  MPI_Datatype get() const { return type_; }
182 
183 private:
184  MPI_Datatype type_;
185 };
186 
187 
192 enum class thread_type {
193  serialized = MPI_THREAD_SERIALIZED,
194  funneled = MPI_THREAD_FUNNELED,
195  single = MPI_THREAD_SINGLE,
196  multiple = MPI_THREAD_MULTIPLE
197 };
198 
199 
209 class environment {
210 public:
211  static bool is_finalized()
212  {
213  int flag = 0;
214  GKO_ASSERT_NO_MPI_ERRORS(MPI_Finalized(&flag));
215  return flag;
216  }
217 
218  static bool is_initialized()
219  {
220  int flag = 0;
221  GKO_ASSERT_NO_MPI_ERRORS(MPI_Initialized(&flag));
222  return flag;
223  }
224 
230  int get_provided_thread_support() const { return provided_thread_support_; }
231 
240  environment(int& argc, char**& argv,
241  const thread_type thread_t = thread_type::serialized)
242  {
243  this->required_thread_support_ = static_cast<int>(thread_t);
244  GKO_ASSERT_NO_MPI_ERRORS(
245  MPI_Init_thread(&argc, &argv, this->required_thread_support_,
246  &(this->provided_thread_support_)));
247  }
248 
252  ~environment() { MPI_Finalize(); }
253 
254  environment(const environment&) = delete;
255  environment(environment&&) = delete;
256  environment& operator=(const environment&) = delete;
257  environment& operator=(environment&&) = delete;
258 
259 private:
260  int required_thread_support_;
261  int provided_thread_support_;
262 };
263 
264 
265 namespace detail {
266 
267 
272 class comm_deleter {
273 public:
274  using pointer = MPI_Comm*;
275  void operator()(pointer comm) const
276  {
277  GKO_ASSERT(*comm != MPI_COMM_NULL);
278  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_free(comm));
279  delete comm;
280  }
281 };
282 
283 
284 } // namespace detail
285 
286 
290 struct status {
294  status() : status_(MPI_Status{}) {}
295 
301  MPI_Status* get() { return &this->status_; }
302 
313  template <typename T>
314  int get_count(const T* data) const
315  {
316  int count;
317  MPI_Get_count(&status_, type_impl<T>::get_type(), &count);
318  return count;
319  }
320 
321 private:
322  MPI_Status status_;
323 };
324 
325 
330 class request {
331 public:
336  request() : req_(MPI_REQUEST_NULL) {}
337 
338  request(const request&) = delete;
339 
340  request& operator=(const request&) = delete;
341 
342  request(request&& o) noexcept { *this = std::move(o); }
343 
344  request& operator=(request&& o) noexcept
345  {
346  if (this != &o) {
347  this->req_ = std::exchange(o.req_, MPI_REQUEST_NULL);
348  }
349  return *this;
350  }
351 
352  ~request()
353  {
354  if (req_ != MPI_REQUEST_NULL) {
355  if (MPI_Request_free(&req_) != MPI_SUCCESS) {
356  std::terminate(); // since we can't throw in destructors, we
357  // have to terminate the program
358  }
359  }
360  }
361 
367  MPI_Request* get() { return &this->req_; }
368 
376  {
377  status status;
378  GKO_ASSERT_NO_MPI_ERRORS(MPI_Wait(&req_, status.get()));
379  return status;
380  }
381 
382 private:
383  MPI_Request req_;
384 };
385 
386 
394 inline std::vector<status> wait_all(std::vector<request>& req)
395 {
396  std::vector<status> stat;
397  for (std::size_t i = 0; i < req.size(); ++i) {
398  stat.emplace_back(req[i].wait());
399  }
400  return stat;
401 }
402 
403 
419 public:
430  communicator(const MPI_Comm& comm, bool force_host_buffer = false)
431  : comm_(), force_host_buffer_(force_host_buffer)
432  {
433  this->comm_.reset(new MPI_Comm(comm));
434  }
435 
444  communicator(const MPI_Comm& comm, int color, int key)
445  : force_host_buffer_(false)
446  {
447  MPI_Comm comm_out;
448  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_split(comm, color, key, &comm_out));
449  this->comm_.reset(new MPI_Comm(comm_out), detail::comm_deleter{});
450  }
451 
460  communicator(const communicator& comm, int color, int key)
461  : force_host_buffer_(comm.force_host_buffer())
462  {
463  MPI_Comm comm_out;
464  GKO_ASSERT_NO_MPI_ERRORS(
465  MPI_Comm_split(comm.get(), color, key, &comm_out));
466  this->comm_.reset(new MPI_Comm(comm_out), detail::comm_deleter{});
467  }
468 
478  static communicator create_owning(const MPI_Comm& comm,
479  bool force_host_buffer = false)
480  {
481  communicator comm_out(MPI_COMM_NULL, force_host_buffer);
482  comm_out.comm_.reset(new MPI_Comm(comm), detail::comm_deleter{});
483  return comm_out;
484  }
485 
491  communicator(const communicator& other) = default;
492 
499  communicator(communicator&& other) { *this = std::move(other); }
500 
504  communicator& operator=(const communicator& other) = default;
505 
510  {
511  if (this != &other) {
512  comm_ = std::exchange(other.comm_,
513  std::make_shared<MPI_Comm>(MPI_COMM_NULL));
514  force_host_buffer_ = other.force_host_buffer_;
515  }
516  return *this;
517  }
518 
524  const MPI_Comm& get() const { return *(this->comm_.get()); }
525 
526  bool force_host_buffer() const { return force_host_buffer_; }
527 
533  int size() const { return get_num_ranks(); }
534 
540  int rank() const { return get_my_rank(); };
541 
547  int node_local_rank() const { return get_node_local_rank(); };
548 
554  bool operator==(const communicator& rhs) const { return is_identical(rhs); }
555 
561  bool operator!=(const communicator& rhs) const { return !(*this == rhs); }
562 
572  bool is_identical(const communicator& rhs) const
573  {
574  if (get() == MPI_COMM_NULL || rhs.get() == MPI_COMM_NULL) {
575  return get() == rhs.get();
576  }
577  int flag;
578  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_compare(get(), rhs.get(), &flag));
579  return flag == MPI_IDENT;
580  }
581 
594  bool is_congruent(const communicator& rhs) const
595  {
596  if (get() == MPI_COMM_NULL || rhs.get() == MPI_COMM_NULL) {
597  return get() == rhs.get();
598  }
599  int flag;
600  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_compare(get(), rhs.get(), &flag));
601  return flag == MPI_CONGRUENT;
602  }
603 
608  void synchronize() const
609  {
610  GKO_ASSERT_NO_MPI_ERRORS(MPI_Barrier(this->get()));
611  }
612 
626  template <typename SendType>
627  void send(std::shared_ptr<const Executor> exec, const SendType* send_buffer,
628  const int send_count, const int destination_rank,
629  const int send_tag) const
630  {
631  auto guard = exec->get_scoped_device_id_guard();
632  GKO_ASSERT_NO_MPI_ERRORS(
633  MPI_Send(send_buffer, send_count, type_impl<SendType>::get_type(),
634  destination_rank, send_tag, this->get()));
635  }
636 
653  template <typename SendType>
654  request i_send(std::shared_ptr<const Executor> exec,
655  const SendType* send_buffer, const int send_count,
656  const int destination_rank, const int send_tag) const
657  {
658  auto guard = exec->get_scoped_device_id_guard();
659  request req;
660  GKO_ASSERT_NO_MPI_ERRORS(
661  MPI_Isend(send_buffer, send_count, type_impl<SendType>::get_type(),
662  destination_rank, send_tag, this->get(), req.get()));
663  return req;
664  }
665 
681  template <typename RecvType>
682  status recv(std::shared_ptr<const Executor> exec, RecvType* recv_buffer,
683  const int recv_count, const int source_rank,
684  const int recv_tag) const
685  {
686  auto guard = exec->get_scoped_device_id_guard();
687  status st;
688  GKO_ASSERT_NO_MPI_ERRORS(
689  MPI_Recv(recv_buffer, recv_count, type_impl<RecvType>::get_type(),
690  source_rank, recv_tag, this->get(), st.get()));
691  return st;
692  }
693 
709  template <typename RecvType>
710  request i_recv(std::shared_ptr<const Executor> exec, RecvType* recv_buffer,
711  const int recv_count, const int source_rank,
712  const int recv_tag) const
713  {
714  auto guard = exec->get_scoped_device_id_guard();
715  request req;
716  GKO_ASSERT_NO_MPI_ERRORS(
717  MPI_Irecv(recv_buffer, recv_count, type_impl<RecvType>::get_type(),
718  source_rank, recv_tag, this->get(), req.get()));
719  return req;
720  }
721 
734  template <typename BroadcastType>
735  void broadcast(std::shared_ptr<const Executor> exec, BroadcastType* buffer,
736  int count, int root_rank) const
737  {
738  auto guard = exec->get_scoped_device_id_guard();
739  GKO_ASSERT_NO_MPI_ERRORS(MPI_Bcast(buffer, count,
741  root_rank, this->get()));
742  }
743 
759  template <typename BroadcastType>
760  request i_broadcast(std::shared_ptr<const Executor> exec,
761  BroadcastType* buffer, int count, int root_rank) const
762  {
763  auto guard = exec->get_scoped_device_id_guard();
764  request req;
765  GKO_ASSERT_NO_MPI_ERRORS(
766  MPI_Ibcast(buffer, count, type_impl<BroadcastType>::get_type(),
767  root_rank, this->get(), req.get()));
768  return req;
769  }
770 
786  template <typename ReduceType>
787  void reduce(std::shared_ptr<const Executor> exec,
788  const ReduceType* send_buffer, ReduceType* recv_buffer,
789  int count, MPI_Op operation, int root_rank) const
790  {
791  auto guard = exec->get_scoped_device_id_guard();
792  GKO_ASSERT_NO_MPI_ERRORS(MPI_Reduce(send_buffer, recv_buffer, count,
794  operation, root_rank, this->get()));
795  }
796 
814  template <typename ReduceType>
815  request i_reduce(std::shared_ptr<const Executor> exec,
816  const ReduceType* send_buffer, ReduceType* recv_buffer,
817  int count, MPI_Op operation, int root_rank) const
818  {
819  auto guard = exec->get_scoped_device_id_guard();
820  request req;
821  GKO_ASSERT_NO_MPI_ERRORS(MPI_Ireduce(
822  send_buffer, recv_buffer, count, type_impl<ReduceType>::get_type(),
823  operation, root_rank, this->get(), req.get()));
824  return req;
825  }
826 
840  template <typename ReduceType>
841  void all_reduce(std::shared_ptr<const Executor> exec,
842  ReduceType* recv_buffer, int count, MPI_Op operation) const
843  {
844  auto guard = exec->get_scoped_device_id_guard();
845  GKO_ASSERT_NO_MPI_ERRORS(MPI_Allreduce(
846  MPI_IN_PLACE, recv_buffer, count, type_impl<ReduceType>::get_type(),
847  operation, this->get()));
848  }
849 
865  template <typename ReduceType>
866  request i_all_reduce(std::shared_ptr<const Executor> exec,
867  ReduceType* recv_buffer, int count,
868  MPI_Op operation) const
869  {
870  auto guard = exec->get_scoped_device_id_guard();
871  request req;
872  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iallreduce(
873  MPI_IN_PLACE, recv_buffer, count, type_impl<ReduceType>::get_type(),
874  operation, this->get(), req.get()));
875  return req;
876  }
877 
892  template <typename ReduceType>
893  void all_reduce(std::shared_ptr<const Executor> exec,
894  const ReduceType* send_buffer, ReduceType* recv_buffer,
895  int count, MPI_Op operation) const
896  {
897  auto guard = exec->get_scoped_device_id_guard();
898  GKO_ASSERT_NO_MPI_ERRORS(MPI_Allreduce(
899  send_buffer, recv_buffer, count, type_impl<ReduceType>::get_type(),
900  operation, this->get()));
901  }
902 
919  template <typename ReduceType>
920  request i_all_reduce(std::shared_ptr<const Executor> exec,
921  const ReduceType* send_buffer, ReduceType* recv_buffer,
922  int count, MPI_Op operation) const
923  {
924  auto guard = exec->get_scoped_device_id_guard();
925  request req;
926  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iallreduce(
927  send_buffer, recv_buffer, count, type_impl<ReduceType>::get_type(),
928  operation, this->get(), req.get()));
929  return req;
930  }
931 
948  template <typename SendType, typename RecvType>
949  void gather(std::shared_ptr<const Executor> exec,
950  const SendType* send_buffer, const int send_count,
951  RecvType* recv_buffer, const int recv_count,
952  int root_rank) const
953  {
954  auto guard = exec->get_scoped_device_id_guard();
955  GKO_ASSERT_NO_MPI_ERRORS(
956  MPI_Gather(send_buffer, send_count, type_impl<SendType>::get_type(),
957  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
958  root_rank, this->get()));
959  }
960 
980  template <typename SendType, typename RecvType>
981  request i_gather(std::shared_ptr<const Executor> exec,
982  const SendType* send_buffer, const int send_count,
983  RecvType* recv_buffer, const int recv_count,
984  int root_rank) const
985  {
986  auto guard = exec->get_scoped_device_id_guard();
987  request req;
988  GKO_ASSERT_NO_MPI_ERRORS(MPI_Igather(
989  send_buffer, send_count, type_impl<SendType>::get_type(),
990  recv_buffer, recv_count, type_impl<RecvType>::get_type(), root_rank,
991  this->get(), req.get()));
992  return req;
993  }
994 
1013  template <typename SendType, typename RecvType>
1014  void gather_v(std::shared_ptr<const Executor> exec,
1015  const SendType* send_buffer, const int send_count,
1016  RecvType* recv_buffer, const int* recv_counts,
1017  const int* displacements, int root_rank) const
1018  {
1019  auto guard = exec->get_scoped_device_id_guard();
1020  GKO_ASSERT_NO_MPI_ERRORS(MPI_Gatherv(
1021  send_buffer, send_count, type_impl<SendType>::get_type(),
1022  recv_buffer, recv_counts, displacements,
1023  type_impl<RecvType>::get_type(), root_rank, this->get()));
1024  }
1025 
1046  template <typename SendType, typename RecvType>
1047  request i_gather_v(std::shared_ptr<const Executor> exec,
1048  const SendType* send_buffer, const int send_count,
1049  RecvType* recv_buffer, const int* recv_counts,
1050  const int* displacements, int root_rank) const
1051  {
1052  auto guard = exec->get_scoped_device_id_guard();
1053  request req;
1054  GKO_ASSERT_NO_MPI_ERRORS(MPI_Igatherv(
1055  send_buffer, send_count, type_impl<SendType>::get_type(),
1056  recv_buffer, recv_counts, displacements,
1057  type_impl<RecvType>::get_type(), root_rank, this->get(),
1058  req.get()));
1059  return req;
1060  }
1061 
1077  template <typename SendType, typename RecvType>
1078  void all_gather(std::shared_ptr<const Executor> exec,
1079  const SendType* send_buffer, const int send_count,
1080  RecvType* recv_buffer, const int recv_count) const
1081  {
1082  auto guard = exec->get_scoped_device_id_guard();
1083  GKO_ASSERT_NO_MPI_ERRORS(MPI_Allgather(
1084  send_buffer, send_count, type_impl<SendType>::get_type(),
1085  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1086  this->get()));
1087  }
1088 
1107  template <typename SendType, typename RecvType>
1108  request i_all_gather(std::shared_ptr<const Executor> exec,
1109  const SendType* send_buffer, const int send_count,
1110  RecvType* recv_buffer, const int recv_count) const
1111  {
1112  auto guard = exec->get_scoped_device_id_guard();
1113  request req;
1114  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iallgather(
1115  send_buffer, send_count, type_impl<SendType>::get_type(),
1116  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1117  this->get(), req.get()));
1118  return req;
1119  }
1120 
1137  template <typename SendType, typename RecvType>
1138  void scatter(std::shared_ptr<const Executor> exec,
1139  const SendType* send_buffer, const int send_count,
1140  RecvType* recv_buffer, const int recv_count,
1141  int root_rank) const
1142  {
1143  auto guard = exec->get_scoped_device_id_guard();
1144  GKO_ASSERT_NO_MPI_ERRORS(MPI_Scatter(
1145  send_buffer, send_count, type_impl<SendType>::get_type(),
1146  recv_buffer, recv_count, type_impl<RecvType>::get_type(), root_rank,
1147  this->get()));
1148  }
1149 
1169  template <typename SendType, typename RecvType>
1170  request i_scatter(std::shared_ptr<const Executor> exec,
1171  const SendType* send_buffer, const int send_count,
1172  RecvType* recv_buffer, const int recv_count,
1173  int root_rank) const
1174  {
1175  auto guard = exec->get_scoped_device_id_guard();
1176  request req;
1177  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iscatter(
1178  send_buffer, send_count, type_impl<SendType>::get_type(),
1179  recv_buffer, recv_count, type_impl<RecvType>::get_type(), root_rank,
1180  this->get(), req.get()));
1181  return req;
1182  }
1183 
1202  template <typename SendType, typename RecvType>
1203  void scatter_v(std::shared_ptr<const Executor> exec,
1204  const SendType* send_buffer, const int* send_counts,
1205  const int* displacements, RecvType* recv_buffer,
1206  const int recv_count, int root_rank) const
1207  {
1208  auto guard = exec->get_scoped_device_id_guard();
1209  GKO_ASSERT_NO_MPI_ERRORS(MPI_Scatterv(
1210  send_buffer, send_counts, displacements,
1211  type_impl<SendType>::get_type(), recv_buffer, recv_count,
1212  type_impl<RecvType>::get_type(), root_rank, this->get()));
1213  }
1214 
1235  template <typename SendType, typename RecvType>
1236  request i_scatter_v(std::shared_ptr<const Executor> exec,
1237  const SendType* send_buffer, const int* send_counts,
1238  const int* displacements, RecvType* recv_buffer,
1239  const int recv_count, int root_rank) const
1240  {
1241  auto guard = exec->get_scoped_device_id_guard();
1242  request req;
1243  GKO_ASSERT_NO_MPI_ERRORS(
1244  MPI_Iscatterv(send_buffer, send_counts, displacements,
1245  type_impl<SendType>::get_type(), recv_buffer,
1246  recv_count, type_impl<RecvType>::get_type(),
1247  root_rank, this->get(), req.get()));
1248  return req;
1249  }
1250 
1267  template <typename RecvType>
1268  void all_to_all(std::shared_ptr<const Executor> exec, RecvType* recv_buffer,
1269  const int recv_count) const
1270  {
1271  auto guard = exec->get_scoped_device_id_guard();
1272  GKO_ASSERT_NO_MPI_ERRORS(MPI_Alltoall(
1273  MPI_IN_PLACE, recv_count, type_impl<RecvType>::get_type(),
1274  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1275  this->get()));
1276  }
1277 
1296  template <typename RecvType>
1297  request i_all_to_all(std::shared_ptr<const Executor> exec,
1298  RecvType* recv_buffer, const int recv_count) const
1299  {
1300  auto guard = exec->get_scoped_device_id_guard();
1301  request req;
1302  GKO_ASSERT_NO_MPI_ERRORS(MPI_Ialltoall(
1303  MPI_IN_PLACE, recv_count, type_impl<RecvType>::get_type(),
1304  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1305  this->get(), req.get()));
1306  return req;
1307  }
1308 
1325  template <typename SendType, typename RecvType>
1326  void all_to_all(std::shared_ptr<const Executor> exec,
1327  const SendType* send_buffer, const int send_count,
1328  RecvType* recv_buffer, const int recv_count) const
1329  {
1330  auto guard = exec->get_scoped_device_id_guard();
1331  GKO_ASSERT_NO_MPI_ERRORS(MPI_Alltoall(
1332  send_buffer, send_count, type_impl<SendType>::get_type(),
1333  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1334  this->get()));
1335  }
1336 
1355  template <typename SendType, typename RecvType>
1356  request i_all_to_all(std::shared_ptr<const Executor> exec,
1357  const SendType* send_buffer, const int send_count,
1358  RecvType* recv_buffer, const int recv_count) const
1359  {
1360  auto guard = exec->get_scoped_device_id_guard();
1361  request req;
1362  GKO_ASSERT_NO_MPI_ERRORS(MPI_Ialltoall(
1363  send_buffer, send_count, type_impl<SendType>::get_type(),
1364  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1365  this->get(), req.get()));
1366  return req;
1367  }
1368 
1388  template <typename SendType, typename RecvType>
1389  void all_to_all_v(std::shared_ptr<const Executor> exec,
1390  const SendType* send_buffer, const int* send_counts,
1391  const int* send_offsets, RecvType* recv_buffer,
1392  const int* recv_counts, const int* recv_offsets) const
1393  {
1394  this->all_to_all_v(std::move(exec), send_buffer, send_counts,
1395  send_offsets, type_impl<SendType>::get_type(),
1396  recv_buffer, recv_counts, recv_offsets,
1398  }
1399 
1415  void all_to_all_v(std::shared_ptr<const Executor> exec,
1416  const void* send_buffer, const int* send_counts,
1417  const int* send_offsets, MPI_Datatype send_type,
1418  void* recv_buffer, const int* recv_counts,
1419  const int* recv_offsets, MPI_Datatype recv_type) const
1420  {
1421  auto guard = exec->get_scoped_device_id_guard();
1422  GKO_ASSERT_NO_MPI_ERRORS(MPI_Alltoallv(
1423  send_buffer, send_counts, send_offsets, send_type, recv_buffer,
1424  recv_counts, recv_offsets, recv_type, this->get()));
1425  }
1426 
1446  request i_all_to_all_v(std::shared_ptr<const Executor> exec,
1447  const void* send_buffer, const int* send_counts,
1448  const int* send_offsets, MPI_Datatype send_type,
1449  void* recv_buffer, const int* recv_counts,
1450  const int* recv_offsets,
1451  MPI_Datatype recv_type) const
1452  {
1453  auto guard = exec->get_scoped_device_id_guard();
1454  request req;
1455  GKO_ASSERT_NO_MPI_ERRORS(MPI_Ialltoallv(
1456  send_buffer, send_counts, send_offsets, send_type, recv_buffer,
1457  recv_counts, recv_offsets, recv_type, this->get(), req.get()));
1458  return req;
1459  }
1460 
1481  template <typename SendType, typename RecvType>
1482  request i_all_to_all_v(std::shared_ptr<const Executor> exec,
1483  const SendType* send_buffer, const int* send_counts,
1484  const int* send_offsets, RecvType* recv_buffer,
1485  const int* recv_counts,
1486  const int* recv_offsets) const
1487  {
1488  return this->i_all_to_all_v(
1489  std::move(exec), send_buffer, send_counts, send_offsets,
1490  type_impl<SendType>::get_type(), recv_buffer, recv_counts,
1491  recv_offsets, type_impl<RecvType>::get_type());
1492  }
1493 
1508  template <typename ScanType>
1509  void scan(std::shared_ptr<const Executor> exec, const ScanType* send_buffer,
1510  ScanType* recv_buffer, int count, MPI_Op operation) const
1511  {
1512  auto guard = exec->get_scoped_device_id_guard();
1513  GKO_ASSERT_NO_MPI_ERRORS(MPI_Scan(send_buffer, recv_buffer, count,
1515  operation, this->get()));
1516  }
1517 
1534  template <typename ScanType>
1535  request i_scan(std::shared_ptr<const Executor> exec,
1536  const ScanType* send_buffer, ScanType* recv_buffer,
1537  int count, MPI_Op operation) const
1538  {
1539  auto guard = exec->get_scoped_device_id_guard();
1540  request req;
1541  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iscan(send_buffer, recv_buffer, count,
1543  operation, this->get(), req.get()));
1544  return req;
1545  }
1546 
1547 private:
1548  std::shared_ptr<MPI_Comm> comm_;
1549  bool force_host_buffer_;
1550 
1551  int get_my_rank() const
1552  {
1553  int my_rank = 0;
1554  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_rank(get(), &my_rank));
1555  return my_rank;
1556  }
1557 
1558  int get_node_local_rank() const
1559  {
1560  MPI_Comm local_comm;
1561  int rank;
1562  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_split_type(
1563  this->get(), MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &local_comm));
1564  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_rank(local_comm, &rank));
1565  MPI_Comm_free(&local_comm);
1566  return rank;
1567  }
1568 
1569  int get_num_ranks() const
1570  {
1571  int size = 1;
1572  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_size(this->get(), &size));
1573  return size;
1574  }
1575 };
1576 
1577 
1582 bool requires_host_buffer(const std::shared_ptr<const Executor>& exec,
1583  const communicator& comm);
1584 
1585 
1591 inline double get_walltime() { return MPI_Wtime(); }
1592 
1593 
1602 template <typename ValueType>
1603 class window {
1604 public:
1608  enum class create_type { allocate = 1, create = 2, dynamic_create = 3 };
1609 
1613  enum class lock_type { shared = 1, exclusive = 2 };
1614 
1618  window() : window_(MPI_WIN_NULL) {}
1619 
1620  window(const window& other) = delete;
1621 
1622  window& operator=(const window& other) = delete;
1623 
1630  window(window&& other) noexcept
1631  : window_{std::exchange(other.window_, MPI_WIN_NULL)}
1632  {}
1633 
1640  window& operator=(window&& other) noexcept
1641  {
1642  if (this != &other) {
1643  if (this->window_ && this->window_ != MPI_WIN_NULL) {
1644  MPI_Win_free(&this->window_);
1645  }
1646  window_ = std::exchange(other.window_, MPI_WIN_NULL);
1647  }
1648  return *this;
1649  }
1650 
1663  window(std::shared_ptr<const Executor> exec, ValueType* base, int num_elems,
1664  const communicator& comm, const int disp_unit = sizeof(ValueType),
1665  MPI_Info input_info = MPI_INFO_NULL,
1666  create_type c_type = create_type::create)
1667  {
1668  auto guard = exec->get_scoped_device_id_guard();
1669  unsigned size = num_elems * sizeof(ValueType);
1670  if (c_type == create_type::create) {
1671  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_create(
1672  base, size, disp_unit, input_info, comm.get(), &this->window_));
1673  } else if (c_type == create_type::dynamic_create) {
1674  GKO_ASSERT_NO_MPI_ERRORS(
1675  MPI_Win_create_dynamic(input_info, comm.get(), &this->window_));
1676  } else if (c_type == create_type::allocate) {
1677  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_allocate(
1678  size, disp_unit, input_info, comm.get(), base, &this->window_));
1679  } else {
1680  GKO_NOT_IMPLEMENTED;
1681  }
1682  }
1683 
1689  MPI_Win get_window() const { return this->window_; }
1690 
1697  void fence(int assert = 0) const
1698  {
1699  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_fence(assert, this->window_));
1700  }
1701 
1710  void lock(int rank, lock_type lock_t = lock_type::shared,
1711  int assert = 0) const
1712  {
1713  if (lock_t == lock_type::shared) {
1714  GKO_ASSERT_NO_MPI_ERRORS(
1715  MPI_Win_lock(MPI_LOCK_SHARED, rank, assert, this->window_));
1716  } else if (lock_t == lock_type::exclusive) {
1717  GKO_ASSERT_NO_MPI_ERRORS(
1718  MPI_Win_lock(MPI_LOCK_EXCLUSIVE, rank, assert, this->window_));
1719  } else {
1720  GKO_NOT_IMPLEMENTED;
1721  }
1722  }
1723 
1730  void unlock(int rank) const
1731  {
1732  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_unlock(rank, this->window_));
1733  }
1734 
1741  void lock_all(int assert = 0) const
1742  {
1743  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_lock_all(assert, this->window_));
1744  }
1745 
1750  void unlock_all() const
1751  {
1752  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_unlock_all(this->window_));
1753  }
1754 
1761  void flush(int rank) const
1762  {
1763  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_flush(rank, this->window_));
1764  }
1765 
1772  void flush_local(int rank) const
1773  {
1774  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_flush_local(rank, this->window_));
1775  }
1776 
1781  void flush_all() const
1782  {
1783  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_flush_all(this->window_));
1784  }
1785 
1790  void flush_all_local() const
1791  {
1792  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_flush_local_all(this->window_));
1793  }
1794 
1798  void sync() const { GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_sync(this->window_)); }
1799 
1804  {
1805  if (this->window_ && this->window_ != MPI_WIN_NULL) {
1806  MPI_Win_free(&this->window_);
1807  }
1808  }
1809 
1820  template <typename PutType>
1821  void put(std::shared_ptr<const Executor> exec, const PutType* origin_buffer,
1822  const int origin_count, const int target_rank,
1823  const unsigned int target_disp, const int target_count) const
1824  {
1825  auto guard = exec->get_scoped_device_id_guard();
1826  GKO_ASSERT_NO_MPI_ERRORS(
1827  MPI_Put(origin_buffer, origin_count, type_impl<PutType>::get_type(),
1828  target_rank, target_disp, target_count,
1830  }
1831 
1844  template <typename PutType>
1845  request r_put(std::shared_ptr<const Executor> exec,
1846  const PutType* origin_buffer, const int origin_count,
1847  const int target_rank, const unsigned int target_disp,
1848  const int target_count) const
1849  {
1850  auto guard = exec->get_scoped_device_id_guard();
1851  request req;
1852  GKO_ASSERT_NO_MPI_ERRORS(MPI_Rput(
1853  origin_buffer, origin_count, type_impl<PutType>::get_type(),
1854  target_rank, target_disp, target_count,
1855  type_impl<PutType>::get_type(), this->get_window(), req.get()));
1856  return req;
1857  }
1858 
1870  template <typename PutType>
1871  void accumulate(std::shared_ptr<const Executor> exec,
1872  const PutType* origin_buffer, const int origin_count,
1873  const int target_rank, const unsigned int target_disp,
1874  const int target_count, MPI_Op operation) const
1875  {
1876  auto guard = exec->get_scoped_device_id_guard();
1877  GKO_ASSERT_NO_MPI_ERRORS(MPI_Accumulate(
1878  origin_buffer, origin_count, type_impl<PutType>::get_type(),
1879  target_rank, target_disp, target_count,
1880  type_impl<PutType>::get_type(), operation, this->get_window()));
1881  }
1882 
1896  template <typename PutType>
1897  request r_accumulate(std::shared_ptr<const Executor> exec,
1898  const PutType* origin_buffer, const int origin_count,
1899  const int target_rank, const unsigned int target_disp,
1900  const int target_count, MPI_Op operation) const
1901  {
1902  auto guard = exec->get_scoped_device_id_guard();
1903  request req;
1904  GKO_ASSERT_NO_MPI_ERRORS(MPI_Raccumulate(
1905  origin_buffer, origin_count, type_impl<PutType>::get_type(),
1906  target_rank, target_disp, target_count,
1907  type_impl<PutType>::get_type(), operation, this->get_window(),
1908  req.get()));
1909  return req;
1910  }
1911 
1922  template <typename GetType>
1923  void get(std::shared_ptr<const Executor> exec, GetType* origin_buffer,
1924  const int origin_count, const int target_rank,
1925  const unsigned int target_disp, const int target_count) const
1926  {
1927  auto guard = exec->get_scoped_device_id_guard();
1928  GKO_ASSERT_NO_MPI_ERRORS(
1929  MPI_Get(origin_buffer, origin_count, type_impl<GetType>::get_type(),
1930  target_rank, target_disp, target_count,
1932  }
1933 
1946  template <typename GetType>
1947  request r_get(std::shared_ptr<const Executor> exec, GetType* origin_buffer,
1948  const int origin_count, const int target_rank,
1949  const unsigned int target_disp, const int target_count) const
1950  {
1951  auto guard = exec->get_scoped_device_id_guard();
1952  request req;
1953  GKO_ASSERT_NO_MPI_ERRORS(MPI_Rget(
1954  origin_buffer, origin_count, type_impl<GetType>::get_type(),
1955  target_rank, target_disp, target_count,
1956  type_impl<GetType>::get_type(), this->get_window(), req.get()));
1957  return req;
1958  }
1959 
1973  template <typename GetType>
1974  void get_accumulate(std::shared_ptr<const Executor> exec,
1975  GetType* origin_buffer, const int origin_count,
1976  GetType* result_buffer, const int result_count,
1977  const int target_rank, const unsigned int target_disp,
1978  const int target_count, MPI_Op operation) const
1979  {
1980  auto guard = exec->get_scoped_device_id_guard();
1981  GKO_ASSERT_NO_MPI_ERRORS(MPI_Get_accumulate(
1982  origin_buffer, origin_count, type_impl<GetType>::get_type(),
1983  result_buffer, result_count, type_impl<GetType>::get_type(),
1984  target_rank, target_disp, target_count,
1985  type_impl<GetType>::get_type(), operation, this->get_window()));
1986  }
1987 
2003  template <typename GetType>
2004  request r_get_accumulate(std::shared_ptr<const Executor> exec,
2005  GetType* origin_buffer, const int origin_count,
2006  GetType* result_buffer, const int result_count,
2007  const int target_rank,
2008  const unsigned int target_disp,
2009  const int target_count, MPI_Op operation) const
2010  {
2011  auto guard = exec->get_scoped_device_id_guard();
2012  request req;
2013  GKO_ASSERT_NO_MPI_ERRORS(MPI_Rget_accumulate(
2014  origin_buffer, origin_count, type_impl<GetType>::get_type(),
2015  result_buffer, result_count, type_impl<GetType>::get_type(),
2016  target_rank, target_disp, target_count,
2017  type_impl<GetType>::get_type(), operation, this->get_window(),
2018  req.get()));
2019  return req;
2020  }
2021 
2033  template <typename GetType>
2034  void fetch_and_op(std::shared_ptr<const Executor> exec,
2035  GetType* origin_buffer, GetType* result_buffer,
2036  const int target_rank, const unsigned int target_disp,
2037  MPI_Op operation) const
2038  {
2039  auto guard = exec->get_scoped_device_id_guard();
2040  GKO_ASSERT_NO_MPI_ERRORS(MPI_Fetch_and_op(
2041  origin_buffer, result_buffer, type_impl<GetType>::get_type(),
2042  target_rank, target_disp, operation, this->get_window()));
2043  }
2044 
2045 private:
2046  MPI_Win window_;
2047 };
2048 
2049 
2050 } // namespace mpi
2051 } // namespace experimental
2052 } // namespace gko
2053 
2054 
2055 #endif // GKO_HAVE_MPI
2056 
2057 
2058 #endif // GKO_PUBLIC_CORE_BASE_MPI_HPP_
gko::experimental::mpi::window
This class wraps the MPI_Window class with RAII functionality.
Definition: mpi.hpp:1603
gko::experimental::mpi::environment::get_provided_thread_support
int get_provided_thread_support() const
Return the provided thread support.
Definition: mpi.hpp:230
gko::experimental::mpi::requires_host_buffer
bool requires_host_buffer(const std::shared_ptr< const Executor > &exec, const communicator &comm)
Checks if the combination of Executor and communicator requires passing MPI buffers from the host mem...
gko::experimental::mpi::communicator::i_scan
request i_scan(std::shared_ptr< const Executor > exec, const ScanType *send_buffer, ScanType *recv_buffer, int count, MPI_Op operation) const
Does a scan operation with the given operator.
Definition: mpi.hpp:1535
gko::experimental::mpi::contiguous_type::contiguous_type
contiguous_type()
Constructs empty wrapper with MPI_DATATYPE_NULL.
Definition: mpi.hpp:129
gko::experimental::mpi::communicator::scan
void scan(std::shared_ptr< const Executor > exec, const ScanType *send_buffer, ScanType *recv_buffer, int count, MPI_Op operation) const
Does a scan operation with the given operator.
Definition: mpi.hpp:1509
gko::experimental::mpi::window::get_accumulate
void get_accumulate(std::shared_ptr< const Executor > exec, GetType *origin_buffer, const int origin_count, GetType *result_buffer, const int result_count, const int target_rank, const unsigned int target_disp, const int target_count, MPI_Op operation) const
Get Accumulate data from the target window.
Definition: mpi.hpp:1974
gko::experimental::mpi::window::lock
void lock(int rank, lock_type lock_t=lock_type::shared, int assert=0) const
Create an epoch using MPI_Win_lock for the window object.
Definition: mpi.hpp:1710
gko::experimental::mpi::communicator::i_broadcast
request i_broadcast(std::shared_ptr< const Executor > exec, BroadcastType *buffer, int count, int root_rank) const
(Non-blocking) Broadcast data from calling process to all ranks in the communicator
Definition: mpi.hpp:760
gko::experimental::mpi::communicator::communicator
communicator(const communicator &comm, int color, int key)
Create a communicator object from an existing MPI_Comm object using color and key.
Definition: mpi.hpp:460
gko::experimental::mpi::window::window
window(std::shared_ptr< const Executor > exec, ValueType *base, int num_elems, const communicator &comm, const int disp_unit=sizeof(ValueType), MPI_Info input_info=MPI_INFO_NULL, create_type c_type=create_type::create)
Create a window object with a given data pointer and type.
Definition: mpi.hpp:1663
gko::experimental::mpi::communicator::i_all_to_all
request i_all_to_all(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int recv_count) const
(Non-blocking) Communicate data from all ranks to all other ranks (MPI_Ialltoall).
Definition: mpi.hpp:1356
gko::experimental::mpi::environment::environment
environment(int &argc, char **&argv, const thread_type thread_t=thread_type::serialized)
Call MPI_Init_thread and initialize the MPI environment.
Definition: mpi.hpp:240
gko::experimental::mpi::window::put
void put(std::shared_ptr< const Executor > exec, const PutType *origin_buffer, const int origin_count, const int target_rank, const unsigned int target_disp, const int target_count) const
Put data into the target window.
Definition: mpi.hpp:1821
gko::bfloat16
A class providing basic support for bfloat16 precision floating point types.
Definition: bfloat16.hpp:76
gko::experimental::mpi::window::create_type
create_type
The create type for the window object.
Definition: mpi.hpp:1608
gko::experimental::mpi::window::accumulate
void accumulate(std::shared_ptr< const Executor > exec, const PutType *origin_buffer, const int origin_count, const int target_rank, const unsigned int target_disp, const int target_count, MPI_Op operation) const
Accumulate data into the target window.
Definition: mpi.hpp:1871
gko::experimental::mpi::window::fetch_and_op
void fetch_and_op(std::shared_ptr< const Executor > exec, GetType *origin_buffer, GetType *result_buffer, const int target_rank, const unsigned int target_disp, MPI_Op operation) const
Fetch and operate on data from the target window (An optimized version of Get_accumulate).
Definition: mpi.hpp:2034
gko::experimental::mpi::environment
Class that sets up and finalizes the MPI environment.
Definition: mpi.hpp:209
gko::experimental::mpi::communicator::all_to_all_v
void all_to_all_v(std::shared_ptr< const Executor > exec, const void *send_buffer, const int *send_counts, const int *send_offsets, MPI_Datatype send_type, void *recv_buffer, const int *recv_counts, const int *recv_offsets, MPI_Datatype recv_type) const
Communicate data from all ranks to all other ranks with offsets (MPI_Alltoallv).
Definition: mpi.hpp:1415
gko::experimental::mpi::communicator::send
void send(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, const int destination_rank, const int send_tag) const
Send (Blocking) data from calling process to destination rank.
Definition: mpi.hpp:627
gko::experimental::mpi::communicator::communicator
communicator(const MPI_Comm &comm, int color, int key)
Create a communicator object from an existing MPI_Comm object using color and key.
Definition: mpi.hpp:444
gko::experimental::mpi::communicator::i_scatter_v
request i_scatter_v(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int *send_counts, const int *displacements, RecvType *recv_buffer, const int recv_count, int root_rank) const
(Non-blocking) Scatter data from root rank to all ranks in the communicator with offsets.
Definition: mpi.hpp:1236
gko::experimental::mpi::communicator::synchronize
void synchronize() const
This function is used to synchronize the ranks in the communicator.
Definition: mpi.hpp:608
gko::experimental::mpi::communicator::all_gather
void all_gather(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int recv_count) const
Gather data onto all ranks from all ranks in the communicator.
Definition: mpi.hpp:1078
gko::experimental::mpi::communicator::all_reduce
void all_reduce(std::shared_ptr< const Executor > exec, const ReduceType *send_buffer, ReduceType *recv_buffer, int count, MPI_Op operation) const
Reduce data from all calling processes from all calling processes on same communicator.
Definition: mpi.hpp:893
gko::experimental::mpi::window::get_window
MPI_Win get_window() const
Get the underlying window object of MPI_Win type.
Definition: mpi.hpp:1689
gko::experimental::mpi::window::operator=
window & operator=(window &&other) noexcept
The move assignment operator.
Definition: mpi.hpp:1640
gko::experimental::mpi::window::fence
void fence(int assert=0) const
The active target synchronization using MPI_Win_fence for the window object.
Definition: mpi.hpp:1697
gko::experimental::mpi::communicator::broadcast
void broadcast(std::shared_ptr< const Executor > exec, BroadcastType *buffer, int count, int root_rank) const
Broadcast data from calling process to all ranks in the communicator.
Definition: mpi.hpp:735
gko::experimental::mpi::window::unlock_all
void unlock_all() const
Close the epoch on all ranks using MPI_Win_unlock_all for the window object.
Definition: mpi.hpp:1750
gko::experimental::mpi::communicator::all_reduce
void all_reduce(std::shared_ptr< const Executor > exec, ReduceType *recv_buffer, int count, MPI_Op operation) const
(In-place) Reduce data from all calling processes from all calling processes on same communicator.
Definition: mpi.hpp:841
gko::experimental::mpi::communicator::i_all_to_all
request i_all_to_all(std::shared_ptr< const Executor > exec, RecvType *recv_buffer, const int recv_count) const
(In-place, Non-blocking) Communicate data from all ranks to all other ranks in place (MPI_Ialltoall).
Definition: mpi.hpp:1297
gko::experimental::mpi::contiguous_type::contiguous_type
contiguous_type(contiguous_type &&other) noexcept
Move constructor, leaves other with MPI_DATATYPE_NULL.
Definition: mpi.hpp:146
gko::experimental::mpi::request
The request class is a light, move-only wrapper around the MPI_Request handle.
Definition: mpi.hpp:330
gko::experimental::mpi::communicator::size
int size() const
Return the size of the communicator (number of ranks).
Definition: mpi.hpp:533
gko::experimental::mpi::status::status
status()
The default constructor.
Definition: mpi.hpp:294
gko::experimental::mpi::environment::~environment
~environment()
Call MPI_Finalize at the end of the scope of this class.
Definition: mpi.hpp:252
gko::experimental::mpi::communicator::i_scatter
request i_scatter(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int recv_count, int root_rank) const
(Non-blocking) Scatter data from root rank to all ranks in the communicator.
Definition: mpi.hpp:1170
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:19
gko::experimental::mpi::communicator::reduce
void reduce(std::shared_ptr< const Executor > exec, const ReduceType *send_buffer, ReduceType *recv_buffer, int count, MPI_Op operation, int root_rank) const
Reduce data into root from all calling processes on the same communicator.
Definition: mpi.hpp:787
gko::experimental::mpi::request::wait
status wait()
Allows a rank to wait on a particular request handle.
Definition: mpi.hpp:375
gko::experimental::mpi::contiguous_type::operator=
contiguous_type & operator=(contiguous_type &&other) noexcept
Move assignment, leaves other with MPI_DATATYPE_NULL.
Definition: mpi.hpp:158
gko::experimental::mpi::window::flush_all
void flush_all() const
Flush all the existing RDMA operations for the calling process for the window object.
Definition: mpi.hpp:1781
gko::experimental::mpi::communicator::all_to_all_v
void all_to_all_v(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int *send_counts, const int *send_offsets, RecvType *recv_buffer, const int *recv_counts, const int *recv_offsets) const
Communicate data from all ranks to all other ranks with offsets (MPI_Alltoallv).
Definition: mpi.hpp:1389
gko::experimental::mpi::communicator::i_gather_v
request i_gather_v(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int *recv_counts, const int *displacements, int root_rank) const
(Non-blocking) Gather data onto the root rank from all ranks in the communicator with offsets.
Definition: mpi.hpp:1047
gko::experimental::mpi::contiguous_type::contiguous_type
contiguous_type(int count, MPI_Datatype old_type)
Constructs a wrapper for a contiguous MPI_Datatype.
Definition: mpi.hpp:120
gko::experimental::mpi::window::unlock
void unlock(int rank) const
Close the epoch using MPI_Win_unlock for the window object.
Definition: mpi.hpp:1730
gko::experimental::mpi::window::flush_all_local
void flush_all_local() const
Flush all the local existing RDMA operations on the calling rank for the window object.
Definition: mpi.hpp:1790
gko::experimental::mpi::is_gpu_aware
constexpr bool is_gpu_aware()
Return if GPU aware functionality is available.
Definition: mpi.hpp:41
gko::experimental::mpi::window::lock_all
void lock_all(int assert=0) const
Create the epoch on all ranks using MPI_Win_lock_all for the window object.
Definition: mpi.hpp:1741
gko::experimental::mpi::window::lock_type
lock_type
The lock type for passive target synchronization of the windows.
Definition: mpi.hpp:1613
gko::experimental::mpi::contiguous_type::get
MPI_Datatype get() const
Access the underlying MPI_Datatype.
Definition: mpi.hpp:181
gko::experimental::mpi::communicator::operator==
bool operator==(const communicator &rhs) const
Compare two communicator objects for equality.
Definition: mpi.hpp:554
gko::experimental::mpi::window::r_accumulate
request r_accumulate(std::shared_ptr< const Executor > exec, const PutType *origin_buffer, const int origin_count, const int target_rank, const unsigned int target_disp, const int target_count, MPI_Op operation) const
(Non-blocking) Accumulate data into the target window.
Definition: mpi.hpp:1897
gko::experimental::mpi::communicator
A thin wrapper of MPI_Comm that supports most MPI calls.
Definition: mpi.hpp:418
gko::experimental::mpi::contiguous_type::~contiguous_type
~contiguous_type()
Destructs object by freeing wrapped MPI_Datatype.
Definition: mpi.hpp:169
gko::experimental::mpi::communicator::create_owning
static communicator create_owning(const MPI_Comm &comm, bool force_host_buffer=false)
Creates a new communicator and takes ownership of the MPI_Comm.
Definition: mpi.hpp:478
gko::experimental::mpi::type_impl
A struct that is used to determine the MPI_Datatype of a specified type.
Definition: mpi.hpp:76
gko::experimental::mpi::communicator::communicator
communicator(const MPI_Comm &comm, bool force_host_buffer=false)
Non-owning constructor for an existing communicator of type MPI_Comm.
Definition: mpi.hpp:430
gko::experimental::mpi::communicator::all_to_all
void all_to_all(std::shared_ptr< const Executor > exec, RecvType *recv_buffer, const int recv_count) const
(In-place) Communicate data from all ranks to all other ranks in place (MPI_Alltoall).
Definition: mpi.hpp:1268
gko::experimental::mpi::communicator::i_all_reduce
request i_all_reduce(std::shared_ptr< const Executor > exec, const ReduceType *send_buffer, ReduceType *recv_buffer, int count, MPI_Op operation) const
Reduce data from all calling processes from all calling processes on same communicator.
Definition: mpi.hpp:920
gko::experimental::mpi::request::request
request()
The default constructor.
Definition: mpi.hpp:336
gko::experimental::mpi::communicator::i_send
request i_send(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, const int destination_rank, const int send_tag) const
Send (Non-blocking, Immediate return) data from calling process to destination rank.
Definition: mpi.hpp:654
gko::experimental::mpi::communicator::scatter
void scatter(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int recv_count, int root_rank) const
Scatter data from root rank to all ranks in the communicator.
Definition: mpi.hpp:1138
gko::experimental::mpi::window::r_get_accumulate
request r_get_accumulate(std::shared_ptr< const Executor > exec, GetType *origin_buffer, const int origin_count, GetType *result_buffer, const int result_count, const int target_rank, const unsigned int target_disp, const int target_count, MPI_Op operation) const
(Non-blocking) Get Accumulate data (with handle) from the target window.
Definition: mpi.hpp:2004
gko::experimental::mpi::window::~window
~window()
The deleter which calls MPI_Win_free when the window leaves its scope.
Definition: mpi.hpp:1803
gko::experimental::mpi::communicator::operator=
communicator & operator=(communicator &&other)
Definition: mpi.hpp:509
gko::experimental::mpi::map_rank_to_device_id
int map_rank_to_device_id(MPI_Comm comm, int num_devices)
Maps each MPI rank to a single device id in a round robin manner.
gko::experimental::mpi::window::window
window()
The default constructor.
Definition: mpi.hpp:1618
gko::experimental::mpi::get_walltime
double get_walltime()
Get the rank in the communicator of the calling process.
Definition: mpi.hpp:1591
gko::experimental::mpi::status::get_count
int get_count(const T *data) const
Get the count of the number of elements received by the communication call.
Definition: mpi.hpp:314
gko::experimental::mpi::communicator::i_gather
request i_gather(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int recv_count, int root_rank) const
(Non-blocking) Gather data onto the root rank from all ranks in the communicator.
Definition: mpi.hpp:981
gko::experimental::mpi::communicator::rank
int rank() const
Return the rank of the calling process in the communicator.
Definition: mpi.hpp:540
gko::experimental::mpi::communicator::i_all_reduce
request i_all_reduce(std::shared_ptr< const Executor > exec, ReduceType *recv_buffer, int count, MPI_Op operation) const
(In-place, non-blocking) Reduce data from all calling processes from all calling processes on same co...
Definition: mpi.hpp:866
gko::experimental::mpi::communicator::is_congruent
bool is_congruent(const communicator &rhs) const
Checks if the rhs communicator is congruent to this communicator.
Definition: mpi.hpp:594
gko::experimental::mpi::wait_all
std::vector< status > wait_all(std::vector< request > &req)
Allows a rank to wait on multiple request handles.
Definition: mpi.hpp:394
gko::half
A class providing basic support for half precision floating point types.
Definition: half.hpp:288
gko::experimental::mpi::communicator::gather_v
void gather_v(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int *recv_counts, const int *displacements, int root_rank) const
Gather data onto the root rank from all ranks in the communicator with offsets.
Definition: mpi.hpp:1014
gko::experimental::mpi::communicator::scatter_v
void scatter_v(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int *send_counts, const int *displacements, RecvType *recv_buffer, const int recv_count, int root_rank) const
Scatter data from root rank to all ranks in the communicator with offsets.
Definition: mpi.hpp:1203
gko::experimental::mpi::communicator::operator=
communicator & operator=(const communicator &other)=default
gko::experimental::mpi::window::window
window(window &&other) noexcept
The move constructor.
Definition: mpi.hpp:1630
gko::experimental::mpi::thread_type
thread_type
This enum specifies the threading type to be used when creating an MPI environment.
Definition: mpi.hpp:192
gko::experimental::mpi::communicator::operator!=
bool operator!=(const communicator &rhs) const
Compare two communicator objects for non-equality.
Definition: mpi.hpp:561
gko::experimental::mpi::status::get
MPI_Status * get()
Get a pointer to the underlying MPI_Status object.
Definition: mpi.hpp:301
gko::experimental::mpi::communicator::is_identical
bool is_identical(const communicator &rhs) const
Checks if the rhs communicator is identical to this communicator.
Definition: mpi.hpp:572
gko::experimental::mpi::communicator::gather
void gather(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int recv_count, int root_rank) const
Gather data onto the root rank from all ranks in the communicator.
Definition: mpi.hpp:949
gko::experimental::mpi::contiguous_type::operator=
contiguous_type & operator=(const contiguous_type &)=delete
Disallow copying of wrapper type.
gko::experimental::mpi::communicator::i_all_gather
request i_all_gather(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int recv_count) const
(Non-blocking) Gather data onto all ranks from all ranks in the communicator.
Definition: mpi.hpp:1108
gko::experimental::mpi::status
The status struct is a light wrapper around the MPI_Status struct.
Definition: mpi.hpp:290
gko::experimental::mpi::window::flush_local
void flush_local(int rank) const
Flush the existing RDMA operations on the calling rank from the target rank for the window object.
Definition: mpi.hpp:1772
gko::experimental::mpi::request::get
MPI_Request * get()
Get a pointer to the underlying MPI_Request handle.
Definition: mpi.hpp:367
gko::experimental::mpi::communicator::communicator
communicator(communicator &&other)
Move constructor.
Definition: mpi.hpp:499
gko::experimental::mpi::communicator::i_all_to_all_v
request i_all_to_all_v(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int *send_counts, const int *send_offsets, RecvType *recv_buffer, const int *recv_counts, const int *recv_offsets) const
Communicate data from all ranks to all other ranks with offsets (MPI_Ialltoallv).
Definition: mpi.hpp:1482
gko::experimental::mpi::communicator::i_recv
request i_recv(std::shared_ptr< const Executor > exec, RecvType *recv_buffer, const int recv_count, const int source_rank, const int recv_tag) const
Receive (Non-blocking, Immediate return) data from source rank.
Definition: mpi.hpp:710
gko::experimental::mpi::window::sync
void sync() const
Synchronize the public and private buffers for the window object.
Definition: mpi.hpp:1798
gko::experimental::mpi::window::flush
void flush(int rank) const
Flush the existing RDMA operations on the target rank for the calling process for the window object.
Definition: mpi.hpp:1761
gko::experimental::mpi::communicator::node_local_rank
int node_local_rank() const
Return the node local rank of the calling process in the communicator.
Definition: mpi.hpp:547
gko::experimental::mpi::contiguous_type
A move-only wrapper for a contiguous MPI_Datatype.
Definition: mpi.hpp:112
gko::experimental::mpi::communicator::i_all_to_all_v
request i_all_to_all_v(std::shared_ptr< const Executor > exec, const void *send_buffer, const int *send_counts, const int *send_offsets, MPI_Datatype send_type, void *recv_buffer, const int *recv_counts, const int *recv_offsets, MPI_Datatype recv_type) const
Communicate data from all ranks to all other ranks with offsets (MPI_Ialltoallv).
Definition: mpi.hpp:1446
gko::experimental::mpi::communicator::all_to_all
void all_to_all(std::shared_ptr< const Executor > exec, const SendType *send_buffer, const int send_count, RecvType *recv_buffer, const int recv_count) const
Communicate data from all ranks to all other ranks (MPI_Alltoall).
Definition: mpi.hpp:1326
gko::experimental::mpi::window::r_get
request r_get(std::shared_ptr< const Executor > exec, GetType *origin_buffer, const int origin_count, const int target_rank, const unsigned int target_disp, const int target_count) const
Get data (with handle) from the target window.
Definition: mpi.hpp:1947
gko::experimental::mpi::communicator::recv
status recv(std::shared_ptr< const Executor > exec, RecvType *recv_buffer, const int recv_count, const int source_rank, const int recv_tag) const
Receive data from source rank.
Definition: mpi.hpp:682
gko::experimental::mpi::communicator::i_reduce
request i_reduce(std::shared_ptr< const Executor > exec, const ReduceType *send_buffer, ReduceType *recv_buffer, int count, MPI_Op operation, int root_rank) const
(Non-blocking) Reduce data into root from all calling processes on the same communicator.
Definition: mpi.hpp:815
gko::experimental::mpi::window::get
void get(std::shared_ptr< const Executor > exec, GetType *origin_buffer, const int origin_count, const int target_rank, const unsigned int target_disp, const int target_count) const
Get data from the target window.
Definition: mpi.hpp:1923
gko::experimental::mpi::communicator::get
const MPI_Comm & get() const
Return the underlying MPI_Comm object.
Definition: mpi.hpp:524
gko::experimental::mpi::window::r_put
request r_put(std::shared_ptr< const Executor > exec, const PutType *origin_buffer, const int origin_count, const int target_rank, const unsigned int target_disp, const int target_count) const
Put data into the target window.
Definition: mpi.hpp:1845