kokkos-execution 0.0.1
Loading...
Searching...
No Matches
test_when_all.cpp
Go to the documentation of this file.
2PRAGMA_DIAGNOSTIC_PUSH
4#include "exec/single_thread_context.hpp"
5PRAGMA_DIAGNOSTIC_POP
6
9
11
21
33
34using host_execution_space = Kokkos::DefaultHostExecutionSpace;
35
37
38using namespace Kokkos::utils::callbacks;
39
52
60TEST_F(WhenAllTest, single_branch) {
61 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
62
63 const context_t esc{exec};
64
65 auto sndr = stdexec::when_all(stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data));
66
67 static_assert(std::same_as<
68 decltype(stdexec::get_completion_domain<stdexec::set_value_t>(stdexec::get_env(sndr))),
70 >);
71
75
76 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
77
78 const auto recorded_events = recorder_listener_t::record(
79 [sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); });
80
82 ASSERT_EQ(recorded_events.size(), 3);
83 ASSERT_THAT(recorded_events.at(0), MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")));
84 ASSERT_THAT(recorded_events.at(1), MATCHER_FOR_RECORD_EVENT(exec));
85 ASSERT_THAT(recorded_events.at(2), MATCHER_FOR_WAIT_EVENT(recorded_events.at(1)));
86 } else {
89 ASSERT_THAT(
90 recorded_events,
91 testing::ElementsAre(
93 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch"))));
94 }
95
96 ASSERT_EQ(data(), 1);
97}
98
107TEST_F(WhenAllTest, single_branch_followed_by_self) {
108 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
109
110 const context_t esc{exec};
111
112 auto sndr = stdexec::when_all(stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data))
113 | stdexec::continues_on(esc.get_scheduler()) | THEN_INCREMENT(data);
114
115 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
116
117 ASSERT_THAT(
118 recorder_listener_t::record([sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); }),
119 testing::ElementsAre(
123
124 ASSERT_EQ(data(), 2);
125}
126
136TEST_F(WhenAllTest, single_mixed_branch_followed_by_self) {
137 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
138
139 const context_t esc{exec};
140 experimental::execution::single_thread_context stc{};
141
142 auto sndr = stdexec::when_all(
143 stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data)
144 | stdexec::continues_on(stc.get_scheduler()) | THEN_INCREMENT(data))
145 | stdexec::continues_on(esc.get_scheduler()) | THEN_INCREMENT(data);
146
147 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
148
149 ASSERT_THAT(
150 recorder_listener_t::record([sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); }),
151 testing::ElementsAre(
156
157 ASSERT_EQ(data(), 3);
158}
159
168TEST_F(WhenAllTest, single_branch_followed_by_other_and_finish_on_self) {
169 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
170
171 const context_t esc{exec};
172 experimental::execution::single_thread_context stc{};
173
174 auto sndr = stdexec::when_all(stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data))
175 | stdexec::continues_on(stc.get_scheduler()) | THEN_INCREMENT(data)
176 | stdexec::continues_on(esc.get_scheduler()) | THEN_INCREMENT(data);
177
178 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
179
180 const auto recorded_events = recorder_listener_t::record(
181 [sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); });
182
184 ASSERT_EQ(recorded_events.size(), 5);
185 ASSERT_THAT(recorded_events.at(0), MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")));
186 ASSERT_THAT(recorded_events.at(1), MATCHER_FOR_RECORD_EVENT(exec));
187 ASSERT_THAT(recorded_events.at(2), MATCHER_FOR_WAIT_EVENT(recorded_events.at(1)));
188 ASSERT_THAT(recorded_events.at(3), MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")));
189 ASSERT_THAT(recorded_events.at(4), MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "sync_wait")));
190 } else {
191 ASSERT_THAT(
192 recorded_events,
193 testing::ElementsAre(
195 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch")),
198 }
199
200 ASSERT_EQ(data(), 3);
201}
202
213TEST_F(WhenAllTest, two_mixed_branches_followed_by_self) {
214 const view_s_t data(Kokkos::view_alloc("data - shared space"));
215
216 const context_t esc{exec};
217 experimental::execution::single_thread_context stc{};
218
219 auto w_a = stdexec::when_all(
220 stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT_ATOMIC(data),
221 stdexec::schedule(stc.get_scheduler()) | THEN_INCREMENT_ATOMIC(data));
222
223 static_assert(
224 std::same_as<
225 decltype(stdexec::get_completion_domain<stdexec::set_value_t>(stdexec::get_env(w_a), stdexec::env<>{})),
226 stdexec::default_domain
227 >);
228
229 auto sndr = std::move(w_a) | stdexec::continues_on(esc.get_scheduler()) | THEN_INCREMENT(data);
230
231 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
232
233 ASSERT_THAT(
234 recorder_listener_t::record([sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); }),
235 testing::ElementsAre(
239
240 ASSERT_EQ(data(), 3);
241}
242
253TEST_F(WhenAllTest, two_branches_followed_by_self) {
254 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
255
256 const auto [exec_A, exec_B] = Kokkos::Experimental::partition_space(exec, 1, 1);
257
258 const context_t esc_A{exec_A}, esc_B{exec_B};
259
260 auto sndr = stdexec::when_all(
261 stdexec::schedule(esc_A.get_scheduler()) | THEN_INCREMENT_ATOMIC(data),
262 stdexec::schedule(esc_B.get_scheduler()) | THEN_INCREMENT_ATOMIC(data))
263 | stdexec::continues_on(esc_A.get_scheduler()) | THEN_INCREMENT(data);
264
265 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
266
267 const auto recorded_events = recorder_listener_t::record(
268 [sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); });
269
270 if (Tests::Utils::are_same_instances(exec_A, exec_B)) {
271 ASSERT_THAT(
272 recorded_events,
273 testing::ElementsAre(
274 MATCHER_FOR_BEGIN_PFOR(exec_A, dispatch_label(exec_A, "then")),
275 MATCHER_FOR_BEGIN_PFOR(exec_B, dispatch_label(exec_B, "then")),
276 MATCHER_FOR_BEGIN_PFOR(exec_A, dispatch_label(exec_A, "then")),
277 MATCHER_FOR_BEGIN_FENCE(exec_A, dispatch_label(exec_A, "sync_wait"))));
279 ASSERT_EQ(recorded_events.size(), 6);
280 ASSERT_THAT(recorded_events.at(0), MATCHER_FOR_BEGIN_PFOR(exec_A, dispatch_label(exec, "then")));
281 ASSERT_THAT(recorded_events.at(1), MATCHER_FOR_BEGIN_PFOR(exec_B, dispatch_label(exec, "then")));
282 ASSERT_THAT(recorded_events.at(2), MATCHER_FOR_RECORD_EVENT(exec_B));
283 ASSERT_THAT(recorded_events.at(3), MATCHER_FOR_WAIT_EVENT(recorded_events.at(2)));
284 ASSERT_THAT(recorded_events.at(4), MATCHER_FOR_BEGIN_PFOR(exec_A, dispatch_label(exec, "then")));
285 ASSERT_THAT(recorded_events.at(5), MATCHER_FOR_BEGIN_FENCE(exec_A, dispatch_label(exec, "sync_wait")));
286 } else {
287 ASSERT_THAT(
288 recorded_events,
289 testing::ElementsAre(
290 MATCHER_FOR_BEGIN_PFOR(exec_A, dispatch_label(exec_A, "then")),
291 MATCHER_FOR_BEGIN_PFOR(exec_B, dispatch_label(exec_B, "then")),
292 MATCHER_FOR_BEGIN_FENCE(exec_B, dispatch_label(exec_B, "after dispatch")),
293 MATCHER_FOR_BEGIN_PFOR(exec_A, dispatch_label(exec_A, "then")),
294 MATCHER_FOR_BEGIN_FENCE(exec_A, dispatch_label(exec_A, "sync_wait"))));
295 }
296
297 ASSERT_EQ(data(), 3);
298}
299
311TEST_F(WhenAllTest, two_branches_host_device_followed_by_device) {
313
314 const view_s_t data(Kokkos::view_alloc("data - shared space"));
315
316 const context_t esc{exec};
317
318 const host_execution_space exec_h{};
319 const context_h_t esc_h{exec_h};
320
321 auto sndr = stdexec::when_all(
322 stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT_ATOMIC(data),
323 stdexec::schedule(esc_h.get_scheduler()) | THEN_INCREMENT_ATOMIC(data))
324 | stdexec::continues_on(esc.get_scheduler()) | THEN_INCREMENT(data);
325
326 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
327
328 const auto recorded_events = recorder_listener_t::record(
329 [sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); });
330
332 ASSERT_THAT(
333 recorded_events,
334 testing::ElementsAre(
336 MATCHER_FOR_BEGIN_PFOR(exec_h, dispatch_label(exec_h, "then")),
340 ASSERT_EQ(recorded_events.size(), 6);
341 ASSERT_THAT(recorded_events.at(0), MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")));
342 ASSERT_THAT(recorded_events.at(1), MATCHER_FOR_BEGIN_PFOR(exec_h, dispatch_label(exec_h, "then")));
343 ASSERT_THAT(recorded_events.at(2), MATCHER_FOR_RECORD_EVENT(exec_h));
344 ASSERT_THAT(recorded_events.at(3), MATCHER_FOR_WAIT_EVENT(recorded_events.at(2)));
345 ASSERT_THAT(recorded_events.at(4), MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")));
346 ASSERT_THAT(recorded_events.at(5), MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "sync_wait")));
347 } else {
348 ASSERT_THAT(
349 recorded_events,
350 testing::ElementsAre(
352 MATCHER_FOR_BEGIN_PFOR(exec_h, dispatch_label(exec_h, "then")),
353 MATCHER_FOR_BEGIN_FENCE(exec_h, dispatch_label(exec_h, "after dispatch")),
356 }
357
358 ASSERT_EQ(data(), 3);
359}
360
372TEST_F(WhenAllTest, two_mixed_branches_followed_by_other_and_finish_on_self) {
373 const view_s_t data(Kokkos::view_alloc("data - shared space"));
374
375 const context_t esc{exec};
376 experimental::execution::single_thread_context stc{};
377
378 auto sndr = stdexec::when_all(
379 stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT_ATOMIC(data),
380 stdexec::schedule(stc.get_scheduler()) | THEN_INCREMENT_ATOMIC(data))
381 | stdexec::continues_on(stc.get_scheduler()) | THEN_INCREMENT(data)
382 | stdexec::continues_on(esc.get_scheduler()) | THEN_INCREMENT(data);
383
384 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
385
386 const auto recorded_events = recorder_listener_t::record(
387 [sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); });
388
390 ASSERT_EQ(recorded_events.size(), 5);
391 ASSERT_THAT(recorded_events.at(0), MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")));
392 ASSERT_THAT(recorded_events.at(1), MATCHER_FOR_RECORD_EVENT(exec));
393 ASSERT_THAT(recorded_events.at(2), MATCHER_FOR_WAIT_EVENT(recorded_events.at(1)));
394 ASSERT_THAT(recorded_events.at(3), MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")));
395 ASSERT_THAT(recorded_events.at(4), MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "sync_wait")));
396 } else {
397 ASSERT_THAT(
398 recorded_events,
399 testing::ElementsAre(
401 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch")),
404 }
405
406 ASSERT_EQ(data(), 4);
407}
408
423TEST_F(WhenAllTest, nested_with_inner_followed_by_other) {
424 const view_s_t data(Kokkos::view_alloc("data - shared space"));
425
426 const context_t esc{exec};
427 experimental::execution::single_thread_context stc{};
428
429 auto sndr =
430 stdexec::when_all(
431 stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT_ATOMIC(data),
432 stdexec::when_all(stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT_ATOMIC(data))
434 | stdexec::continues_on(stc.get_scheduler()) | THEN_INCREMENT_ATOMIC(data))
435 | stdexec::continues_on(esc.get_scheduler()) | THEN_INCREMENT(data);
436
437 ASSERT_THAT(
438 recorder_listener_t::record([sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); }),
439 testing::ElementsAre(
442 // MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch")),
445
446 ASSERT_EQ(data(), 4);
447}
448
460TEST_F(WhenAllTest, nested_when_all_with_independent_branch) {
461 const auto [exec_A, exec_B, exec_C] = Kokkos::Experimental::partition_space(exec, 1, 1, 1);
462
463 const context_t esc_A{exec_A}, esc_B{exec_B}, esc_C{exec_C};
464
465 auto br_A = ::stdexec::schedule(esc_A.get_scheduler()) | THEN_LABELED_PFOR(TEST_EXECUTION_SPACE, 'A');
466 auto br_B = ::stdexec::schedule(esc_B.get_scheduler()) | THEN_LABELED_PFOR(TEST_EXECUTION_SPACE, 'B');
467 auto br_C = ::stdexec::schedule(esc_C.get_scheduler()) | THEN_LABELED_PFOR(TEST_EXECUTION_SPACE, 'C');
468
469 auto when_AB_then_D = ::stdexec::when_all(std::move(br_A), std::move(br_B))
470 | ::stdexec::continues_on(esc_A.get_scheduler()) | THEN_LABELED_PFOR(TEST_EXECUTION_SPACE, 'D');
471
472 auto sndr = ::stdexec::when_all(std::move(when_AB_then_D), std::move(br_C));
473
474 const auto recorded_events = recorder_listener_t::record(
475 [sndr = std::move(sndr)]() mutable { stdexec::sync_wait(std::move(sndr)); });
476
477 if (Tests::Utils::are_same_instances(exec_A, exec_B)) {
478 ASSERT_THAT(
479 recorded_events,
480 testing::ElementsAre(
481 MATCHER_FOR_BEGIN_PFOR(exec_A, "'A'"),
482 MATCHER_FOR_BEGIN_PFOR(exec_B, "'B'"),
483 MATCHER_FOR_BEGIN_PFOR(exec_A, "'D'"),
484 MATCHER_FOR_BEGIN_FENCE(exec_A, dispatch_label(exec_A, "after dispatch")),
485 MATCHER_FOR_BEGIN_PFOR(exec_C, "'C'"),
486 MATCHER_FOR_BEGIN_FENCE(exec_C, dispatch_label(exec_C, "after dispatch"))));
488 ASSERT_EQ(recorded_events.size(), 10);
489 ASSERT_THAT(recorded_events.at(0), MATCHER_FOR_BEGIN_PFOR(exec_A, "'A'"));
490 ASSERT_THAT(recorded_events.at(1), MATCHER_FOR_BEGIN_PFOR(exec_B, "'B'"));
491 ASSERT_THAT(recorded_events.at(2), MATCHER_FOR_RECORD_EVENT(exec_B));
492 ASSERT_THAT(recorded_events.at(3), MATCHER_FOR_BEGIN_PFOR(exec_C, "'C'"));
493 ASSERT_THAT(recorded_events.at(4), MATCHER_FOR_RECORD_EVENT(exec_C));
494 ASSERT_THAT(recorded_events.at(5), MATCHER_FOR_WAIT_EVENT(recorded_events.at(2)));
495 ASSERT_THAT(recorded_events.at(6), MATCHER_FOR_BEGIN_PFOR(exec_A, "'D'"));
496 ASSERT_THAT(recorded_events.at(7), MATCHER_FOR_RECORD_EVENT(exec_A));
497 ASSERT_THAT(recorded_events.at(8), MATCHER_FOR_WAIT_EVENT(recorded_events.at(4)));
498 ASSERT_THAT(recorded_events.at(9), MATCHER_FOR_WAIT_EVENT(recorded_events.at(7)));
499 } else {
500 ASSERT_THAT(
501 recorded_events,
502 testing::ElementsAre(
503 MATCHER_FOR_BEGIN_PFOR(exec_A, "'A'"),
504 MATCHER_FOR_BEGIN_PFOR(exec_B, "'B'"),
505 MATCHER_FOR_BEGIN_FENCE(exec_B, dispatch_label(exec_B, "after dispatch")),
506 MATCHER_FOR_BEGIN_PFOR(exec_A, "'D'"),
507 MATCHER_FOR_BEGIN_FENCE(exec_A, dispatch_label(exec_A, "after dispatch")),
508 MATCHER_FOR_BEGIN_PFOR(exec_C, "'C'"),
509 MATCHER_FOR_BEGIN_FENCE(exec_C, dispatch_label(exec_C, "after dispatch"))));
510 }
511}
512
513} // namespace Tests::ExecutionSpaceImpl
constexpr std::string dispatch_label(const Exec &, Label &&label)
Get the dispatch label from Exec and label.
#define MATCHER_FOR_WAIT_EVENT(_record_event_variant_)
#define MATCHER_FOR_BEGIN_PFOR(_exec_, _label_)
#define MATCHER_FOR_RECORD_EVENT(_exec_)
#define MATCHER_FOR_BEGIN_FENCE(_exec_, _label_)
RecorderListener< EventDiscardMatcher< TEST_EXECUTION_SPACE >, BeginFenceEvent, BeginParallelForEvent, Kokkos::Execution::Impl::RecordEvent, Kokkos::Execution::Impl::WaitEvent > recorder_listener_t
Concept for a sender whose completion scheduler is Kokkos::Execution::ExecutionSpaceImpl::Scheduler.
#define KOKKOS_EXECUTION_STDEXEC_PRAGMA_DIAGNOSTIC_IGNORED
Basic list of ignored diagnostics when including anything from stdexec.
#define THEN_INCREMENT(_data_)
Add a then using Tests::Utils::Functors::Increment that may throw. // NOLINTNEXTLINE(cppcoreguideline...
Definition increment.hpp:35
#define THEN_INCREMENT_ATOMIC(_data_)
Same as THEN_INCREMENT, using Tests::Utils::atomic_add. // NOLINTNEXTLINE(cppcoreguidelines-macro-usa...
Definition increment.hpp:39
#define THEN_LABELED_PFOR(_exec_, _id_)
Add a Kokkos::Execution::parallel_for using Tests::Utils::Functors::Labeled. // NOLINTNEXTLINE(cppcor...
Definition labeled.hpp:21
constexpr check_rcvr_env_queryable_with_t< true, Queries... > check_rcvr_env_queryable_with
bool are_same_instances(const Exec &exec, const OtherExec &other_exec)
Definition kokkos.hpp:13
Matcher to filter out events that are just noise for tests.
Execution context using a Kokkos execution space under the hood.
auto get_scheduler() const noexcept -> ExecutionSpaceImpl::Scheduler< Exec >
Event to be sent to Kokkos::utils::callbacks::dispatch when an event is recorded on an execution spac...
Definition event.hpp:46
Event to be sent to Kokkos::utils::callbacks::dispatch when an event is being waited for.
Definition event.hpp:63
Kokkos::Execution::ExecutionSpaceContext< Exec > context_t
Definition context.hpp:25
Kokkos::DefaultHostExecutionSpace host_execution_space