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