From 70bef37f4878b1cfef2376d8ae614758820e1350 Mon Sep 17 00:00:00 2001 From: Doc CI Action Date: Tue, 12 Dec 2023 16:29:25 +0000 Subject: [PATCH] Doc: Use `drop_operation_state` to avoid stack overflows (#1004) --- ...lver_2band__to__tridiag_2mc_8h_source.html | 4 +- master/transform_8h_source.html | 259 ++++++++-------- master/transform__mpi_8h_source.html | 285 +++++++++--------- 3 files changed, 278 insertions(+), 270 deletions(-) diff --git a/master/eigensolver_2band__to__tridiag_2mc_8h_source.html b/master/eigensolver_2band__to__tridiag_2mc_8h_source.html index 35c826110a..a754c4c5e3 100644 --- a/master/eigensolver_2band__to__tridiag_2mc_8h_source.html +++ b/master/eigensolver_2band__to__tridiag_2mc_8h_source.html @@ -895,7 +895,7 @@
824  ex::when_all_vector(matrix::select(mat_v, common::iterate_range2d(LocalTileIndex{i, i},
825  LocalTileSize{n - i, 1}))) |
826  ex::then([](TileVector&& vector) { return std::make_shared<TileVector>(std::move(vector)); }) |
-
827  ex::split();
+
827  ex::drop_operation_state() | ex::split();
828  }
829 
830  ex::when_all(std::move(sem_sender), ex::just(sem_next, sweep), w_pipeline(), tiles_v) |
@@ -1410,7 +1410,7 @@
1339  if (sweep % b == 0) {
1340  tile_v = panel_v.readwrite(LocalTileIndex{id_block_local, 0}) |
1341  ex::then([](Tile&& tile) { return std::make_shared<Tile>(std::move(tile)); }) |
-
1342  ex::split();
+
1342  ex::drop_operation_state() | ex::split();
1343  }
1344 
1345  ex::unique_any_sender<SemaphorePtr> sem_sender;
diff --git a/master/transform_8h_source.html b/master/transform_8h_source.html index e32cc2c4fd..16bcc75f9b 100644 --- a/master/transform_8h_source.html +++ b/master/transform_8h_source.html @@ -121,143 +121,148 @@
51  typename F = void, typename Sender = void,
52  typename = std::enable_if_t<pika::execution::experimental::is_sender_v<Sender>>>
53 [[nodiscard]] decltype(auto) transform(const Policy<B> policy, F&& f, Sender&& sender) {
-
54  using pika::execution::experimental::then;
-
55  using pika::execution::experimental::transfer;
-
56 
-
57  auto scheduler = getBackendScheduler<B>(policy.priority(), policy.stacksize());
-
58  auto transfer_sender = transfer(std::forward<Sender>(sender), std::move(scheduler));
-
59 
-
60  using dlaf::common::internal::ConsumeRvalues;
-
61  using dlaf::common::internal::Unwrapping;
-
62 
-
63  if constexpr (B == Backend::MC) {
-
64  return then(std::move(transfer_sender), ConsumeRvalues{Unwrapping{std::forward<F>(f)}});
-
65  }
-
66  else if constexpr (B == Backend::GPU) {
-
67 #if defined(DLAF_WITH_GPU)
-
68  using pika::cuda::experimental::then_with_cublas;
-
69  using pika::cuda::experimental::then_with_cusolver;
-
70  using pika::cuda::experimental::then_with_stream;
-
71 
-
72  if constexpr (Tag == TransformDispatchType::Plain) {
-
73  return then_with_stream(std::move(transfer_sender),
-
74  ConsumeRvalues{Unwrapping{std::forward<F>(f)}});
-
75  }
-
76  else if constexpr (Tag == TransformDispatchType::Blas) {
-
77  return then_with_cublas(std::move(transfer_sender), ConsumeRvalues{Unwrapping{std::forward<F>(f)}},
-
78  CUBLAS_POINTER_MODE_HOST);
-
79  }
-
80  else if constexpr (Tag == TransformDispatchType::Lapack) {
-
81  return then_with_cusolver(std::move(transfer_sender),
-
82  ConsumeRvalues{Unwrapping{std::forward<F>(f)}});
+
54  using pika::execution::experimental::drop_operation_state;
+
55  using pika::execution::experimental::then;
+
56  using pika::execution::experimental::transfer;
+
57 
+
58  auto scheduler = getBackendScheduler<B>(policy.priority(), policy.stacksize());
+
59  auto transfer_sender = transfer(std::forward<Sender>(sender), std::move(scheduler));
+
60 
+
61  using dlaf::common::internal::ConsumeRvalues;
+
62  using dlaf::common::internal::Unwrapping;
+
63 
+
64  if constexpr (B == Backend::MC) {
+
65  return then(std::move(transfer_sender), ConsumeRvalues{Unwrapping{std::forward<F>(f)}}) |
+
66  drop_operation_state();
+
67  }
+
68  else if constexpr (B == Backend::GPU) {
+
69 #if defined(DLAF_WITH_GPU)
+
70  using pika::cuda::experimental::then_with_cublas;
+
71  using pika::cuda::experimental::then_with_cusolver;
+
72  using pika::cuda::experimental::then_with_stream;
+
73 
+
74  if constexpr (Tag == TransformDispatchType::Plain) {
+
75  return then_with_stream(std::move(transfer_sender),
+
76  ConsumeRvalues{Unwrapping{std::forward<F>(f)}}) |
+
77  drop_operation_state();
+
78  }
+
79  else if constexpr (Tag == TransformDispatchType::Blas) {
+
80  return then_with_cublas(std::move(transfer_sender), ConsumeRvalues{Unwrapping{std::forward<F>(f)}},
+
81  CUBLAS_POINTER_MODE_HOST) |
+
82  drop_operation_state();
83  }
-
84  else {
-
85  DLAF_STATIC_FAIL(
-
86  Sender,
-
87  "Attempting to use transform with a GPU policy, but f is not invocable with a CUDA stream as the last argument or cuBLAS/cuSOLVER handle as the first argument.");
+
84  else if constexpr (Tag == TransformDispatchType::Lapack) {
+
85  return then_with_cusolver(std::move(transfer_sender),
+
86  ConsumeRvalues{Unwrapping{std::forward<F>(f)}}) |
+
87  drop_operation_state();
88  }
-
89 #else
-
90  DLAF_STATIC_FAIL(Sender, "Attempting to use transform with Backend::GPU but it is disabled");
-
91 #endif
-
92  }
-
93  else {
-
94  DLAF_STATIC_FAIL(Sender, "Unknown backend given to transform");
-
95  }
-
96 }
-
97 
-
99 template <TransformDispatchType Tag = TransformDispatchType::Plain, Backend B = Backend::MC,
-
100  typename F = void, typename Sender = void,
-
101  typename = std::enable_if_t<pika::execution::experimental::is_sender_v<Sender>>>
-
102 void transformDetach(const Policy<B> policy, F&& f, Sender&& sender) {
-
103  pika::execution::experimental::start_detached(transform<Tag>(policy, std::forward<F>(f),
-
104  std::forward<Sender>(sender)));
-
105 }
-
106 
-
110 template <TransformDispatchType Tag, Backend B, typename F, typename... Ts>
-
111 [[nodiscard]] decltype(auto) transformLift(const Policy<B> policy, F&& f, Ts&&... ts) {
-
112  return transform<Tag>(policy, std::forward<F>(f), internal::whenAllLift(std::forward<Ts>(ts)...));
-
113 }
-
114 
-
118 template <TransformDispatchType Tag = TransformDispatchType::Plain, Backend B = Backend::MC,
-
119  typename F = void, typename... Ts>
-
120 void transformLiftDetach(const Policy<B> policy, F&& f, Ts&&... ts) {
-
121  pika::execution::experimental::start_detached(transformLift<Tag>(policy, std::forward<F>(f),
-
122  std::forward<Ts>(ts)...));
-
123 }
-
124 
-
125 template <TransformDispatchType Tag, Backend B, typename F>
-
126 struct PartialTransformBase {
-
127  const Policy<B> policy_;
-
128  std::decay_t<F> f_;
-
129 };
-
130 
-
134 template <TransformDispatchType Tag, Backend B, typename F>
-
135 class PartialTransform : private PartialTransformBase<Tag, B, F> {
-
136 public:
-
137  template <typename F_>
-
138  PartialTransform(const Policy<B> policy, F_&& f)
-
139  : PartialTransformBase<Tag, B, F>{policy, std::forward<F_>(f)} {}
-
140  PartialTransform(PartialTransform&&) = default;
-
141  PartialTransform(const PartialTransform&) = default;
-
142  PartialTransform& operator=(PartialTransform&&) = default;
-
143  PartialTransform& operator=(const PartialTransform&) = default;
-
144 
-
145  template <typename Sender>
-
146  friend auto operator|(Sender&& sender, PartialTransform pa) {
-
147  return transform<Tag, B>(pa.policy_, std::move(pa.f_), std::forward<Sender>(sender));
-
148  }
-
149 };
-
150 
-
151 template <TransformDispatchType Tag, Backend B, typename F>
-
152 auto makePartialTransform(const Policy<B> policy, F&& f) {
-
153  return PartialTransform<Tag, B, std::decay_t<F>>{policy, std::forward<F>(f)};
-
154 }
+
89  else {
+
90  DLAF_STATIC_FAIL(
+
91  Sender,
+
92  "Attempting to use transform with a GPU policy, but f is not invocable with a CUDA stream as the last argument or cuBLAS/cuSOLVER handle as the first argument.");
+
93  }
+
94 #else
+
95  DLAF_STATIC_FAIL(Sender, "Attempting to use transform with Backend::GPU but it is disabled");
+
96 #endif
+
97  }
+
98  else {
+
99  DLAF_STATIC_FAIL(Sender, "Unknown backend given to transform");
+
100  }
+
101 }
+
102 
+
104 template <TransformDispatchType Tag = TransformDispatchType::Plain, Backend B = Backend::MC,
+
105  typename F = void, typename Sender = void,
+
106  typename = std::enable_if_t<pika::execution::experimental::is_sender_v<Sender>>>
+
107 void transformDetach(const Policy<B> policy, F&& f, Sender&& sender) {
+
108  pika::execution::experimental::start_detached(transform<Tag>(policy, std::forward<F>(f),
+
109  std::forward<Sender>(sender)));
+
110 }
+
111 
+
115 template <TransformDispatchType Tag, Backend B, typename F, typename... Ts>
+
116 [[nodiscard]] decltype(auto) transformLift(const Policy<B> policy, F&& f, Ts&&... ts) {
+
117  return transform<Tag>(policy, std::forward<F>(f), internal::whenAllLift(std::forward<Ts>(ts)...));
+
118 }
+
119 
+
123 template <TransformDispatchType Tag = TransformDispatchType::Plain, Backend B = Backend::MC,
+
124  typename F = void, typename... Ts>
+
125 void transformLiftDetach(const Policy<B> policy, F&& f, Ts&&... ts) {
+
126  pika::execution::experimental::start_detached(transformLift<Tag>(policy, std::forward<F>(f),
+
127  std::forward<Ts>(ts)...));
+
128 }
+
129 
+
130 template <TransformDispatchType Tag, Backend B, typename F>
+
131 struct PartialTransformBase {
+
132  const Policy<B> policy_;
+
133  std::decay_t<F> f_;
+
134 };
+
135 
+
139 template <TransformDispatchType Tag, Backend B, typename F>
+
140 class PartialTransform : private PartialTransformBase<Tag, B, F> {
+
141 public:
+
142  template <typename F_>
+
143  PartialTransform(const Policy<B> policy, F_&& f)
+
144  : PartialTransformBase<Tag, B, F>{policy, std::forward<F_>(f)} {}
+
145  PartialTransform(PartialTransform&&) = default;
+
146  PartialTransform(const PartialTransform&) = default;
+
147  PartialTransform& operator=(PartialTransform&&) = default;
+
148  PartialTransform& operator=(const PartialTransform&) = default;
+
149 
+
150  template <typename Sender>
+
151  friend auto operator|(Sender&& sender, PartialTransform pa) {
+
152  return transform<Tag, B>(pa.policy_, std::move(pa.f_), std::forward<Sender>(sender));
+
153  }
+
154 };
155 
-
159 template <TransformDispatchType Tag, Backend B, typename F>
-
160 class PartialTransformDetach : private PartialTransformBase<Tag, B, F> {
-
161 public:
-
162  template <typename F_>
-
163  PartialTransformDetach(const Policy<B> policy, F_&& f)
-
164  : PartialTransformBase<Tag, B, F>{policy, std::forward<F_>(f)} {}
-
165  PartialTransformDetach(PartialTransformDetach&&) = default;
-
166  PartialTransformDetach(const PartialTransformDetach&) = default;
-
167  PartialTransformDetach& operator=(PartialTransformDetach&&) = default;
-
168  PartialTransformDetach& operator=(const PartialTransformDetach&) = default;
-
169 
-
170  template <typename Sender>
-
171  friend auto operator|(Sender&& sender, PartialTransformDetach pa) {
-
172  return pika::execution::experimental::start_detached(
-
173  transform<Tag, B>(pa.policy_, std::move(pa.f_), std::forward<Sender>(sender)));
-
174  }
-
175 };
-
176 
-
177 template <TransformDispatchType Tag, Backend B, typename F>
-
178 auto makePartialTransformDetach(const Policy<B> policy, F&& f) {
-
179  return PartialTransformDetach<Tag, B, std::decay_t<F>>{policy, std::forward<F>(f)};
-
180 }
+
156 template <TransformDispatchType Tag, Backend B, typename F>
+
157 auto makePartialTransform(const Policy<B> policy, F&& f) {
+
158  return PartialTransform<Tag, B, std::decay_t<F>>{policy, std::forward<F>(f)};
+
159 }
+
160 
+
164 template <TransformDispatchType Tag, Backend B, typename F>
+
165 class PartialTransformDetach : private PartialTransformBase<Tag, B, F> {
+
166 public:
+
167  template <typename F_>
+
168  PartialTransformDetach(const Policy<B> policy, F_&& f)
+
169  : PartialTransformBase<Tag, B, F>{policy, std::forward<F_>(f)} {}
+
170  PartialTransformDetach(PartialTransformDetach&&) = default;
+
171  PartialTransformDetach(const PartialTransformDetach&) = default;
+
172  PartialTransformDetach& operator=(PartialTransformDetach&&) = default;
+
173  PartialTransformDetach& operator=(const PartialTransformDetach&) = default;
+
174 
+
175  template <typename Sender>
+
176  friend auto operator|(Sender&& sender, PartialTransformDetach pa) {
+
177  return pika::execution::experimental::start_detached(
+
178  transform<Tag, B>(pa.policy_, std::move(pa.f_), std::forward<Sender>(sender)));
+
179  }
+
180 };
181 
-
186 template <TransformDispatchType Tag = TransformDispatchType::Plain, Backend B = Backend::MC,
-
187  typename F = void>
-
188 [[nodiscard]] decltype(auto) transform(const Policy<B> policy, F&& f) {
-
189  return makePartialTransform<Tag>(policy, std::forward<F>(f));
-
190 }
-
191 
-
196 template <TransformDispatchType Tag = TransformDispatchType::Plain, Backend B = Backend::MC,
-
197  typename F = void>
-
198 [[nodiscard]] decltype(auto) transformDetach(const Policy<B> policy, F&& f) {
-
199  return makePartialTransformDetach<Tag>(policy, std::forward<F>(f));
-
200 }
-
201 }
-
202 }
-
Definition: transform.h:160
-
Definition: transform.h:135
+
182 template <TransformDispatchType Tag, Backend B, typename F>
+
183 auto makePartialTransformDetach(const Policy<B> policy, F&& f) {
+
184  return PartialTransformDetach<Tag, B, std::decay_t<F>>{policy, std::forward<F>(f)};
+
185 }
+
186 
+
191 template <TransformDispatchType Tag = TransformDispatchType::Plain, Backend B = Backend::MC,
+
192  typename F = void>
+
193 [[nodiscard]] decltype(auto) transform(const Policy<B> policy, F&& f) {
+
194  return makePartialTransform<Tag>(policy, std::forward<F>(f));
+
195 }
+
196 
+
201 template <TransformDispatchType Tag = TransformDispatchType::Plain, Backend B = Backend::MC,
+
202  typename F = void>
+
203 [[nodiscard]] decltype(auto) transformDetach(const Policy<B> policy, F&& f) {
+
204  return makePartialTransformDetach<Tag>(policy, std::forward<F>(f));
+
205 }
+
206 }
+
207 }
+
Definition: transform.h:165
+
Definition: transform.h:140
Definition: policy.h:24
Definition: consume_rvalues.h:33
Definition: unwrap.h:57
-
Definition: transform.h:126
+
Definition: transform.h:131
diff --git a/master/transform__mpi_8h_source.html b/master/transform__mpi_8h_source.html index 8a5f9307d9..c11ad2beb9 100644 --- a/master/transform__mpi_8h_source.html +++ b/master/transform__mpi_8h_source.html @@ -82,153 +82,156 @@
11 
12 #include <type_traits>
13 
-
14 #include <dlaf/common/consume_rvalues.h>
-
15 #include <dlaf/common/pipeline.h>
-
16 #include <dlaf/common/unwrap.h>
-
17 #include <dlaf/communication/communicator.h>
-
18 #include <dlaf/sender/transform.h>
-
19 #include <dlaf/sender/when_all_lift.h>
-
20 
-
21 namespace dlaf::comm::internal {
+
14 #include <pika/execution.hpp>
+
15 
+
16 #include <dlaf/common/consume_rvalues.h>
+
17 #include <dlaf/common/pipeline.h>
+
18 #include <dlaf/common/unwrap.h>
+
19 #include <dlaf/communication/communicator.h>
+
20 #include <dlaf/sender/transform.h>
+
21 #include <dlaf/sender/when_all_lift.h>
22 
-
26 inline void consumeCommunicatorWrapper(common::Pipeline<Communicator>::Wrapper& comm_wrapper) {
-
27  [[maybe_unused]] auto comm_wrapper_local = std::move(comm_wrapper);
-
28 }
-
29 
-
31 template <typename T>
-
32 void consumeCommunicatorWrapper(T&) {}
-
33 
-
44 template <typename F>
-
45 struct MPICallHelper {
-
46  std::decay_t<F> f;
-
47  template <typename... Ts>
-
48  auto operator()(Ts&&... ts)
-
49  -> decltype(std::move(f)(dlaf::common::internal::unwrap(ts)..., std::declval<MPI_Request*>())) {
-
50  MPI_Request req;
-
51  auto is_request_completed = [&req] {
-
52  int flag;
-
53  MPI_Test(&req, &flag, MPI_STATUS_IGNORE);
-
54  return flag == 0;
-
55  };
-
56 
-
57  // Note:
-
58  // Callables passed to transformMPI have their arguments passed by reference, but doing so
-
59  // with PromiseGuard would keep the guard alive until the completion of the MPI operation,
-
60  // whereas we are only looking to guard the submission of the MPI operation. We therefore
-
61  // explicitly release Pipeline<Communicator>::Wrapper after submitting the MPI operation with
-
62  // consumeCommunicatorWrapper.
-
63  //
-
64  // We also use unwrap various types passed to the MPI operation, including PromiseGuards of
-
65  // any type, to allow the MPI operation not to care whether a Communicator was wrapped in a
-
66  // PromiseGuard or not.
-
67  using result_type = decltype(std::move(f)(dlaf::common::internal::unwrap(ts)..., &req));
-
68  if constexpr (std::is_void_v<result_type>) {
-
69  std::move(f)(dlaf::common::internal::unwrap(ts)..., &req);
-
70  (internal::consumeCommunicatorWrapper(ts), ...);
-
71  pika::util::yield_while(is_request_completed);
-
72  }
-
73  else {
-
74  auto r = std::move(f)(dlaf::common::internal::unwrap(ts)..., &req);
-
75  (internal::consumeCommunicatorWrapper(ts), ...);
-
76  pika::util::yield_while(is_request_completed);
-
77  return r;
-
78  }
-
79  }
-
80 };
-
81 
-
82 template <typename F>
-
83 MPICallHelper(F&&) -> MPICallHelper<std::decay_t<F>>;
-
84 
-
86 template <typename F, typename Sender,
-
87  typename = std::enable_if_t<pika::execution::experimental::is_sender_v<Sender>>>
-
88 [[nodiscard]] decltype(auto) transformMPI(F&& f, Sender&& sender) {
-
89  namespace ex = pika::execution::experimental;
-
90 
-
91  return ex::transfer(std::forward<Sender>(sender),
-
92  ex::with_priority(dlaf::internal::getMPIScheduler(),
-
93  pika::execution::thread_priority::boost)) |
-
94  ex::then(dlaf::common::internal::ConsumeRvalues{MPICallHelper{std::forward<F>(f)}});
-
95 }
-
96 
-
98 template <typename F, typename Sender,
-
99  typename = std::enable_if_t<pika::execution::experimental::is_sender_v<Sender>>>
-
100 void transformMPIDetach(F&& f, Sender&& sender) {
-
101  pika::execution::experimental::start_detached(transformMPI(std::forward<F>(f),
-
102  std::forward<Sender>(sender)));
-
103 }
-
104 
-
108 template <typename F, typename... Ts>
-
109 [[nodiscard]] decltype(auto) transformMPILift(F&& f, Ts&&... ts) {
-
110  return transformMPI(std::forward<F>(f), dlaf::internal::whenAllLift(std::forward<Ts>(ts)...));
-
111 }
-
112 
-
116 template <typename F, typename... Ts>
-
117 void transformMPILiftDetach(F&& f, Ts&&... ts) {
-
118  pika::execution::experimental::start_detached(transformLift(std::forward<F>(f),
-
119  std::forward<Ts>(ts)...));
-
120 }
-
121 
-
122 template <typename F>
-
123 struct PartialTransformMPIBase {
-
124  std::decay_t<F> f_;
-
125 };
-
126 
-
130 template <typename F>
-
131 class PartialTransformMPI : private PartialTransformMPIBase<F> {
-
132 public:
-
133  template <typename F_>
-
134  PartialTransformMPI(F_&& f) : PartialTransformMPIBase<F>{std::forward<F_>(f)} {}
-
135  PartialTransformMPI(PartialTransformMPI&&) = default;
-
136  PartialTransformMPI(const PartialTransformMPI&) = default;
-
137  PartialTransformMPI& operator=(PartialTransformMPI&&) = default;
-
138  PartialTransformMPI& operator=(const PartialTransformMPI&) = default;
-
139 
-
140  template <typename Sender>
-
141  friend auto operator|(Sender&& sender, PartialTransformMPI pa) {
-
142  return transformMPI(std::move(pa.f_), std::forward<Sender>(sender));
-
143  }
-
144 };
-
145 
-
146 template <typename F>
-
147 PartialTransformMPI(F&& f) -> PartialTransformMPI<std::decay_t<F>>;
+
23 namespace dlaf::comm::internal {
+
24 
+
28 inline void consumeCommunicatorWrapper(common::Pipeline<Communicator>::Wrapper& comm_wrapper) {
+
29  [[maybe_unused]] auto comm_wrapper_local = std::move(comm_wrapper);
+
30 }
+
31 
+
33 template <typename T>
+
34 void consumeCommunicatorWrapper(T&) {}
+
35 
+
46 template <typename F>
+
47 struct MPICallHelper {
+
48  std::decay_t<F> f;
+
49  template <typename... Ts>
+
50  auto operator()(Ts&&... ts)
+
51  -> decltype(std::move(f)(dlaf::common::internal::unwrap(ts)..., std::declval<MPI_Request*>())) {
+
52  MPI_Request req;
+
53  auto is_request_completed = [&req] {
+
54  int flag;
+
55  MPI_Test(&req, &flag, MPI_STATUS_IGNORE);
+
56  return flag == 0;
+
57  };
+
58 
+
59  // Note:
+
60  // Callables passed to transformMPI have their arguments passed by reference, but doing so
+
61  // with PromiseGuard would keep the guard alive until the completion of the MPI operation,
+
62  // whereas we are only looking to guard the submission of the MPI operation. We therefore
+
63  // explicitly release Pipeline<Communicator>::Wrapper after submitting the MPI operation with
+
64  // consumeCommunicatorWrapper.
+
65  //
+
66  // We also use unwrap various types passed to the MPI operation, including PromiseGuards of
+
67  // any type, to allow the MPI operation not to care whether a Communicator was wrapped in a
+
68  // PromiseGuard or not.
+
69  using result_type = decltype(std::move(f)(dlaf::common::internal::unwrap(ts)..., &req));
+
70  if constexpr (std::is_void_v<result_type>) {
+
71  std::move(f)(dlaf::common::internal::unwrap(ts)..., &req);
+
72  (internal::consumeCommunicatorWrapper(ts), ...);
+
73  pika::util::yield_while(is_request_completed);
+
74  }
+
75  else {
+
76  auto r = std::move(f)(dlaf::common::internal::unwrap(ts)..., &req);
+
77  (internal::consumeCommunicatorWrapper(ts), ...);
+
78  pika::util::yield_while(is_request_completed);
+
79  return r;
+
80  }
+
81  }
+
82 };
+
83 
+
84 template <typename F>
+
85 MPICallHelper(F&&) -> MPICallHelper<std::decay_t<F>>;
+
86 
+
88 template <typename F, typename Sender,
+
89  typename = std::enable_if_t<pika::execution::experimental::is_sender_v<Sender>>>
+
90 [[nodiscard]] decltype(auto) transformMPI(F&& f, Sender&& sender) {
+
91  namespace ex = pika::execution::experimental;
+
92 
+
93  return ex::transfer(std::forward<Sender>(sender),
+
94  ex::with_priority(dlaf::internal::getMPIScheduler(),
+
95  pika::execution::thread_priority::boost)) |
+
96  ex::then(dlaf::common::internal::ConsumeRvalues{MPICallHelper{std::forward<F>(f)}}) |
+
97  ex::drop_operation_state();
+
98 }
+
99 
+
101 template <typename F, typename Sender,
+
102  typename = std::enable_if_t<pika::execution::experimental::is_sender_v<Sender>>>
+
103 void transformMPIDetach(F&& f, Sender&& sender) {
+
104  pika::execution::experimental::start_detached(transformMPI(std::forward<F>(f),
+
105  std::forward<Sender>(sender)));
+
106 }
+
107 
+
111 template <typename F, typename... Ts>
+
112 [[nodiscard]] decltype(auto) transformMPILift(F&& f, Ts&&... ts) {
+
113  return transformMPI(std::forward<F>(f), dlaf::internal::whenAllLift(std::forward<Ts>(ts)...));
+
114 }
+
115 
+
119 template <typename F, typename... Ts>
+
120 void transformMPILiftDetach(F&& f, Ts&&... ts) {
+
121  pika::execution::experimental::start_detached(transformLift(std::forward<F>(f),
+
122  std::forward<Ts>(ts)...));
+
123 }
+
124 
+
125 template <typename F>
+
126 struct PartialTransformMPIBase {
+
127  std::decay_t<F> f_;
+
128 };
+
129 
+
133 template <typename F>
+
134 class PartialTransformMPI : private PartialTransformMPIBase<F> {
+
135 public:
+
136  template <typename F_>
+
137  PartialTransformMPI(F_&& f) : PartialTransformMPIBase<F>{std::forward<F_>(f)} {}
+
138  PartialTransformMPI(PartialTransformMPI&&) = default;
+
139  PartialTransformMPI(const PartialTransformMPI&) = default;
+
140  PartialTransformMPI& operator=(PartialTransformMPI&&) = default;
+
141  PartialTransformMPI& operator=(const PartialTransformMPI&) = default;
+
142 
+
143  template <typename Sender>
+
144  friend auto operator|(Sender&& sender, PartialTransformMPI pa) {
+
145  return transformMPI(std::move(pa.f_), std::forward<Sender>(sender));
+
146  }
+
147 };
148 
-
152 template <typename F>
-
153 class PartialTransformMPIDetach : private PartialTransformMPIBase<F> {
-
154 public:
-
155  template <typename F_>
-
156  PartialTransformMPIDetach(F_&& f) : PartialTransformMPIBase<F>{std::forward<F_>(f)} {}
-
157  PartialTransformMPIDetach(PartialTransformMPIDetach&&) = default;
-
158  PartialTransformMPIDetach(const PartialTransformMPIDetach&) = default;
-
159  PartialTransformMPIDetach& operator=(PartialTransformMPIDetach&&) = default;
-
160  PartialTransformMPIDetach& operator=(const PartialTransformMPIDetach&) = default;
-
161 
-
162  template <typename Sender>
-
163  friend auto operator|(Sender&& sender, PartialTransformMPIDetach pa) {
-
164  return pika::execution::experimental::start_detached(transformMPI(std::move(pa.f_),
-
165  std::forward<Sender>(sender)));
-
166  }
-
167 };
-
168 
-
169 template <typename F>
-
170 PartialTransformMPIDetach(F&& f) -> PartialTransformMPIDetach<std::decay_t<F>>;
+
149 template <typename F>
+
150 PartialTransformMPI(F&& f) -> PartialTransformMPI<std::decay_t<F>>;
+
151 
+
155 template <typename F>
+
156 class PartialTransformMPIDetach : private PartialTransformMPIBase<F> {
+
157 public:
+
158  template <typename F_>
+
159  PartialTransformMPIDetach(F_&& f) : PartialTransformMPIBase<F>{std::forward<F_>(f)} {}
+
160  PartialTransformMPIDetach(PartialTransformMPIDetach&&) = default;
+
161  PartialTransformMPIDetach(const PartialTransformMPIDetach&) = default;
+
162  PartialTransformMPIDetach& operator=(PartialTransformMPIDetach&&) = default;
+
163  PartialTransformMPIDetach& operator=(const PartialTransformMPIDetach&) = default;
+
164 
+
165  template <typename Sender>
+
166  friend auto operator|(Sender&& sender, PartialTransformMPIDetach pa) {
+
167  return pika::execution::experimental::start_detached(transformMPI(std::move(pa.f_),
+
168  std::forward<Sender>(sender)));
+
169  }
+
170 };
171 
-
176 template <typename F>
-
177 [[nodiscard]] decltype(auto) transformMPI(F&& f) {
-
178  return PartialTransformMPI{std::forward<F>(f)};
-
179 }
-
180 
-
185 template <typename F>
-
186 [[nodiscard]] decltype(auto) transformMPIDetach(F&& f) {
-
187  return PartialTransformMPIDetach{std::forward<F>(f)};
-
188 }
-
189 }
-
Definition: transform_mpi.h:153
-
Definition: transform_mpi.h:131
+
172 template <typename F>
+
173 PartialTransformMPIDetach(F&& f) -> PartialTransformMPIDetach<std::decay_t<F>>;
+
174 
+
179 template <typename F>
+
180 [[nodiscard]] decltype(auto) transformMPI(F&& f) {
+
181  return PartialTransformMPI{std::forward<F>(f)};
+
182 }
+
183 
+
188 template <typename F>
+
189 [[nodiscard]] decltype(auto) transformMPIDetach(F&& f) {
+
190  return PartialTransformMPIDetach{std::forward<F>(f)};
+
191 }
+
192 }
+
Definition: transform_mpi.h:156
+
Definition: transform_mpi.h:134
-
Definition: transform_mpi.h:45
-
Definition: transform_mpi.h:123
+
Definition: transform_mpi.h:47
+
Definition: transform_mpi.h:126
Definition: consume_rvalues.h:33