Ginkgo  Generated from pipelines/2837190956 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 {
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
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  {
446  MPI_Comm comm_out;
447  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_split(comm, color, key, &comm_out));
448  this->comm_.reset(new MPI_Comm(comm_out), comm_deleter{});
449  }
450 
459  communicator(const communicator& comm, int color, int key)
460  {
461  MPI_Comm comm_out;
462  GKO_ASSERT_NO_MPI_ERRORS(
463  MPI_Comm_split(comm.get(), color, key, &comm_out));
464  this->comm_.reset(new MPI_Comm(comm_out), comm_deleter{});
465  }
466 
476  static communicator create_owning(const MPI_Comm& comm,
477  bool force_host_buffer = false)
478  {
479  communicator comm_out(MPI_COMM_NULL, force_host_buffer);
480  comm_out.comm_.reset(new MPI_Comm(comm), comm_deleter{});
481  return comm_out;
482  }
483 
489  communicator(const communicator& other) = default;
490 
497  communicator(communicator&& other) { *this = std::move(other); }
498 
502  communicator& operator=(const communicator& other) = default;
503 
508  {
509  if (this != &other) {
510  comm_ = std::exchange(other.comm_,
511  std::make_shared<MPI_Comm>(MPI_COMM_NULL));
512  force_host_buffer_ = other.force_host_buffer_;
513  }
514  return *this;
515  }
516 
522  const MPI_Comm& get() const { return *(this->comm_.get()); }
523 
524  bool force_host_buffer() const { return force_host_buffer_; }
525 
531  int size() const { return get_num_ranks(); }
532 
538  int rank() const { return get_my_rank(); };
539 
545  int node_local_rank() const { return get_node_local_rank(); };
546 
552  bool operator==(const communicator& rhs) const { return is_identical(rhs); }
553 
559  bool operator!=(const communicator& rhs) const { return !(*this == rhs); }
560 
570  bool is_identical(const communicator& rhs) const
571  {
572  if (get() == MPI_COMM_NULL || rhs.get() == MPI_COMM_NULL) {
573  return get() == rhs.get();
574  }
575  int flag;
576  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_compare(get(), rhs.get(), &flag));
577  return flag == MPI_IDENT;
578  }
579 
592  bool is_congruent(const communicator& rhs) const
593  {
594  if (get() == MPI_COMM_NULL || rhs.get() == MPI_COMM_NULL) {
595  return get() == rhs.get();
596  }
597  int flag;
598  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_compare(get(), rhs.get(), &flag));
599  return flag == MPI_CONGRUENT;
600  }
601 
606  void synchronize() const
607  {
608  GKO_ASSERT_NO_MPI_ERRORS(MPI_Barrier(this->get()));
609  }
610 
624  template <typename SendType>
625  void send(std::shared_ptr<const Executor> exec, const SendType* send_buffer,
626  const int send_count, const int destination_rank,
627  const int send_tag) const
628  {
629  auto guard = exec->get_scoped_device_id_guard();
630  GKO_ASSERT_NO_MPI_ERRORS(
631  MPI_Send(send_buffer, send_count, type_impl<SendType>::get_type(),
632  destination_rank, send_tag, this->get()));
633  }
634 
651  template <typename SendType>
652  request i_send(std::shared_ptr<const Executor> exec,
653  const SendType* send_buffer, const int send_count,
654  const int destination_rank, const int send_tag) const
655  {
656  auto guard = exec->get_scoped_device_id_guard();
657  request req;
658  GKO_ASSERT_NO_MPI_ERRORS(
659  MPI_Isend(send_buffer, send_count, type_impl<SendType>::get_type(),
660  destination_rank, send_tag, this->get(), req.get()));
661  return req;
662  }
663 
679  template <typename RecvType>
680  status recv(std::shared_ptr<const Executor> exec, RecvType* recv_buffer,
681  const int recv_count, const int source_rank,
682  const int recv_tag) const
683  {
684  auto guard = exec->get_scoped_device_id_guard();
685  status st;
686  GKO_ASSERT_NO_MPI_ERRORS(
687  MPI_Recv(recv_buffer, recv_count, type_impl<RecvType>::get_type(),
688  source_rank, recv_tag, this->get(), st.get()));
689  return st;
690  }
691 
707  template <typename RecvType>
708  request i_recv(std::shared_ptr<const Executor> exec, RecvType* recv_buffer,
709  const int recv_count, const int source_rank,
710  const int recv_tag) const
711  {
712  auto guard = exec->get_scoped_device_id_guard();
713  request req;
714  GKO_ASSERT_NO_MPI_ERRORS(
715  MPI_Irecv(recv_buffer, recv_count, type_impl<RecvType>::get_type(),
716  source_rank, recv_tag, this->get(), req.get()));
717  return req;
718  }
719 
732  template <typename BroadcastType>
733  void broadcast(std::shared_ptr<const Executor> exec, BroadcastType* buffer,
734  int count, int root_rank) const
735  {
736  auto guard = exec->get_scoped_device_id_guard();
737  GKO_ASSERT_NO_MPI_ERRORS(MPI_Bcast(buffer, count,
739  root_rank, this->get()));
740  }
741 
757  template <typename BroadcastType>
758  request i_broadcast(std::shared_ptr<const Executor> exec,
759  BroadcastType* buffer, int count, int root_rank) const
760  {
761  auto guard = exec->get_scoped_device_id_guard();
762  request req;
763  GKO_ASSERT_NO_MPI_ERRORS(
764  MPI_Ibcast(buffer, count, type_impl<BroadcastType>::get_type(),
765  root_rank, this->get(), req.get()));
766  return req;
767  }
768 
784  template <typename ReduceType>
785  void reduce(std::shared_ptr<const Executor> exec,
786  const ReduceType* send_buffer, ReduceType* recv_buffer,
787  int count, MPI_Op operation, int root_rank) const
788  {
789  auto guard = exec->get_scoped_device_id_guard();
790  GKO_ASSERT_NO_MPI_ERRORS(MPI_Reduce(send_buffer, recv_buffer, count,
792  operation, root_rank, this->get()));
793  }
794 
812  template <typename ReduceType>
813  request i_reduce(std::shared_ptr<const Executor> exec,
814  const ReduceType* send_buffer, ReduceType* recv_buffer,
815  int count, MPI_Op operation, int root_rank) const
816  {
817  auto guard = exec->get_scoped_device_id_guard();
818  request req;
819  GKO_ASSERT_NO_MPI_ERRORS(MPI_Ireduce(
820  send_buffer, recv_buffer, count, type_impl<ReduceType>::get_type(),
821  operation, root_rank, this->get(), req.get()));
822  return req;
823  }
824 
838  template <typename ReduceType>
839  void all_reduce(std::shared_ptr<const Executor> exec,
840  ReduceType* recv_buffer, int count, MPI_Op operation) const
841  {
842  auto guard = exec->get_scoped_device_id_guard();
843  GKO_ASSERT_NO_MPI_ERRORS(MPI_Allreduce(
844  MPI_IN_PLACE, recv_buffer, count, type_impl<ReduceType>::get_type(),
845  operation, this->get()));
846  }
847 
863  template <typename ReduceType>
864  request i_all_reduce(std::shared_ptr<const Executor> exec,
865  ReduceType* recv_buffer, int count,
866  MPI_Op operation) const
867  {
868  auto guard = exec->get_scoped_device_id_guard();
869  request req;
870  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iallreduce(
871  MPI_IN_PLACE, recv_buffer, count, type_impl<ReduceType>::get_type(),
872  operation, this->get(), req.get()));
873  return req;
874  }
875 
890  template <typename ReduceType>
891  void all_reduce(std::shared_ptr<const Executor> exec,
892  const ReduceType* send_buffer, ReduceType* recv_buffer,
893  int count, MPI_Op operation) const
894  {
895  auto guard = exec->get_scoped_device_id_guard();
896  GKO_ASSERT_NO_MPI_ERRORS(MPI_Allreduce(
897  send_buffer, recv_buffer, count, type_impl<ReduceType>::get_type(),
898  operation, this->get()));
899  }
900 
917  template <typename ReduceType>
918  request i_all_reduce(std::shared_ptr<const Executor> exec,
919  const ReduceType* send_buffer, ReduceType* recv_buffer,
920  int count, MPI_Op operation) const
921  {
922  auto guard = exec->get_scoped_device_id_guard();
923  request req;
924  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iallreduce(
925  send_buffer, recv_buffer, count, type_impl<ReduceType>::get_type(),
926  operation, this->get(), req.get()));
927  return req;
928  }
929 
946  template <typename SendType, typename RecvType>
947  void gather(std::shared_ptr<const Executor> exec,
948  const SendType* send_buffer, const int send_count,
949  RecvType* recv_buffer, const int recv_count,
950  int root_rank) const
951  {
952  auto guard = exec->get_scoped_device_id_guard();
953  GKO_ASSERT_NO_MPI_ERRORS(
954  MPI_Gather(send_buffer, send_count, type_impl<SendType>::get_type(),
955  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
956  root_rank, this->get()));
957  }
958 
978  template <typename SendType, typename RecvType>
979  request i_gather(std::shared_ptr<const Executor> exec,
980  const SendType* send_buffer, const int send_count,
981  RecvType* recv_buffer, const int recv_count,
982  int root_rank) const
983  {
984  auto guard = exec->get_scoped_device_id_guard();
985  request req;
986  GKO_ASSERT_NO_MPI_ERRORS(MPI_Igather(
987  send_buffer, send_count, type_impl<SendType>::get_type(),
988  recv_buffer, recv_count, type_impl<RecvType>::get_type(), root_rank,
989  this->get(), req.get()));
990  return req;
991  }
992 
1011  template <typename SendType, typename RecvType>
1012  void gather_v(std::shared_ptr<const Executor> exec,
1013  const SendType* send_buffer, const int send_count,
1014  RecvType* recv_buffer, const int* recv_counts,
1015  const int* displacements, int root_rank) const
1016  {
1017  auto guard = exec->get_scoped_device_id_guard();
1018  GKO_ASSERT_NO_MPI_ERRORS(MPI_Gatherv(
1019  send_buffer, send_count, type_impl<SendType>::get_type(),
1020  recv_buffer, recv_counts, displacements,
1021  type_impl<RecvType>::get_type(), root_rank, this->get()));
1022  }
1023 
1044  template <typename SendType, typename RecvType>
1045  request i_gather_v(std::shared_ptr<const Executor> exec,
1046  const SendType* send_buffer, const int send_count,
1047  RecvType* recv_buffer, const int* recv_counts,
1048  const int* displacements, int root_rank) const
1049  {
1050  auto guard = exec->get_scoped_device_id_guard();
1051  request req;
1052  GKO_ASSERT_NO_MPI_ERRORS(MPI_Igatherv(
1053  send_buffer, send_count, type_impl<SendType>::get_type(),
1054  recv_buffer, recv_counts, displacements,
1055  type_impl<RecvType>::get_type(), root_rank, this->get(),
1056  req.get()));
1057  return req;
1058  }
1059 
1075  template <typename SendType, typename RecvType>
1076  void all_gather(std::shared_ptr<const Executor> exec,
1077  const SendType* send_buffer, const int send_count,
1078  RecvType* recv_buffer, const int recv_count) const
1079  {
1080  auto guard = exec->get_scoped_device_id_guard();
1081  GKO_ASSERT_NO_MPI_ERRORS(MPI_Allgather(
1082  send_buffer, send_count, type_impl<SendType>::get_type(),
1083  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1084  this->get()));
1085  }
1086 
1105  template <typename SendType, typename RecvType>
1106  request i_all_gather(std::shared_ptr<const Executor> exec,
1107  const SendType* send_buffer, const int send_count,
1108  RecvType* recv_buffer, const int recv_count) const
1109  {
1110  auto guard = exec->get_scoped_device_id_guard();
1111  request req;
1112  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iallgather(
1113  send_buffer, send_count, type_impl<SendType>::get_type(),
1114  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1115  this->get(), req.get()));
1116  return req;
1117  }
1118 
1135  template <typename SendType, typename RecvType>
1136  void scatter(std::shared_ptr<const Executor> exec,
1137  const SendType* send_buffer, const int send_count,
1138  RecvType* recv_buffer, const int recv_count,
1139  int root_rank) const
1140  {
1141  auto guard = exec->get_scoped_device_id_guard();
1142  GKO_ASSERT_NO_MPI_ERRORS(MPI_Scatter(
1143  send_buffer, send_count, type_impl<SendType>::get_type(),
1144  recv_buffer, recv_count, type_impl<RecvType>::get_type(), root_rank,
1145  this->get()));
1146  }
1147 
1167  template <typename SendType, typename RecvType>
1168  request i_scatter(std::shared_ptr<const Executor> exec,
1169  const SendType* send_buffer, const int send_count,
1170  RecvType* recv_buffer, const int recv_count,
1171  int root_rank) const
1172  {
1173  auto guard = exec->get_scoped_device_id_guard();
1174  request req;
1175  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iscatter(
1176  send_buffer, send_count, type_impl<SendType>::get_type(),
1177  recv_buffer, recv_count, type_impl<RecvType>::get_type(), root_rank,
1178  this->get(), req.get()));
1179  return req;
1180  }
1181 
1200  template <typename SendType, typename RecvType>
1201  void scatter_v(std::shared_ptr<const Executor> exec,
1202  const SendType* send_buffer, const int* send_counts,
1203  const int* displacements, RecvType* recv_buffer,
1204  const int recv_count, int root_rank) const
1205  {
1206  auto guard = exec->get_scoped_device_id_guard();
1207  GKO_ASSERT_NO_MPI_ERRORS(MPI_Scatterv(
1208  send_buffer, send_counts, displacements,
1209  type_impl<SendType>::get_type(), recv_buffer, recv_count,
1210  type_impl<RecvType>::get_type(), root_rank, this->get()));
1211  }
1212 
1233  template <typename SendType, typename RecvType>
1234  request i_scatter_v(std::shared_ptr<const Executor> exec,
1235  const SendType* send_buffer, const int* send_counts,
1236  const int* displacements, RecvType* recv_buffer,
1237  const int recv_count, int root_rank) const
1238  {
1239  auto guard = exec->get_scoped_device_id_guard();
1240  request req;
1241  GKO_ASSERT_NO_MPI_ERRORS(
1242  MPI_Iscatterv(send_buffer, send_counts, displacements,
1243  type_impl<SendType>::get_type(), recv_buffer,
1244  recv_count, type_impl<RecvType>::get_type(),
1245  root_rank, this->get(), req.get()));
1246  return req;
1247  }
1248 
1265  template <typename RecvType>
1266  void all_to_all(std::shared_ptr<const Executor> exec, RecvType* recv_buffer,
1267  const int recv_count) const
1268  {
1269  auto guard = exec->get_scoped_device_id_guard();
1270  GKO_ASSERT_NO_MPI_ERRORS(MPI_Alltoall(
1271  MPI_IN_PLACE, recv_count, type_impl<RecvType>::get_type(),
1272  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1273  this->get()));
1274  }
1275 
1294  template <typename RecvType>
1295  request i_all_to_all(std::shared_ptr<const Executor> exec,
1296  RecvType* recv_buffer, const int recv_count) const
1297  {
1298  auto guard = exec->get_scoped_device_id_guard();
1299  request req;
1300  GKO_ASSERT_NO_MPI_ERRORS(MPI_Ialltoall(
1301  MPI_IN_PLACE, recv_count, type_impl<RecvType>::get_type(),
1302  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1303  this->get(), req.get()));
1304  return req;
1305  }
1306 
1323  template <typename SendType, typename RecvType>
1324  void all_to_all(std::shared_ptr<const Executor> exec,
1325  const SendType* send_buffer, const int send_count,
1326  RecvType* recv_buffer, const int recv_count) const
1327  {
1328  auto guard = exec->get_scoped_device_id_guard();
1329  GKO_ASSERT_NO_MPI_ERRORS(MPI_Alltoall(
1330  send_buffer, send_count, type_impl<SendType>::get_type(),
1331  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1332  this->get()));
1333  }
1334 
1353  template <typename SendType, typename RecvType>
1354  request i_all_to_all(std::shared_ptr<const Executor> exec,
1355  const SendType* send_buffer, const int send_count,
1356  RecvType* recv_buffer, const int recv_count) const
1357  {
1358  auto guard = exec->get_scoped_device_id_guard();
1359  request req;
1360  GKO_ASSERT_NO_MPI_ERRORS(MPI_Ialltoall(
1361  send_buffer, send_count, type_impl<SendType>::get_type(),
1362  recv_buffer, recv_count, type_impl<RecvType>::get_type(),
1363  this->get(), req.get()));
1364  return req;
1365  }
1366 
1386  template <typename SendType, typename RecvType>
1387  void all_to_all_v(std::shared_ptr<const Executor> exec,
1388  const SendType* send_buffer, const int* send_counts,
1389  const int* send_offsets, RecvType* recv_buffer,
1390  const int* recv_counts, const int* recv_offsets) const
1391  {
1392  this->all_to_all_v(std::move(exec), send_buffer, send_counts,
1393  send_offsets, type_impl<SendType>::get_type(),
1394  recv_buffer, recv_counts, recv_offsets,
1396  }
1397 
1413  void all_to_all_v(std::shared_ptr<const Executor> exec,
1414  const void* send_buffer, const int* send_counts,
1415  const int* send_offsets, MPI_Datatype send_type,
1416  void* recv_buffer, const int* recv_counts,
1417  const int* recv_offsets, MPI_Datatype recv_type) const
1418  {
1419  auto guard = exec->get_scoped_device_id_guard();
1420  GKO_ASSERT_NO_MPI_ERRORS(MPI_Alltoallv(
1421  send_buffer, send_counts, send_offsets, send_type, recv_buffer,
1422  recv_counts, recv_offsets, recv_type, this->get()));
1423  }
1424 
1444  request i_all_to_all_v(std::shared_ptr<const Executor> exec,
1445  const void* send_buffer, const int* send_counts,
1446  const int* send_offsets, MPI_Datatype send_type,
1447  void* recv_buffer, const int* recv_counts,
1448  const int* recv_offsets,
1449  MPI_Datatype recv_type) const
1450  {
1451  auto guard = exec->get_scoped_device_id_guard();
1452  request req;
1453  GKO_ASSERT_NO_MPI_ERRORS(MPI_Ialltoallv(
1454  send_buffer, send_counts, send_offsets, send_type, recv_buffer,
1455  recv_counts, recv_offsets, recv_type, this->get(), req.get()));
1456  return req;
1457  }
1458 
1479  template <typename SendType, typename RecvType>
1480  request i_all_to_all_v(std::shared_ptr<const Executor> exec,
1481  const SendType* send_buffer, const int* send_counts,
1482  const int* send_offsets, RecvType* recv_buffer,
1483  const int* recv_counts,
1484  const int* recv_offsets) const
1485  {
1486  return this->i_all_to_all_v(
1487  std::move(exec), send_buffer, send_counts, send_offsets,
1488  type_impl<SendType>::get_type(), recv_buffer, recv_counts,
1489  recv_offsets, type_impl<RecvType>::get_type());
1490  }
1491 
1506  template <typename ScanType>
1507  void scan(std::shared_ptr<const Executor> exec, const ScanType* send_buffer,
1508  ScanType* recv_buffer, int count, MPI_Op operation) const
1509  {
1510  auto guard = exec->get_scoped_device_id_guard();
1511  GKO_ASSERT_NO_MPI_ERRORS(MPI_Scan(send_buffer, recv_buffer, count,
1513  operation, this->get()));
1514  }
1515 
1532  template <typename ScanType>
1533  request i_scan(std::shared_ptr<const Executor> exec,
1534  const ScanType* send_buffer, ScanType* recv_buffer,
1535  int count, MPI_Op operation) const
1536  {
1537  auto guard = exec->get_scoped_device_id_guard();
1538  request req;
1539  GKO_ASSERT_NO_MPI_ERRORS(MPI_Iscan(send_buffer, recv_buffer, count,
1541  operation, this->get(), req.get()));
1542  return req;
1543  }
1544 
1545 private:
1546  std::shared_ptr<MPI_Comm> comm_;
1547  bool force_host_buffer_;
1548 
1549  int get_my_rank() const
1550  {
1551  int my_rank = 0;
1552  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_rank(get(), &my_rank));
1553  return my_rank;
1554  }
1555 
1556  int get_node_local_rank() const
1557  {
1558  MPI_Comm local_comm;
1559  int rank;
1560  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_split_type(
1561  this->get(), MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &local_comm));
1562  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_rank(local_comm, &rank));
1563  MPI_Comm_free(&local_comm);
1564  return rank;
1565  }
1566 
1567  int get_num_ranks() const
1568  {
1569  int size = 1;
1570  GKO_ASSERT_NO_MPI_ERRORS(MPI_Comm_size(this->get(), &size));
1571  return size;
1572  }
1573 };
1574 
1575 
1580 bool requires_host_buffer(const std::shared_ptr<const Executor>& exec,
1581  const communicator& comm);
1582 
1583 
1589 inline double get_walltime() { return MPI_Wtime(); }
1590 
1591 
1600 template <typename ValueType>
1601 class window {
1602 public:
1606  enum class create_type { allocate = 1, create = 2, dynamic_create = 3 };
1607 
1611  enum class lock_type { shared = 1, exclusive = 2 };
1612 
1616  window() : window_(MPI_WIN_NULL) {}
1617 
1618  window(const window& other) = delete;
1619 
1620  window& operator=(const window& other) = delete;
1621 
1628  window(window&& other) : window_{std::exchange(other.window_, MPI_WIN_NULL)}
1629  {}
1630 
1638  {
1639  window_ = std::exchange(other.window_, MPI_WIN_NULL);
1640  }
1641 
1654  window(std::shared_ptr<const Executor> exec, ValueType* base, int num_elems,
1655  const communicator& comm, const int disp_unit = sizeof(ValueType),
1656  MPI_Info input_info = MPI_INFO_NULL,
1657  create_type c_type = create_type::create)
1658  {
1659  auto guard = exec->get_scoped_device_id_guard();
1660  unsigned size = num_elems * sizeof(ValueType);
1661  if (c_type == create_type::create) {
1662  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_create(
1663  base, size, disp_unit, input_info, comm.get(), &this->window_));
1664  } else if (c_type == create_type::dynamic_create) {
1665  GKO_ASSERT_NO_MPI_ERRORS(
1666  MPI_Win_create_dynamic(input_info, comm.get(), &this->window_));
1667  } else if (c_type == create_type::allocate) {
1668  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_allocate(
1669  size, disp_unit, input_info, comm.get(), base, &this->window_));
1670  } else {
1671  GKO_NOT_IMPLEMENTED;
1672  }
1673  }
1674 
1680  MPI_Win get_window() const { return this->window_; }
1681 
1688  void fence(int assert = 0) const
1689  {
1690  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_fence(assert, this->window_));
1691  }
1692 
1701  void lock(int rank, lock_type lock_t = lock_type::shared,
1702  int assert = 0) const
1703  {
1704  if (lock_t == lock_type::shared) {
1705  GKO_ASSERT_NO_MPI_ERRORS(
1706  MPI_Win_lock(MPI_LOCK_SHARED, rank, assert, this->window_));
1707  } else if (lock_t == lock_type::exclusive) {
1708  GKO_ASSERT_NO_MPI_ERRORS(
1709  MPI_Win_lock(MPI_LOCK_EXCLUSIVE, rank, assert, this->window_));
1710  } else {
1711  GKO_NOT_IMPLEMENTED;
1712  }
1713  }
1714 
1721  void unlock(int rank) const
1722  {
1723  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_unlock(rank, this->window_));
1724  }
1725 
1732  void lock_all(int assert = 0) const
1733  {
1734  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_lock_all(assert, this->window_));
1735  }
1736 
1741  void unlock_all() const
1742  {
1743  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_unlock_all(this->window_));
1744  }
1745 
1752  void flush(int rank) const
1753  {
1754  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_flush(rank, this->window_));
1755  }
1756 
1763  void flush_local(int rank) const
1764  {
1765  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_flush_local(rank, this->window_));
1766  }
1767 
1772  void flush_all() const
1773  {
1774  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_flush_all(this->window_));
1775  }
1776 
1781  void flush_all_local() const
1782  {
1783  GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_flush_local_all(this->window_));
1784  }
1785 
1789  void sync() const { GKO_ASSERT_NO_MPI_ERRORS(MPI_Win_sync(this->window_)); }
1790 
1795  {
1796  if (this->window_ && this->window_ != MPI_WIN_NULL) {
1797  MPI_Win_free(&this->window_);
1798  }
1799  }
1800 
1811  template <typename PutType>
1812  void put(std::shared_ptr<const Executor> exec, const PutType* origin_buffer,
1813  const int origin_count, const int target_rank,
1814  const unsigned int target_disp, const int target_count) const
1815  {
1816  auto guard = exec->get_scoped_device_id_guard();
1817  GKO_ASSERT_NO_MPI_ERRORS(
1818  MPI_Put(origin_buffer, origin_count, type_impl<PutType>::get_type(),
1819  target_rank, target_disp, target_count,
1821  }
1822 
1835  template <typename PutType>
1836  request r_put(std::shared_ptr<const Executor> exec,
1837  const PutType* origin_buffer, const int origin_count,
1838  const int target_rank, const unsigned int target_disp,
1839  const int target_count) const
1840  {
1841  auto guard = exec->get_scoped_device_id_guard();
1842  request req;
1843  GKO_ASSERT_NO_MPI_ERRORS(MPI_Rput(
1844  origin_buffer, origin_count, type_impl<PutType>::get_type(),
1845  target_rank, target_disp, target_count,
1846  type_impl<PutType>::get_type(), this->get_window(), req.get()));
1847  return req;
1848  }
1849 
1861  template <typename PutType>
1862  void accumulate(std::shared_ptr<const Executor> exec,
1863  const PutType* origin_buffer, const int origin_count,
1864  const int target_rank, const unsigned int target_disp,
1865  const int target_count, MPI_Op operation) const
1866  {
1867  auto guard = exec->get_scoped_device_id_guard();
1868  GKO_ASSERT_NO_MPI_ERRORS(MPI_Accumulate(
1869  origin_buffer, origin_count, type_impl<PutType>::get_type(),
1870  target_rank, target_disp, target_count,
1871  type_impl<PutType>::get_type(), operation, this->get_window()));
1872  }
1873 
1887  template <typename PutType>
1888  request r_accumulate(std::shared_ptr<const Executor> exec,
1889  const PutType* origin_buffer, const int origin_count,
1890  const int target_rank, const unsigned int target_disp,
1891  const int target_count, MPI_Op operation) const
1892  {
1893  auto guard = exec->get_scoped_device_id_guard();
1894  request req;
1895  GKO_ASSERT_NO_MPI_ERRORS(MPI_Raccumulate(
1896  origin_buffer, origin_count, type_impl<PutType>::get_type(),
1897  target_rank, target_disp, target_count,
1898  type_impl<PutType>::get_type(), operation, this->get_window(),
1899  req.get()));
1900  return req;
1901  }
1902 
1913  template <typename GetType>
1914  void get(std::shared_ptr<const Executor> exec, GetType* origin_buffer,
1915  const int origin_count, const int target_rank,
1916  const unsigned int target_disp, const int target_count) const
1917  {
1918  auto guard = exec->get_scoped_device_id_guard();
1919  GKO_ASSERT_NO_MPI_ERRORS(
1920  MPI_Get(origin_buffer, origin_count, type_impl<GetType>::get_type(),
1921  target_rank, target_disp, target_count,
1923  }
1924 
1937  template <typename GetType>
1938  request r_get(std::shared_ptr<const Executor> exec, GetType* origin_buffer,
1939  const int origin_count, const int target_rank,
1940  const unsigned int target_disp, const int target_count) const
1941  {
1942  auto guard = exec->get_scoped_device_id_guard();
1943  request req;
1944  GKO_ASSERT_NO_MPI_ERRORS(MPI_Rget(
1945  origin_buffer, origin_count, type_impl<GetType>::get_type(),
1946  target_rank, target_disp, target_count,
1947  type_impl<GetType>::get_type(), this->get_window(), req.get()));
1948  return req;
1949  }
1950 
1964  template <typename GetType>
1965  void get_accumulate(std::shared_ptr<const Executor> exec,
1966  GetType* origin_buffer, const int origin_count,
1967  GetType* result_buffer, const int result_count,
1968  const int target_rank, const unsigned int target_disp,
1969  const int target_count, MPI_Op operation) const
1970  {
1971  auto guard = exec->get_scoped_device_id_guard();
1972  GKO_ASSERT_NO_MPI_ERRORS(MPI_Get_accumulate(
1973  origin_buffer, origin_count, type_impl<GetType>::get_type(),
1974  result_buffer, result_count, type_impl<GetType>::get_type(),
1975  target_rank, target_disp, target_count,
1976  type_impl<GetType>::get_type(), operation, this->get_window()));
1977  }
1978 
1994  template <typename GetType>
1995  request r_get_accumulate(std::shared_ptr<const Executor> exec,
1996  GetType* origin_buffer, const int origin_count,
1997  GetType* result_buffer, const int result_count,
1998  const int target_rank,
1999  const unsigned int target_disp,
2000  const int target_count, MPI_Op operation) const
2001  {
2002  auto guard = exec->get_scoped_device_id_guard();
2003  request req;
2004  GKO_ASSERT_NO_MPI_ERRORS(MPI_Rget_accumulate(
2005  origin_buffer, origin_count, type_impl<GetType>::get_type(),
2006  result_buffer, result_count, type_impl<GetType>::get_type(),
2007  target_rank, target_disp, target_count,
2008  type_impl<GetType>::get_type(), operation, this->get_window(),
2009  req.get()));
2010  return req;
2011  }
2012 
2024  template <typename GetType>
2025  void fetch_and_op(std::shared_ptr<const Executor> exec,
2026  GetType* origin_buffer, GetType* result_buffer,
2027  const int target_rank, const unsigned int target_disp,
2028  MPI_Op operation) const
2029  {
2030  auto guard = exec->get_scoped_device_id_guard();
2031  GKO_ASSERT_NO_MPI_ERRORS(MPI_Fetch_and_op(
2032  origin_buffer, result_buffer, type_impl<GetType>::get_type(),
2033  target_rank, target_disp, operation, this->get_window()));
2034  }
2035 
2036 private:
2037  MPI_Win window_;
2038 };
2039 
2040 
2041 } // namespace mpi
2042 } // namespace experimental
2043 } // namespace gko
2044 
2045 
2046 #endif // GKO_HAVE_MPI
2047 
2048 
2049 #endif // GKO_PUBLIC_CORE_BASE_MPI_HPP_
gko::experimental::mpi::window
This class wraps the MPI_Window class with RAII functionality.
Definition: mpi.hpp:1601
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:1533
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:1507
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:1965
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:1701
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:758
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:459
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:1654
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:1354
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:1812
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:1606
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:1862
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:2025
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:1413
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:625
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:1234
gko::experimental::mpi::communicator::synchronize
void synchronize() const
This function is used to synchronize the ranks in the communicator.
Definition: mpi.hpp:606
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:1076
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:891
gko::experimental::mpi::window::get_window
MPI_Win get_window() const
Get the underlying window object of MPI_Win type.
Definition: mpi.hpp:1680
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:1688
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:733
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:1741
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:839
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:1295
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:531
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:1168
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:785
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:1772
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:1387
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:1045
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:1721
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:1781
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:1732
gko::experimental::mpi::window::lock_type
lock_type
The lock type for passive target synchronization of the windows.
Definition: mpi.hpp:1611
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:552
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:1888
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:476
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:1266
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:918
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:652
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:1136
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:1995
gko::experimental::mpi::window::~window
~window()
The deleter which calls MPI_Win_free when the window leaves its scope.
Definition: mpi.hpp:1794
gko::experimental::mpi::communicator::operator=
communicator & operator=(communicator &&other)
Definition: mpi.hpp:507
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:1616
gko::experimental::mpi::get_walltime
double get_walltime()
Get the rank in the communicator of the calling process.
Definition: mpi.hpp:1589
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:979
gko::experimental::mpi::communicator::rank
int rank() const
Return the rank of the calling process in the communicator.
Definition: mpi.hpp:538
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:864
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:592
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:1012
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:1201
gko::experimental::mpi::communicator::operator=
communicator & operator=(const communicator &other)=default
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:559
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:570
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:947
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:1106
gko::experimental::mpi::window::window
window(window &&other)
The move constructor.
Definition: mpi.hpp:1628
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:1763
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:497
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:1480
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:708
gko::experimental::mpi::window::sync
void sync() const
Synchronize the public and private buffers for the window object.
Definition: mpi.hpp:1789
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:1752
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:545
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:1444
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:1324
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:1938
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:680
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:813
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:1914
gko::experimental::mpi::window::operator=
window & operator=(window &&other)
The move assignment operator.
Definition: mpi.hpp:1637
gko::experimental::mpi::communicator::get
const MPI_Comm & get() const
Return the underlying MPI_Comm object.
Definition: mpi.hpp:522
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:1836