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 MPI_Win window_;
56 };
57 } // mpi
58 } // diy
59
60 template<class T>
61 diy::mpi::window<T>::
window(const communicator & comm,unsigned size)62 window(const communicator& comm, unsigned size):
63 buffer_(size), rank_(comm.rank())
64 {
65 #ifndef DIY_NO_MPI
66 MPI_Win_create(buffer_.data(), buffer_.size()*sizeof(T), sizeof(T), MPI_INFO_NULL, comm, &window_);
67 #endif
68 }
69
70 template<class T>
71 diy::mpi::window<T>::
~window()72 ~window()
73 {
74 #ifndef DIY_NO_MPI
75 MPI_Win_free(&window_);
76 #endif
77 }
78
79 template<class T>
80 void
81 diy::mpi::window<T>::
put(const T & x,int rank,unsigned offset)82 put(const T& x, int rank, unsigned offset)
83 {
84 #ifndef DIY_NO_MPI
85 MPI_Put(address(x), count(x), datatype(x),
86 rank,
87 offset,
88 count(x), datatype(x),
89 window_);
90 #else
91 buffer_[offset] = x;
92 #endif
93 }
94
95 template<class T>
96 void
97 diy::mpi::window<T>::
put(const std::vector<T> & x,int rank,unsigned offset)98 put(const std::vector<T>& x, int rank, unsigned offset)
99 {
100 #ifndef DIY_NO_MPI
101 MPI_Put(address(x), count(x), datatype(x),
102 rank,
103 offset,
104 count(x), datatype(x),
105 window_);
106 #else
107 for (size_t i = 0; i < x.size(); ++i)
108 buffer_[offset + i] = x[i];
109 #endif
110 }
111
112 template<class T>
113 void
114 diy::mpi::window<T>::
get(T & x,int rank,unsigned offset)115 get(T& x, int rank, unsigned offset)
116 {
117 #ifndef DIY_NO_MPI
118 MPI_Get(address(x), count(x), datatype(x),
119 rank,
120 offset,
121 count(x), datatype(x),
122 window_);
123 #else
124 x = buffer_[offset];
125 #endif
126 }
127
128 template<class T>
129 void
130 diy::mpi::window<T>::
get(std::vector<T> & x,int rank,unsigned offset)131 get(std::vector<T>& x, int rank, unsigned offset)
132 {
133 #ifndef DIY_NO_MPI
134 MPI_Get(address(x), count(x), datatype(x),
135 rank,
136 offset,
137 count(x), datatype(x),
138 window_);
139 #else
140 for (size_t i = 0; i < x.size(); ++i)
141 x[i] = buffer_[offset + i];
142 #endif
143 }
144
145 template<class T>
146 void
147 diy::mpi::window<T>::
fence(int assert)148 fence(int assert)
149 {
150 #ifndef DIY_NO_MPI
151 MPI_Win_fence(assert, window_);
152 #endif
153 }
154
155 template<class T>
156 void
157 diy::mpi::window<T>::
lock(int lock_type,int rank,int assert)158 lock(int lock_type, int rank, int assert)
159 {
160 #ifndef DIY_NO_MPI
161 MPI_Win_lock(lock_type, rank, assert, window_);
162 #endif
163 }
164
165 template<class T>
166 void
167 diy::mpi::window<T>::
unlock(int rank)168 unlock(int rank)
169 {
170 #ifndef DIY_NO_MPI
171 MPI_Win_unlock(rank, window_);
172 #endif
173 }
174
175 template<class T>
176 void
177 diy::mpi::window<T>::
lock_all(int assert)178 lock_all(int assert)
179 {
180 #ifndef DIY_NO_MPI
181 MPI_Win_lock_all(assert, window_);
182 #endif
183 }
184
185 template<class T>
186 void
187 diy::mpi::window<T>::
unlock_all()188 unlock_all()
189 {
190 #ifndef DIY_NO_MPI
191 MPI_Win_unlock_all(window_);
192 #endif
193 }
194 template<class T>
195 void
196 diy::mpi::window<T>::
fetch_and_op(const T * origin,T * result,int rank,unsigned offset,MPI_Op op)197 fetch_and_op(const T* origin, T* result, int rank, unsigned offset, MPI_Op op)
198 {
199 #ifndef DIY_NO_MPI
200 MPI_Fetch_and_op(origin, result, datatype(*origin), rank, offset, op, window_);
201 #else
202 DIY_UNSUPPORTED_MPI_CALL(MPI_Fetch_and_op);
203 #endif
204 }
205
206 template<class T>
207 void
208 diy::mpi::window<T>::
fetch(T & result,int rank,unsigned offset)209 fetch(T& result, int rank, unsigned offset)
210 {
211 #ifndef DIY_NO_MPI
212 T unused;
213 fetch_and_op(&unused, &result, rank, offset, MPI_NO_OP);
214 #else
215 result = buffer_[offset];
216 #endif
217 }
218
219 template<class T>
220 void
221 diy::mpi::window<T>::
replace(const T & value,int rank,unsigned offset)222 replace(const T& value, int rank, unsigned offset)
223 {
224 #ifndef DIY_NO_MPI
225 T unused;
226 fetch_and_op(&value, &unused, rank, offset, MPI_REPLACE);
227 #else
228 buffer_[offset] = value;
229 #endif
230 }
231
232 template<class T>
233 void
234 diy::mpi::window<T>::
sync()235 sync()
236 {
237 #ifndef DIY_NO_MPI
238 MPI_Win_sync(window_);
239 #endif
240 }
241
242 template<class T>
243 void
244 diy::mpi::window<T>::
flush(int rank)245 flush(int rank)
246 {
247 #ifndef DIY_NO_MPI
248 MPI_Win_flush(rank, window_);
249 #endif
250 }
251
252 template<class T>
253 void
254 diy::mpi::window<T>::
flush_all()255 flush_all()
256 {
257 #ifndef DIY_NO_MPI
258 MPI_Win_flush_all(window_);
259 #endif
260 }
261
262 template<class T>
263 void
264 diy::mpi::window<T>::
flush_local(int rank)265 flush_local(int rank)
266 {
267 #ifndef DIY_NO_MPI
268 MPI_Win_flush_local(rank, window_);
269 #endif
270 }
271
272 template<class T>
273 void
274 diy::mpi::window<T>::
flush_local_all()275 flush_local_all()
276 {
277 #ifndef DIY_NO_MPI
278 MPI_Win_flush_local_all(window_);
279 #endif
280 }
281