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