kokkos-execution 0.0.1
Loading...
Searching...
No Matches
test_then.cpp
Go to the documentation of this file.
3
5
17
29
31
32using namespace Kokkos::utils::callbacks;
33
49
51consteval bool test_sndr_traits() {
53 using schd_sndr_t = typename ThenTest::schedule_sender_t;
54
57 using then_sndr_t = stdexec::transform_sender_result_t<
58 decltype(stdexec::then(std::declval<schd_sndr_t>(), std::declval<functor_t>())),
59 stdexec::env<>
60 >;
61
64 static_assert(std::same_as<Kokkos::Execution::Impl::exec_of_t<then_sndr_t>, TEST_EXECUTION_SPACE>);
65
68
69 return true;
70}
71
72static_assert(test_sndr_traits());
73
76 typename ThenTest::scheduler_t,
77 stdexec::then_t,
79>());
80
85TEST_F(ThenTest, then_schedule) {
86 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
87
88 const context_t esc{exec};
89
90 auto chain = stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data) | THEN_INCREMENT(data);
91
92 using chain_t = decltype(chain);
93
95 static_assert(std::same_as<stdexec::__domain_of_t<stdexec::env_of_t<chain_t>>, stdexec::default_domain>);
96 static_assert(std::same_as<
97 stdexec::__detail::__completing_domain_t<stdexec::set_value_t, chain_t>,
99 >);
100
102 static_assert(std::same_as<
103 decltype(stdexec::get_completion_scheduler<stdexec::set_value_t>(stdexec::get_env(chain))),
105 >);
106
107 ASSERT_THAT(
109 testing::ElementsAre(
113
114 ASSERT_EQ(data(), 2);
115}
116
121TEST_F(ThenTest, then_starts_on) {
122 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
123
124 const context_t esc{exec};
125
127 auto chain = stdexec::just() | THEN_INCREMENT(data) | THEN_INCREMENT(data);
128
132 using chain_t = decltype(chain);
133
134 static_assert(
135 stdexec::get_completion_signatures<chain_t>()
136 == stdexec::completion_signatures<stdexec::set_value_t(), stdexec::set_error_t(std::exception_ptr)>{});
138 static_assert(
139 std::same_as<stdexec::__completion_domain_of_t<stdexec::set_value_t, chain_t>, stdexec::indeterminate_domain<>>);
140
142 auto starts_on = stdexec::starts_on(esc.get_scheduler(), std::move(chain));
143
144 using starts_on_t = decltype(starts_on);
145
147 static_assert(stdexec::__has_eptr_completion<chain_t>);
148 static_assert(!stdexec::dependent_sender<starts_on_t>);
149 static_assert(
150 stdexec::get_completion_signatures<starts_on_t>()
151 == stdexec::completion_signatures<stdexec::set_value_t(), stdexec::set_error_t(std::exception_ptr)>{});
152
154 static_assert(stdexec::__completes_where_it_starts<stdexec::set_value_t, stdexec::env_of_t<chain_t>>);
156 static_assert(std::same_as<
159 >);
160 static_assert(std::same_as<
161 stdexec::__completion_domain_of_t<stdexec::set_value_t, starts_on_t, stdexec::env<>>,
163 >);
164
165 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
166
167 const auto recorded_events = Tests::Utils::record_sync_wait<recorder_listener_t>(std::move(starts_on));
168
169 ASSERT_THAT(recorded_events, [&]() {
171 return testing::ElementsAre(
175 MATCHER_FOR_WAIT_EVENT(recorded_events.at(2)));
176 } else {
177 return testing::ElementsAre(
180 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch")));
181 }
182 }());
183
184 ASSERT_EQ(data(), 2);
185}
186
194TEST_F(ThenTest, error_propagates) {
195 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
196
197 const context_t esc{exec};
198
199 stdexec::sender auto sndr = stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data)
201 | stdexec::then(KOKKOS_LAMBDA() {
202 Kokkos::abort("The value channel should be used at this point.");
203 });
204
205 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
206
207 ASSERT_THAT(
208 recorder_listener_t::record([sndr = std::move(sndr)]() mutable {
209 ASSERT_THAT(
210 Tests::Utils::Functors::MutableMoveToSyncWait{.sndr = std::move(sndr)},
211 testing::ThrowsMessage<std::runtime_error>(
212 testing::HasSubstr("ThrowsWhenCopied: Throwing in copy constructor!")));
213 }),
214 testing::ElementsAre(
215 MATCHER_FOR_BEGIN_SINGLE(exec, dispatch_label(exec, "then")), // Increment: succeeds
216 MATCHER_FOR_BEGIN_SINGLE(exec, dispatch_label(exec, "then")), // ThrowsWhenCopied: throws on copy
218
219 ASSERT_EQ(data(), 1);
220}
221
227TEST_F(ThenTest, then_lifetime) {
229 const context_t esc{exec};
230
232 auto create_chain_in_scope = [&]() {
233 const view_s_t data(Kokkos::view_alloc("data - shared space", exec));
234
235 return stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data) | THEN_INCREMENT(data);
236 };
237
239 const auto run_test = [&]() {
240 auto chain = create_chain_in_scope();
241
242 using chain_t = decltype(chain);
243
245 static_assert(std::same_as<stdexec::__domain_of_t<stdexec::env_of_t<chain_t>>, stdexec::default_domain>);
246 static_assert(std::same_as<
247 stdexec::__detail::__completing_domain_t<stdexec::set_value_t, chain_t>,
249 >);
250
252 static_assert(std::same_as<
253 decltype(stdexec::get_completion_scheduler<stdexec::set_value_t>(stdexec::get_env(chain))),
255 >);
256
257 stdexec::sync_wait(std::move(chain));
258 };
259
260 ASSERT_THAT(
261 recorder_listener_t::record(run_test),
264 testing::Field(
266 testing::Field(
267 &Kokkos::utils::callbacks::AllocDescriptor::name, testing::StrEq("data - shared space")))),
272 testing::Field(
274 testing::Field(
275 &Kokkos::utils::callbacks::AllocDescriptor::name, testing::StrEq("data - shared space"))))));
276}
277
279consteval bool test_sndr_nothrow_transformable() {
280 using sndr_then_t =
281 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(Tests::Utils::Functors::NoOp<false, false, false>{}));
282
283 static_assert(std::same_as<
284 sndr_then_t,
285 stdexec::then_t::__sender<
288 >
289 >);
290
291 static_assert(stdexec::__detail::__has_nothrow_transform_sender<
293 stdexec::set_value_t,
294 sndr_then_t&&,
295 stdexec::env<>
296 >);
297
298 using sndr_then_maythrow_on_move_t =
299 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(Tests::Utils::Functors::NoOp<false, false, true>{}));
300
301 static_assert(!stdexec::__detail::__has_nothrow_transform_sender<
303 stdexec::set_value_t,
304 sndr_then_maythrow_on_move_t&&,
305 stdexec::env<>
306 >);
307
308 using sndr_then_maythrow_on_copy_t =
309 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(Tests::Utils::Functors::NoOp<false, true, false>{}));
310
311 static_assert(!stdexec::__detail::__has_nothrow_transform_sender<
312 Kokkos::Execution::ExecutionSpaceImpl::Domain,
313 stdexec::set_value_t,
314 const sndr_then_maythrow_on_copy_t&,
315 stdexec::env<>
316 >);
317
318 static_assert(
319 !noexcept(stdexec::transform_sender(std::declval<const sndr_then_maythrow_on_copy_t&>(), stdexec::env<>{})));
320
321 return true;
322}
323
324static_assert(test_sndr_nothrow_transformable());
325
327TEST_F(ThenTest, forwarding_env) {
328 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
329
330 std::atomic<size_t> count = 0;
331
332 int value;
333
334 const context_t esc{exec};
335
336 stdexec::sender auto sndr =
337 stdexec::read_env(stdexec::get_allocator)
338 | stdexec::then([&value](auto allocator) { value = Tests::Utils::round_trip_allocate(allocator, 42); })
339 | stdexec::continues_on(esc.get_scheduler())
341 | stdexec::write_env(stdexec::prop{stdexec::get_allocator, Tests::Utils::TrackingAllocator<int>{&count}});
342
343 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
344
345 const auto recorded_events = Tests::Utils::record_sync_wait<recorder_listener_t>(std::move(sndr));
346
347 ASSERT_THAT(recorded_events, [&]() {
349 return testing::ElementsAre(
352 MATCHER_FOR_WAIT_EVENT(recorded_events.at(1)));
353 } else {
354 return testing::ElementsAre(
356 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch")));
357 }
358 }());
359
360 ASSERT_EQ(data(), 1);
361
362 ASSERT_EQ(value, 42);
363 ASSERT_EQ(count, 1);
364}
365
367TEST_F(ThenTest, set_stopped_will_not_dispatch_operation) {
368 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
369
370 const context_t esc{exec};
371
372 stdexec::sender auto sndr = stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data)
373 | stdexec::continues_on(Tests::Utils::Schedulers::Stopped{})
374 | stdexec::continues_on(esc.get_scheduler()) | THEN_INCREMENT(data);
375
376 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
377
378 const auto recorded_events = Tests::Utils::record_sync_wait<recorder_listener_t>(std::move(sndr));
379
380 ASSERT_THAT(
381 recorded_events,
382 testing::ElementsAre(
384 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "schedule_from"))));
385
386 ASSERT_EQ(data(), 1);
387}
388
389} // namespace Tests::ExecutionSpaceImpl
constexpr std::string dispatch_label(const Exec &, const std::string_view label)
Get the dispatch label from Exec and label.
#define MATCHER_FOR_BEGIN_SINGLE(_exec_, _label_)
#define MATCHER_FOR_WAIT_EVENT(_record_event_variant_)
#define MATCHER_FOR_RECORD_EVENT(_exec_)
#define MATCHER_FOR_BEGIN_FENCE(_exec_, _label_)
RecorderListener< EventDiscardMatcher< TEST_EXECUTION_SPACE >, BeginFenceEvent, BeginSingleEvent, AllocateDataEvent, DeallocateDataEvent, Kokkos::Execution::Impl::RecordEvent, Kokkos::Execution::Impl::WaitEvent > recorder_listener_t
Definition test_then.cpp:38
typename recorder_listener_t::event_variant_t variant_t
Definition test_then.cpp:47
Concept for a sender whose completion scheduler is Kokkos::Execution::ExecutionSpaceImpl::Scheduler.
Concept that constrains the type of a sender that dispatches a functor for execution.
#define THEN_INCREMENT(_data_)
Add a then using Tests::Utils::Functors::Increment that may throw. // NOLINTNEXTLINE(cppcoreguideline...
Definition increment.hpp:64
std::invoke_result_t< stdexec::get_completion_scheduler_t< Tag >, stdexec::env_of_t< Sndr >, Env... > completion_scheduler_of_t
Retrieve the completion scheduler for a given completion tag.
auto AAllocateDataEvent(Matchers &&... matchers)
auto ADeallocateDataEvent(Matchers &&... matchers)
auto ContainsInOrder(Matchers &&... matchers)
consteval bool test_sndr_traits()
Definition test_bulk.cpp:49
consteval bool test_sndr_nothrow_transformable()
Definition test_bulk.cpp:87
auto record_sync_wait(Sndr &&sndr)
Definition sync_wait.hpp:14
consteval bool check_continues_on_after_just_stopped()
constexpr check_rcvr_env_queryable_with_t< true, Queries... > check_rcvr_env_queryable_with
auto round_trip_allocate(Allocator &allocator, T &&value)
Matcher to filter out events that are just noise for tests.
auto get_scheduler() const noexcept -> ExecutionSpaceImpl::Scheduler< execution_space >
Event to be sent to Kokkos::utils::callbacks::dispatch when calling record.
Definition event.hpp:59
Event to be sent to Kokkos::utils::callbacks::dispatch when calling wait.
Definition event.hpp:80
decltype(std::declval< const context_t >().get_scheduler()) scheduler_t
Definition context.hpp:34
decltype(stdexec::schedule(std::declval< scheduler_t >())) schedule_sender_t
Definition context.hpp:35
Kokkos::Execution::ExecutionSpaceContext< Exec > context_t
Definition context.hpp:33
This helper struct throws when copy constructed.
Scheduler that returns a sender that always completes on the stop channel.
Definition stopped.hpp:22
A minimal tracking allocator.