dune-common  2.11
mpifuture.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5 #ifndef DUNE_COMMON_PARALLEL_MPIFUTURE_HH
6 #define DUNE_COMMON_PARALLEL_MPIFUTURE_HH
7 
8 #if HAVE_MPI
9 
10 #include <functional>
11 #include <memory>
12 #include <optional>
13 #include <type_traits>
14 #include <utility>
15 
16 #include <mpi.h>
17 
22 
23 namespace Dune{
24 
25  namespace Impl{
26  template<class T>
27  struct Buffer{
28  Buffer(bool valid){
29  if(valid)
30  value = std::make_unique<T>();
31  }
32  template<class V>
33  Buffer(V&& t)
34  : value(std::make_unique<T>(std::forward<V>(t)))
35  {}
36  std::unique_ptr<T> value;
37  T get(){
38  T tmp = std::move(*value);
39  value.reset();
40  return tmp;
41  }
42  operator bool () const {
43  return (bool)value;
44  }
45  T& operator *() const{
46  return *value;
47  }
48  };
49 
50  template<class T>
51  struct Buffer<T&>{
52  Buffer(bool valid = false)
53  {
54  if(valid)
55  value = T();
56  }
57  template<class V>
58  Buffer(V&& t)
59  : value(std::forward<V>(t))
60  {}
61  std::optional<std::reference_wrapper<T>> value;
62  T& get(){
63  T& tmp = *value;
64  value.reset();
65  return tmp;
66  }
67  operator bool () const{
68  return (bool)value;
69  }
70  T& operator *() const{
71  return *value;
72  }
73  };
74 
75  template<>
76  struct Buffer<void>{
77  bool valid_;
78  Buffer(bool valid = false)
79  : valid_(valid)
80  {}
81  operator bool () const{
82  return valid_;
83  }
84  void get(){}
85  };
86  }
87 
92  template<class R, class S = void>
93  class MPIFuture{
94  mutable MPI_Request req_;
95  mutable MPI_Status status_;
96  Impl::Buffer<R> data_;
97  Impl::Buffer<S> send_data_;
98  friend class Communication<MPI_Comm>;
99  public:
100  MPIFuture(bool valid = false)
101  : req_(MPI_REQUEST_NULL)
102  , data_(valid)
103  {}
104 
105  // Hide this constructor if R or S is void
106  template<class V = R, class U = S>
107  MPIFuture(V&& recv_data, U&& send_data, typename std::enable_if_t<!std::is_void<V>::value && !std::is_void<U>::value>* = 0) :
108  req_(MPI_REQUEST_NULL)
109  , data_(std::forward<R>(recv_data))
110  , send_data_(std::forward<S>(send_data))
111  {}
112 
113  // hide this constructor if R is void
114  template<class V = R>
115  MPIFuture(V&& recv_data, typename std::enable_if_t<!std::is_void<V>::value>* = 0)
116  : req_(MPI_REQUEST_NULL)
117  , data_(std::forward<V>(recv_data))
118  {}
119 
121  if(req_ != MPI_REQUEST_NULL){
122  try{ // might fail when it is a collective communication
123  MPI_Cancel(&req_);
124  MPI_Request_free(&req_);
125  }catch(...){
126  }
127  }
128  }
129 
131  : req_(MPI_REQUEST_NULL)
132  , data_(std::move(f.data_))
133  , send_data_(std::move(f.send_data_))
134  {
135  std::swap(req_, f.req_);
136  std::swap(status_, f.status_);
137  }
138 
140  std::swap(req_, f.req_);
141  std::swap(status_, f.status_);
142  std::swap(data_, f.data_);
143  std::swap(send_data_, f.send_data_);
144  return *this;
145  }
146 
147  bool valid() const{
148  return (bool)data_;
149  }
150 
151  void wait(){
152  if(!valid())
153  DUNE_THROW(InvalidFutureException, "The MPIFuture is not valid!");
154  MPI_Wait(&req_, &status_);
155  }
156 
157  bool ready() const{
158  int flag = -1;
159  MPI_Test(&req_, &flag, &status_);
160  return flag;
161  }
162 
163  R get() {
164  wait();
165  return data_.get();
166  }
167 
169  wait();
170  return send_data_.get();
171  }
172 
173  auto get_mpidata(){
174  return getMPIData(*data_);
175  }
176 
178  return getMPIData(*send_data_);
179  }
180  };
181 
182 }
183 #endif // HAVE_MPI
184 #endif // DUNE_COMMON_PARALLEL_MPIFUTURE_HH
bool ready() const
Definition: mpifuture.hh:157
~MPIFuture()
Definition: mpifuture.hh:120
MPIFuture(V &&recv_data, typename std::enable_if_t<!std::is_void< V >::value > *=0)
Definition: mpifuture.hh:115
auto getMPIData(T &t)
Definition: mpidata.hh:44
auto get_send_mpidata()
Definition: mpifuture.hh:177
void wait()
Definition: mpifuture.hh:151
bool valid() const
Definition: mpifuture.hh:147
auto get_mpidata()
Definition: mpifuture.hh:173
MPIFuture(bool valid=false)
Definition: mpifuture.hh:100
S get_send_data()
Definition: mpifuture.hh:168
bigunsignedint< k > operator*(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:572
Interface class to translate objects to a MPI_Datatype, void* and size used for MPI calls...
MPIFuture(V &&recv_data, U &&send_data, typename std::enable_if_t<!std::is_void< V >::value &&!std::is_void< U >::value > *=0)
Definition: mpifuture.hh:107
This exception is thrown when ready(), wait() or get() is called on an invalid future. A future is valid until get() is called and if it is not default-constructed and it was not moved from.
Definition: future.hh:19
Collective communication interface and sequential default implementation.
Definition: communication.hh:99
Dune namespace
Definition: alignedallocator.hh:12
#define DUNE_THROW(E,...)
Definition: exceptions.hh:314
MPIFuture & operator=(MPIFuture &&f)
Definition: mpifuture.hh:139
A few common exception classes.
void swap(T &v1, T &v2, bool mask)
Definition: simd.hh:472
STL namespace.
Implements an utility class that provides collective communication methods for sequential programs...
Provides a future-like object for MPI communication. It contains the object that will be received and...
Definition: mpifuture.hh:93
MPIFuture(MPIFuture &&f)
Definition: mpifuture.hh:130