TRIQS/mpi 2.0.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
59 template <class BaseType> class window {
60 public:
62 using base_type = BaseType;
63
65 window() = default;
66
68 window(window const &) = delete;
69
71 window &operator=(window const &) = delete;
72
74 window(window &&other) noexcept
75 : win_{std::exchange(other.win_, MPI_WIN_NULL)},
76 comm_{std::exchange(other.comm_, communicator{MPI_COMM_NULL})},
77 owned_{std::exchange(other.owned_, false)},
78 data_{std::exchange(other.data_, nullptr)},
79 size_{std::exchange(other.size_, 0)} {}
80
82 window &operator=(window &&rhs) noexcept {
83 if (this != std::addressof(rhs)) {
84 free();
85 win_ = std::exchange(rhs.win_, MPI_WIN_NULL);
86 comm_ = std::exchange(rhs.comm_, communicator{MPI_COMM_NULL});
87 owned_ = std::exchange(rhs.owned_, false);
88 data_ = std::exchange(rhs.data_, nullptr);
89 size_ = std::exchange(rhs.size_, 0);
90 }
91 return *this;
92 }
93
106 explicit window(communicator const &c, BaseType *base_ptr, MPI_Aint sz, MPI_Info info = MPI_INFO_NULL)
107 : comm_(c.get()), data_(base_ptr), size_(sz) {
108 ASSERT(size_ >= 0)
109 ASSERT(!(data_ == nullptr && size_ > 0))
110 if (has_env) check_mpi_call(MPI_Win_create(data_, size_ * sizeof(BaseType), sizeof(BaseType), info, c.get(), &win_), "MPI_Win_create");
111 }
112
124 explicit window(communicator const &c, MPI_Aint sz, MPI_Info info = MPI_INFO_NULL) : comm_(c.get()), size_(sz) {
125 ASSERT(size_ >= 0)
126 if (has_env) {
127 check_mpi_call(MPI_Win_allocate(size_ * sizeof(BaseType), sizeof(BaseType), info, c.get(), &data_, &win_), "MPI_Win_allocate");
128 } else {
129 data_ = new BaseType[size_]; // NOLINT (new is fine here)
130 }
131 owned_ = true;
132 }
133
135 explicit operator MPI_Win() const { return win_; };
136
138 explicit operator MPI_Win *() { return &win_; };
139
141 virtual ~window() { free(); }
142
155 void free() noexcept {
156 if (has_env) {
157 if (win_ != MPI_WIN_NULL) {
158 MPI_Win_fence(0, win_);
159 MPI_Win_free(&win_);
160 }
161 } else if (owned_) {
162 delete[] data_;
163 }
164 owned_ = false;
165 data_ = nullptr;
166 size_ = 0;
167 }
168
177 void fence(int assert = 0) const {
178 if (has_env) check_mpi_call(MPI_Win_fence(assert, win_), "MPI_Win_fence");
179 }
180
189 void flush(int rank = -1) const {
190 if (has_env) {
191 if (rank < 0) {
192 check_mpi_call(MPI_Win_flush_all(win_), "MPI_Win_flush_all");
193 } else {
194 check_mpi_call(MPI_Win_flush(rank, win_), "MPI_Win_flush");
195 }
196 }
197 }
198
205 void sync() const {
206 if (has_env) check_mpi_call(MPI_Win_sync(win_), "MPI_Win_sync");
207 }
208
221 void lock(int rank = -1, int lock_type = MPI_LOCK_SHARED, int assert = 0) const {
222 if (has_env) {
223 if (rank < 0) {
224 check_mpi_call(MPI_Win_lock_all(assert, win_), "MPI_Win_lock_all");
225 } else {
226 check_mpi_call(MPI_Win_lock(lock_type, rank, assert, win_), "MPI_Win_lock");
227 }
228 }
229 }
230
241 void unlock(int rank = -1) const {
242 if (has_env) {
243 if (rank < 0) {
244 check_mpi_call(MPI_Win_unlock_all(win_), "MPI_Win_unlock_all");
245 } else {
246 check_mpi_call(MPI_Win_unlock(rank, win_), "MPI_Win_unlock");
247 }
248 }
249 }
250
257 void start(group const &grp, int assert = 0) const {
258 if (has_env) check_mpi_call(MPI_Win_start(grp.get(), assert, win_), "MPI_Win_start");
259 }
260
262 void complete() const {
263 if (has_env) check_mpi_call(MPI_Win_complete(win_), "MPI_Win_complete");
264 }
265
272 void post(group const &grp, int assert = 0) const {
273 if (has_env) check_mpi_call(MPI_Win_post(grp.get(), assert, win_), "MPI_Win_post");
274 }
275
277 void wait() const {
278 if (has_env) check_mpi_call(MPI_Win_wait(win_), "MPI_Win_wait");
279 }
280
296 template <typename TargetType = BaseType, typename OriginType>
298 void get(OriginType *origin_addr, int origin_count, int target_rank, MPI_Aint target_disp = 0, int target_count = -1) const {
299 ASSERT(origin_count >= 0 && target_disp >= 0);
300 target_count = target_count < 0 ? origin_count : target_count;
301 if (has_env) {
302 auto origin_datatype = mpi_type<OriginType>::get();
303 auto target_datatype = mpi_type<TargetType>::get();
304 check_mpi_call(MPI_Get(origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count, target_datatype, win_), "MPI_Get");
305 } else {
306 ASSERT(target_rank == 0); // there are no other ranks
307 std::copy(data_, data_ + target_count, origin_addr);
308 }
309 }
310
326 template <typename TargetType = BaseType, typename OriginType>
328 void put(OriginType *origin_addr, int origin_count, int target_rank, MPI_Aint target_disp = 0, int target_count = -1) const {
329 ASSERT(origin_count >= 0 && target_disp >= 0);
330 target_count = target_count < 0 ? origin_count : target_count;
331 if (has_env) {
332 auto origin_datatype = mpi_type<OriginType>::get();
333 auto target_datatype = mpi_type<TargetType>::get();
334 check_mpi_call(MPI_Put(origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count, target_datatype, win_), "MPI_Put");
335 } else {
336 ASSERT(target_rank == 0); // there are no other ranks
337 std::copy(origin_addr, origin_addr + origin_count, data_);
338 }
339 }
340
342 [[nodiscard]] BaseType *base() const { return data_; }
343
345 [[nodiscard]] MPI_Aint size() const { return size_; }
346
348 [[nodiscard]] int disp_unit() const { return sizeof(BaseType); }
349
351 [[nodiscard]] communicator get_communicator() const { return comm_; }
352
353 protected:
354 MPI_Win win_{MPI_WIN_NULL};
355 communicator comm_{MPI_COMM_NULL};
356 bool owned_{false};
357 BaseType *data_{nullptr};
358 MPI_Aint size_{0};
359 };
360
370 template <class BaseType> class shared_window : public window<BaseType> {
371 public:
373 shared_window() = default;
374
385 explicit shared_window(shared_communicator const &c, MPI_Aint sz, MPI_Info info = MPI_INFO_NULL) {
386 ASSERT(sz >= 0)
387 comm_ = c.get();
388 size_ = sz;
389 if (has_env) {
390 check_mpi_call(MPI_Win_allocate_shared(size_ * sizeof(BaseType), sizeof(BaseType), info, c.get(), &data_, &win_), "MPI_Win_allocate_shared");
391 } else {
392 data_ = new BaseType[size_]; // NOLINT (new is fine here)
393 }
394 owned_ = true;
395 }
396
409 [[nodiscard]] std::tuple<MPI_Aint, int, void *> query(int rank = MPI_PROC_NULL) const {
410 if (has_env) {
411 MPI_Aint sz = 0;
412 int du = 0;
413 void *baseptr = nullptr;
414 check_mpi_call(MPI_Win_shared_query(win_, rank, &sz, &du, &baseptr), "MPI_Win_shared_query");
415 return {sz, du, baseptr};
416 } else {
417 return {size_, sizeof(BaseType), data_};
418 }
419 }
420
427 [[nodiscard]] BaseType *base(int rank = MPI_PROC_NULL) const { return static_cast<BaseType *>(std::get<2>(query(rank))); }
428
435 [[nodiscard]] MPI_Aint size(int rank = MPI_PROC_NULL) const { return std::get<0>(query(rank)) / sizeof(BaseType); }
436
443 [[nodiscard]] int disp_unit(int rank = MPI_PROC_NULL) const { return std::get<1>(query(rank)); }
444
446 [[nodiscard]] shared_communicator get_communicator() const { return comm_.get(); }
447
448 private:
449 using window<BaseType>::win_;
450 using window<BaseType>::comm_;
451 using window<BaseType>::owned_;
452 using window<BaseType>::data_;
453 using window<BaseType>::size_;
454 };
455
457
458} // 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:446
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:443
std::tuple< MPI_Aint, int, void * > query(int rank=MPI_PROC_NULL) const
Query attributes of a shared memory window.
Definition window.hpp:409
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:385
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:427
MPI_Aint size(int rank=MPI_PROC_NULL) const
Get the size of the shared memory region of a specific rank.
Definition window.hpp:435
A C++ wrapper around MPI_Win providing convenient memory window management.
Definition window.hpp:59
int disp_unit() const
Get the displacement unit in bytes.
Definition window.hpp:348
BaseType base_type
Type of the base pointer.
Definition window.hpp:62
void lock(int rank=-1, int lock_type=MPI_LOCK_SHARED, int assert=0) const
Start an RMA access epoch.
Definition window.hpp:221
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:298
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:106
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:272
void complete() const
Completes an RMA access epoch by calling MPI_Win_complete (see also start()).
Definition window.hpp:262
virtual ~window()
Destructor calls free() to release the window.
Definition window.hpp:141
MPI_Aint size() const
Get the size of the window in number of elements.
Definition window.hpp:345
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:328
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:257
window(communicator const &c, MPI_Aint sz, MPI_Info info=MPI_INFO_NULL)
Construct an MPI window with dynamically allocated memory.
Definition window.hpp:124
void fence(int assert=0) const
Synchronize all RMA operations within an access epoch by calling MPI_Win_fence.
Definition window.hpp:177
void flush(int rank=-1) const
Ensure completion of all outstanding RMA operations.
Definition window.hpp:189
void free() noexcept
Release allocated resources owned by the window.
Definition window.hpp:155
BaseType * base() const
Get a pointer to the beginning of the window memory.
Definition window.hpp:342
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:82
void wait() const
Completes an RMA exposure epoch by calling MPI_Win_wait (see also post()).
Definition window.hpp:277
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:241
void sync() const
Synchronize the public and private copies of the window.
Definition window.hpp:205
window(window &&other) noexcept
Move constructor takes ownership of the moved-from MPI window and leaves it with MPI_WIN_NULL.
Definition window.hpp:74
communicator get_communicator() const
Get the mpi::communicator associated with the window.
Definition window.hpp:351
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 checks if there is an active MPI runtime environment.
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...
void check_mpi_call(int errcode, const std::string &mpi_routine)
Check the success of an MPI call.
Definition utils.hpp:48
Macros used in the mpi library.
Map C++ datatypes to the corresponding MPI datatypes.
Definition datatypes.hpp:60
Provides general utilities related to MPI.