TRIQS/mpi 1.3.0
C++ interface to MPI
Loading...
Searching...
No Matches
window.hpp
Go to the documentation of this file.
1// Copyright (c) 2024 Simons Foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0.txt
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Authors: Thomas Hahn, Alexander Hampel, Olivier Parcollet, Nils Wentzell
16
21
22#pragma once
23
24#include "./communicator.hpp"
25#include "./datatypes.hpp"
26#include "./group.hpp"
27#include "./macros.hpp"
28#include "./utils.hpp"
29
30#include <mpi.h>
31
32#include <algorithm>
33#include <memory>
34#include <tuple>
35#include <utility>
36
37namespace mpi {
38
43
57 template <class BaseType> class window {
58 public:
60 using base_type = BaseType;
61
63 window() = default;
64
66 window(window const &) = delete;
67
69 window &operator=(window const &) = delete;
70
72 window(window &&other) noexcept
73 : win_{std::exchange(other.win_, MPI_WIN_NULL)},
74 comm_{std::exchange(other.comm_, communicator{MPI_COMM_NULL})},
75 owned_{std::exchange(other.owned_, false)},
76 data_{std::exchange(other.data_, nullptr)},
77 size_{std::exchange(other.size_, 0)} {}
78
80 window &operator=(window &&rhs) noexcept {
81 if (this != std::addressof(rhs)) {
82 free();
83 win_ = std::exchange(rhs.win_, MPI_WIN_NULL);
84 comm_ = std::exchange(rhs.comm_, communicator{MPI_COMM_NULL});
85 owned_ = std::exchange(rhs.owned_, false);
86 data_ = std::exchange(rhs.data_, nullptr);
87 size_ = std::exchange(rhs.size_, 0);
88 }
89 return *this;
90 }
91
104 explicit window(communicator const &c, BaseType *base_ptr, MPI_Aint sz, MPI_Info info = MPI_INFO_NULL)
105 : comm_(c.get()), data_(base_ptr), size_(sz) {
106 ASSERT(size_ >= 0)
107 ASSERT(!(data_ == nullptr && size_ > 0))
108 if (has_env) check_mpi_call(MPI_Win_create(data_, size_ * sizeof(BaseType), sizeof(BaseType), info, c.get(), &win_), "MPI_Win_create");
109 }
110
122 explicit window(communicator const &c, MPI_Aint sz, MPI_Info info = MPI_INFO_NULL) : comm_(c.get()), size_(sz) {
123 ASSERT(size_ >= 0)
124 if (has_env) {
125 check_mpi_call(MPI_Win_allocate(size_ * sizeof(BaseType), sizeof(BaseType), info, c.get(), &data_, &win_), "MPI_Win_allocate");
126 } else {
127 data_ = new BaseType[size_]; // NOLINT (new is fine here)
128 }
129 owned_ = true;
130 }
131
133 explicit operator MPI_Win() const { return win_; };
134
136 explicit operator MPI_Win *() { return &win_; };
137
139 virtual ~window() { free(); }
140
153 void free() noexcept {
154 if (has_env) {
155 if (win_ != MPI_WIN_NULL) {
156 MPI_Win_fence(0, win_);
157 MPI_Win_free(&win_);
158 }
159 } else if (owned_) {
160 delete[] data_;
161 }
162 owned_ = false;
163 data_ = nullptr;
164 size_ = 0;
165 }
166
175 void fence(int assert = 0) const {
176 if (has_env) check_mpi_call(MPI_Win_fence(assert, win_), "MPI_Win_fence");
177 }
178
187 void flush(int rank = -1) const {
188 if (has_env) {
189 if (rank < 0) {
190 check_mpi_call(MPI_Win_flush_all(win_), "MPI_Win_flush_all");
191 } else {
192 check_mpi_call(MPI_Win_flush(rank, win_), "MPI_Win_flush");
193 }
194 }
195 }
196
203 void sync() const {
204 if (has_env) check_mpi_call(MPI_Win_sync(win_), "MPI_Win_sync");
205 }
206
219 void lock(int rank = -1, int lock_type = MPI_LOCK_SHARED, int assert = 0) const {
220 if (has_env) {
221 if (rank < 0) {
222 check_mpi_call(MPI_Win_lock_all(assert, win_), "MPI_Win_lock_all");
223 } else {
224 check_mpi_call(MPI_Win_lock(lock_type, rank, assert, win_), "MPI_Win_lock");
225 }
226 }
227 }
228
239 void unlock(int rank = -1) const {
240 if (has_env) {
241 if (rank < 0) {
242 check_mpi_call(MPI_Win_unlock_all(win_), "MPI_Win_unlock_all");
243 } else {
244 check_mpi_call(MPI_Win_unlock(rank, win_), "MPI_Win_unlock");
245 }
246 }
247 }
248
255 void start(group const &grp, int assert = 0) const {
256 if (has_env) check_mpi_call(MPI_Win_start(grp.get(), assert, win_), "MPI_Win_start");
257 }
258
260 void complete() const {
261 if (has_env) check_mpi_call(MPI_Win_complete(win_), "MPI_Win_complete");
262 }
263
270 void post(group const &grp, int assert = 0) const {
271 if (has_env) check_mpi_call(MPI_Win_post(grp.get(), assert, win_), "MPI_Win_post");
272 }
273
275 void wait() const {
276 if (has_env) check_mpi_call(MPI_Win_wait(win_), "MPI_Win_wait");
277 }
278
294 template <typename TargetType = BaseType, typename OriginType>
296 void get(OriginType *origin_addr, int origin_count, int target_rank, MPI_Aint target_disp = 0, int target_count = -1) const {
297 ASSERT(origin_count >= 0 && target_disp >= 0);
298 target_count = target_count < 0 ? origin_count : target_count;
299 if (has_env) {
300 auto origin_datatype = mpi_type<OriginType>::get();
301 auto target_datatype = mpi_type<TargetType>::get();
302 check_mpi_call(MPI_Get(origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count, target_datatype, win_), "MPI_Get");
303 } else {
304 ASSERT(target_rank == 0); // there are no other ranks
305 std::copy(data_, data_ + target_count, origin_addr);
306 }
307 }
308
324 template <typename TargetType = BaseType, typename OriginType>
326 void put(OriginType *origin_addr, int origin_count, int target_rank, MPI_Aint target_disp = 0, int target_count = -1) const {
327 ASSERT(origin_count >= 0 && target_disp >= 0);
328 target_count = target_count < 0 ? origin_count : target_count;
329 if (has_env) {
330 auto origin_datatype = mpi_type<OriginType>::get();
331 auto target_datatype = mpi_type<TargetType>::get();
332 check_mpi_call(MPI_Put(origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count, target_datatype, win_), "MPI_Put");
333 } else {
334 ASSERT(target_rank == 0); // there are no other ranks
335 std::copy(origin_addr, origin_addr + origin_count, data_);
336 }
337 }
338
340 [[nodiscard]] BaseType *base() const { return data_; }
341
343 [[nodiscard]] MPI_Aint size() const { return size_; }
344
346 [[nodiscard]] int disp_unit() const { return sizeof(BaseType); }
347
349 [[nodiscard]] communicator get_communicator() const { return comm_; }
350
351 protected:
352 MPI_Win win_{MPI_WIN_NULL};
353 communicator comm_{MPI_COMM_NULL};
354 bool owned_{false};
355 BaseType *data_{nullptr};
356 MPI_Aint size_{0};
357 };
358
366 template <class BaseType> class shared_window : public window<BaseType> {
367 public:
369 shared_window() = default;
370
381 explicit shared_window(shared_communicator const &c, MPI_Aint sz, MPI_Info info = MPI_INFO_NULL) {
382 ASSERT(sz >= 0)
383 comm_ = c.get();
384 size_ = sz;
385 if (has_env) {
386 check_mpi_call(MPI_Win_allocate_shared(size_ * sizeof(BaseType), sizeof(BaseType), info, c.get(), &data_, &win_), "MPI_Win_allocate_shared");
387 } else {
388 data_ = new BaseType[size_]; // NOLINT (new is fine here)
389 }
390 owned_ = true;
391 }
392
405 [[nodiscard]] std::tuple<MPI_Aint, int, void *> query(int rank = MPI_PROC_NULL) const {
406 if (has_env) {
407 MPI_Aint sz = 0;
408 int du = 0;
409 void *baseptr = nullptr;
410 check_mpi_call(MPI_Win_shared_query(win_, rank, &sz, &du, &baseptr), "MPI_Win_shared_query");
411 return {sz, du, baseptr};
412 } else {
413 return {size_, sizeof(BaseType), data_};
414 }
415 }
416
423 [[nodiscard]] BaseType *base(int rank = MPI_PROC_NULL) const { return static_cast<BaseType *>(std::get<2>(query(rank))); }
424
431 [[nodiscard]] MPI_Aint size(int rank = MPI_PROC_NULL) const { return std::get<0>(query(rank)) / sizeof(BaseType); }
432
439 [[nodiscard]] int disp_unit(int rank = MPI_PROC_NULL) const { return std::get<1>(query(rank)); }
440
442 [[nodiscard]] shared_communicator get_communicator() const { return comm_.get(); }
443
444 private:
445 using window<BaseType>::win_;
446 using window<BaseType>::comm_;
447 using window<BaseType>::owned_;
448 using window<BaseType>::data_;
449 using window<BaseType>::size_;
450 };
451
453
454} // namespace mpi
C++ wrapper around MPI_Comm providing various convenience functions.
MPI_Comm get() const noexcept
Get the wrapped MPI_Comm object.
C++ wrapper around MPI_Group providing various convenience functions.
Definition group.hpp:46
MPI_Group get() const noexcept
Get the wrapped MPI_Group object.
Definition group.hpp:87
C++ wrapper around MPI_Comm that is a result of the mpi::communicator::split_shared operation.
shared_communicator get_communicator() const
Get the mpi::shared_communicator associated with the window.
Definition window.hpp:442
shared_window()=default
Construct a shared memory window with MPI_WIN_NULL.
int disp_unit(int rank=MPI_PROC_NULL) const
Get the displacement unit of the shared memory region of a specific rank.
Definition window.hpp:439
std::tuple< MPI_Aint, int, void * > query(int rank=MPI_PROC_NULL) const
Query attributes of a shared memory window.
Definition window.hpp:405
shared_window(shared_communicator const &c, MPI_Aint sz, MPI_Info info=MPI_INFO_NULL)
Construct a shared memory window by dynamically allocating memory.
Definition window.hpp:381
BaseType * base(int rank=MPI_PROC_NULL) const
Get a pointer to the beginning of the shared memory region of a specific rank.
Definition window.hpp:423
MPI_Aint size(int rank=MPI_PROC_NULL) const
Get the size of the shared memory region of a specific rank.
Definition window.hpp:431
A C++ wrapper around MPI_Win providing convenient memory window management.
Definition window.hpp:57
int disp_unit() const
Get the displacement unit in bytes.
Definition window.hpp:346
BaseType base_type
Type of the base pointer.
Definition window.hpp:60
void lock(int rank=-1, int lock_type=MPI_LOCK_SHARED, int assert=0) const
Start an RMA access epoch.
Definition window.hpp:219
window()=default
Construct a window with MPI_WIN_NULL.
void get(OriginType *origin_addr, int origin_count, int target_rank, MPI_Aint target_disp=0, int target_count=-1) const
Read data from a remote memory window.
Definition window.hpp:296
window(communicator const &c, BaseType *base_ptr, MPI_Aint sz, MPI_Info info=MPI_INFO_NULL)
Construct an MPI window over an existing local memory buffer.
Definition window.hpp:104
window(window const &)=delete
Deleted copy constructor.
void post(group const &grp, int assert=0) const
Start an RMA exposure epoch by calling MPI_Win_post (see also wait()).
Definition window.hpp:270
void complete() const
Completes an RMA access epoch by calling MPI_Win_complete (see also start()).
Definition window.hpp:260
virtual ~window()
Destructor calls free() to release the window.
Definition window.hpp:139
MPI_Aint size() const
Get the size of the window in number of elements.
Definition window.hpp:343
void put(OriginType *origin_addr, int origin_count, int target_rank, MPI_Aint target_disp=0, int target_count=-1) const
Write data to a remote memory window.
Definition window.hpp:326
void start(group const &grp, int assert=0) const
Start an RMA access epoch by calling MPI_Win_start (see also complete()).
Definition window.hpp:255
window(communicator const &c, MPI_Aint sz, MPI_Info info=MPI_INFO_NULL)
Construct an MPI window with dynamically allocated memory.
Definition window.hpp:122
void fence(int assert=0) const
Synchronize all RMA operations within an access epoch by calling MPI_Win_fence.
Definition window.hpp:175
void flush(int rank=-1) const
Ensure completion of all outstanding RMA operations.
Definition window.hpp:187
void free() noexcept
Release allocated resources owned by the window.
Definition window.hpp:153
BaseType * base() const
Get a pointer to the beginning of the window memory.
Definition window.hpp:340
window & operator=(window &&rhs) noexcept
Move assignment operator takes ownership of the moved-from MPI window and leaves it with MPI_WIN_NULL...
Definition window.hpp:80
void wait() const
Completes an RMA exposure epoch by calling MPI_Win_wait (see also post()).
Definition window.hpp:275
window & operator=(window const &)=delete
Deleted copy assignment operator.
void unlock(int rank=-1) const
Complete an RMA access epoch started by lock().
Definition window.hpp:239
void sync() const
Synchronize the public and private copies of the window.
Definition window.hpp:203
window(window &&other) noexcept
Move constructor takes ownership of the moved-from MPI window and leaves it with MPI_WIN_NULL.
Definition window.hpp:72
communicator get_communicator() const
Get the mpi::communicator associated with the window.
Definition window.hpp:349
Provides a C++ wrapper class for an MPI_Comm object.
Provides utilities to map C++ datatypes to MPI datatypes.
Provides a C++ wrapper class for an MPI_Group object.
static const bool has_env
Boolean variable that is true, if one of the environment variables OMPI_COMM_WORLD_RANK,...
constexpr bool has_mpi_type
Type trait to check if a type T has a corresponding MPI datatype, i.e. if mpi::mpi_type has been spec...
Definition datatypes.hpp:99
void check_mpi_call(int errcode, const std::string &mpi_routine)
Check the success of an MPI call.
Definition utils.hpp:51
Macros used in the mpi library.
Map C++ datatypes to the corresponding MPI datatypes.
Definition datatypes.hpp:58
Provides general utilities related to MPI.