1 #include <type_traits>
2
3 namespace diy
4 {
5 namespace mpi
6 {
7
8 //! \ingroup MPI
9 //! Simple wrapper around MPI window functions.
10 template<class T>
11 class window
12 {
13 static_assert(std::is_same<typename detail::is_mpi_datatype<T>::type, detail::true_type>::value, "Only MPI datatypes are allowed in windows");
14
15 public:
16 inline window(const communicator& comm, unsigned size);
17 inline ~window();
18
19 // moving is Ok
20 window(window&&) = default;
21 window& operator=(window&&) = default;
22
23 // cannot copy because of the buffer_
24 window(const window&) = delete;
25 window& operator=(const window&) = delete;
26
27 inline void put(const T& x, int rank, unsigned offset);
28 inline void put(const std::vector<T>& x, int rank, unsigned offset);
29
30 inline void get(T& x, int rank, unsigned offset);
31 inline void get(std::vector<T>& x, int rank, unsigned offset);
32
33 inline void fence(int assert);
34
35 inline void lock(int lock_type, int rank, int assert = 0);
36 inline void unlock(int rank);
37
38 inline void lock_all(int assert = 0);
39 inline void unlock_all();
40
41 inline void fetch_and_op(const T* origin, T* result, int rank, unsigned offset, MPI_Op op);
42 inline void fetch(T& result, int rank, unsigned offset);
43 inline void replace(const T& value, int rank, unsigned offset);
44
45 inline void sync();
46
47 inline void flush(int rank);
48 inline void flush_all();
49 inline void flush_local(int rank);
50 inline void flush_local_all();
51
52 private:
53 std::vector<T> buffer_;
54 int rank_;
55 #ifndef DIY_NO_MPI
56 MPI_Win window_;
57 #endif
58 };
59 } // mpi
60 } // diy
61
62 template<class T>
63 diy::mpi::window<T>::
window(const communicator & comm,unsigned size)64 window(const communicator& comm, unsigned size):
65 buffer_(size), rank_(comm.rank())
66 {
67 #ifndef DIY_NO_MPI
68 MPI_Win_create(buffer_.data(), buffer_.size()*sizeof(T), sizeof(T), MPI_INFO_NULL, comm, &window_);
69 #endif
70 }
71
72 template<class T>
73 diy::mpi::window<T>::
~window()74 ~window()
75 {
76 #ifndef DIY_NO_MPI
77 MPI_Win_free(&window_);
78 #endif
79 }
80
81 template<class T>
82 void
83 diy::mpi::window<T>::
put(const T & x,int rank,unsigned offset)84 put(const T& x, int rank, unsigned offset)
85 {
86 #ifndef DIY_NO_MPI
87 MPI_Put(address(x), count(x), datatype(x),
88 rank,
89 offset,
90 count(x), datatype(x),
91 window_);
92 #else
93 buffer_[offset] = x;
94 #endif
95 }
96
97 template<class T>
98 void
99 diy::mpi::window<T>::
put(const std::vector<T> & x,int rank,unsigned offset)100 put(const std::vector<T>& x, int rank, unsigned offset)
101 {
102 #ifndef DIY_NO_MPI
103 MPI_Put(address(x), count(x), datatype(x),
104 rank,
105 offset,
106 count(x), datatype(x),
107 window_);
108 #else
109 for (size_t i = 0; i < x.size(); ++i)
110 buffer_[offset + i] = x[i];
111 #endif
112 }
113
114 template<class T>
115 void
116 diy::mpi::window<T>::
get(T & x,int rank,unsigned offset)117 get(T& x, int rank, unsigned offset)
118 {
119 #ifndef DIY_NO_MPI
120 MPI_Get(address(x), count(x), datatype(x),
121 rank,
122 offset,
123 count(x), datatype(x),
124 window_);
125 #else
126 x = buffer_[offset];
127 #endif
128 }
129
130 template<class T>
131 void
132 diy::mpi::window<T>::
get(std::vector<T> & x,int rank,unsigned offset)133 get(std::vector<T>& x, int rank, unsigned offset)
134 {
135 #ifndef DIY_NO_MPI
136 MPI_Get(address(x), count(x), datatype(x),
137 rank,
138 offset,
139 count(x), datatype(x),
140 window_);
141 #else
142 for (size_t i = 0; i < x.size(); ++i)
143 x[i] = buffer_[offset + i];
144 #endif
145 }
146
147 template<class T>
148 void
149 diy::mpi::window<T>::
fence(int assert)150 fence(int assert)
151 {
152 #ifndef DIY_NO_MPI
153 MPI_Win_fence(assert, window_);
154 #endif
155 }
156
157 template<class T>
158 void
159 diy::mpi::window<T>::
lock(int lock_type,int rank,int assert)160 lock(int lock_type, int rank, int assert)
161 {
162 #ifndef DIY_NO_MPI
163 MPI_Win_lock(lock_type, rank, assert, window_);
164 #endif
165 }
166
167 template<class T>
168 void
169 diy::mpi::window<T>::
unlock(int rank)170 unlock(int rank)
171 {
172 #ifndef DIY_NO_MPI
173 MPI_Win_unlock(rank, window_);
174 #endif
175 }
176
177 template<class T>
178 void
179 diy::mpi::window<T>::
lock_all(int assert)180 lock_all(int assert)
181 {
182 #ifndef DIY_NO_MPI
183 MPI_Win_lock_all(assert, window_);
184 #endif
185 }
186
187 template<class T>
188 void
189 diy::mpi::window<T>::
unlock_all()190 unlock_all()
191 {
192 #ifndef DIY_NO_MPI
193 MPI_Win_unlock_all(window_);
194 #endif
195 }
196 template<class T>
197 void
198 diy::mpi::window<T>::
fetch_and_op(const T * origin,T * result,int rank,unsigned offset,MPI_Op op)199 fetch_and_op(const T* origin, T* result, int rank, unsigned offset, MPI_Op op)
200 {
201 #ifndef DIY_NO_MPI
202 MPI_Fetch_and_op(origin, result, datatype(*origin), rank, offset, op, window_);
203 #else
204 DIY_UNSUPPORTED_MPI_CALL(MPI_Fetch_and_op);
205 #endif
206 }
207
208 template<class T>
209 void
210 diy::mpi::window<T>::
fetch(T & result,int rank,unsigned offset)211 fetch(T& result, int rank, unsigned offset)
212 {
213 #ifndef DIY_NO_MPI
214 T unused;
215 fetch_and_op(&unused, &result, rank, offset, MPI_NO_OP);
216 #else
217 result = buffer_[offset];
218 #endif
219 }
220
221 template<class T>
222 void
223 diy::mpi::window<T>::
replace(const T & value,int rank,unsigned offset)224 replace(const T& value, int rank, unsigned offset)
225 {
226 #ifndef DIY_NO_MPI
227 T unused;
228 fetch_and_op(&value, &unused, rank, offset, MPI_REPLACE);
229 #else
230 buffer_[offset] = value;
231 #endif
232 }
233
234 template<class T>
235 void
236 diy::mpi::window<T>::
sync()237 sync()
238 {
239 #ifndef DIY_NO_MPI
240 MPI_Win_sync(window_);
241 #endif
242 }
243
244 template<class T>
245 void
246 diy::mpi::window<T>::
flush(int rank)247 flush(int rank)
248 {
249 #ifndef DIY_NO_MPI
250 MPI_Win_flush(rank, window_);
251 #endif
252 }
253
254 template<class T>
255 void
256 diy::mpi::window<T>::
flush_all()257 flush_all()
258 {
259 #ifndef DIY_NO_MPI
260 MPI_Win_flush_all(window_);
261 #endif
262 }
263
264 template<class T>
265 void
266 diy::mpi::window<T>::
flush_local(int rank)267 flush_local(int rank)
268 {
269 #ifndef DIY_NO_MPI
270 MPI_Win_flush_local(rank, window_);
271 #endif
272 }
273
274 template<class T>
275 void
276 diy::mpi::window<T>::
flush_local_all()277 flush_local_all()
278 {
279 #ifndef DIY_NO_MPI
280 MPI_Win_flush_local_all(window_);
281 #endif
282 }
283