kokkos-execution 0.0.1
Loading...
Searching...
No Matches
test_then.cpp
Go to the documentation of this file.
3
5
16
28
30
31using namespace Kokkos::utils::callbacks;
32
48
50consteval bool test_sndr_traits() {
52 using schd_sndr_t = typename ThenTest::schedule_sender_t;
53
56 using then_sndr_t = stdexec::transform_sender_result_t<
57 decltype(stdexec::then(std::declval<schd_sndr_t>(), std::declval<functor_t>())),
58 stdexec::env<>
59 >;
60
63 static_assert(std::same_as<Kokkos::Execution::Impl::exec_of_t<then_sndr_t>, TEST_EXECUTION_SPACE>);
64
67
69 using policy_t = typename then_sndr_t::closure_t::policy_t;
70 static_assert(std::same_as<typename policy_t::launch_bounds, Kokkos::LaunchBounds<1>>);
71
72 return true;
73}
74static_assert(test_sndr_traits());
75
78 typename ThenTest::scheduler_t,
79 stdexec::then_t,
81>());
82
87TEST_F(ThenTest, then_schedule) {
88 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
89
90 const context_t esc{exec};
91
92 auto chain = stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data) | THEN_INCREMENT(data);
93
94 using chain_t = decltype(chain);
95
97 static_assert(std::same_as<stdexec::__domain_of_t<stdexec::env_of_t<chain_t>>, stdexec::default_domain>);
98 static_assert(std::same_as<
99 stdexec::__detail::__completing_domain_t<stdexec::set_value_t, chain_t>,
101 >);
102
104 static_assert(std::same_as<
105 decltype(stdexec::get_completion_scheduler<stdexec::set_value_t>(stdexec::get_env(chain))),
107 >);
108
109 ASSERT_THAT(
111 testing::ElementsAre(
115
116 ASSERT_EQ(data(), 2);
117}
118
123TEST_F(ThenTest, then_starts_on) {
124 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
125
126 const context_t esc{exec};
127
129 auto chain = stdexec::just() | THEN_INCREMENT(data) | THEN_INCREMENT(data);
130
134 using chain_t = decltype(chain);
135
136 static_assert(
137 stdexec::get_completion_signatures<chain_t>()
138 == stdexec::completion_signatures<stdexec::set_value_t(), stdexec::set_error_t(std::exception_ptr)>{});
140 static_assert(
141 std::same_as<stdexec::__completion_domain_of_t<stdexec::set_value_t, chain_t>, stdexec::indeterminate_domain<>>);
142
144 auto starts_on = stdexec::starts_on(esc.get_scheduler(), std::move(chain));
145
146 using starts_on_t = decltype(starts_on);
147
149 static_assert(stdexec::__has_eptr_completion<chain_t>);
150 static_assert(!stdexec::dependent_sender<starts_on_t>);
151 static_assert(
152 stdexec::get_completion_signatures<starts_on_t>()
153 == stdexec::completion_signatures<stdexec::set_value_t(), stdexec::set_error_t(std::exception_ptr)>{});
154
156 static_assert(stdexec::__completes_where_it_starts<stdexec::set_value_t, stdexec::env_of_t<chain_t>>);
158 static_assert(std::same_as<
161 >);
162 static_assert(std::same_as<
163 stdexec::__completion_domain_of_t<stdexec::set_value_t, starts_on_t, stdexec::env<>>,
165 >);
166
167 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
168
169 const auto recorded_events = Tests::Utils::record_sync_wait<recorder_listener_t>(std::move(starts_on));
170
171 ASSERT_THAT(recorded_events, [&]() {
173 return testing::ElementsAre(
177 MATCHER_FOR_WAIT_EVENT(recorded_events.at(2)));
178 } else {
179 return testing::ElementsAre(
182 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch")));
183 }
184 }());
185
186 ASSERT_EQ(data(), 2);
187}
188
196TEST_F(ThenTest, error_propagates) {
197 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
198
199 const context_t esc{exec};
200
201 stdexec::sender auto sndr = stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data)
203 | stdexec::then(KOKKOS_LAMBDA() {
204 Kokkos::abort("The value channel should be used at this point.");
205 });
206
207 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
208
209 ASSERT_THAT(
210 recorder_listener_t::record([sndr = std::move(sndr)]() mutable {
211 ASSERT_THAT(
212 Tests::Utils::Functors::MutableMoveToSyncWait{.sndr = std::move(sndr)},
213 testing::ThrowsMessage<std::runtime_error>(
214 testing::HasSubstr("ThrowsWhenCopied: Throwing in copy constructor!")));
215 }),
216 testing::ElementsAre(
217 MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")), // Increment: succeeds
218 MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "then")), // ThrowsWhenCopied: throws on copy
220
221 ASSERT_EQ(data(), 1);
222}
223
229TEST_F(ThenTest, then_lifetime) {
231 const context_t esc{exec};
232
234 auto create_chain_in_scope = [&]() {
235 const view_s_t data(Kokkos::view_alloc("data - shared space", exec));
236
237 return stdexec::schedule(esc.get_scheduler()) | THEN_INCREMENT(data) | THEN_INCREMENT(data);
238 };
239
241 const auto run_test = [&]() {
242 auto chain = create_chain_in_scope();
243
244 using chain_t = decltype(chain);
245
247 static_assert(std::same_as<stdexec::__domain_of_t<stdexec::env_of_t<chain_t>>, stdexec::default_domain>);
248 static_assert(std::same_as<
249 stdexec::__detail::__completing_domain_t<stdexec::set_value_t, chain_t>,
251 >);
252
254 static_assert(std::same_as<
255 decltype(stdexec::get_completion_scheduler<stdexec::set_value_t>(stdexec::get_env(chain))),
257 >);
258
259 stdexec::sync_wait(std::move(chain));
260 };
261
262 ASSERT_THAT(
263 recorder_listener_t::record(run_test),
266 testing::Field(
268 testing::Field(
269 &Kokkos::utils::callbacks::AllocDescriptor::name, testing::StrEq("data - shared space")))),
274 testing::Field(
276 testing::Field(
277 &Kokkos::utils::callbacks::AllocDescriptor::name, testing::StrEq("data - shared space"))))));
278}
279
281consteval bool test_sndr_nothrow_transformable() {
282 using sndr_then_t =
283 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(Tests::Utils::Functors::NoOp<false, false, false>{}));
284
285 static_assert(std::same_as<
286 stdexec::__demangle_t<sndr_then_t>,
288 stdexec::then_t,
291 >
292 >);
293
294 static_assert(stdexec::__detail::__has_nothrow_transform_sender<
296 stdexec::set_value_t,
297 sndr_then_t&&,
298 stdexec::env<>
299 >);
300
301 using sndr_then_maythrow_on_move_t =
302 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(Tests::Utils::Functors::NoOp<false, false, true>{}));
303
304 static_assert(!stdexec::__detail::__has_nothrow_transform_sender<
306 stdexec::set_value_t,
307 sndr_then_maythrow_on_move_t&&,
308 stdexec::env<>
309 >);
310
311 return true;
312}
313static_assert(test_sndr_nothrow_transformable());
314
316TEST_F(ThenTest, forwarding_env) {
317 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
318
319 std::atomic<size_t> count = 0;
320
321 int value;
322
323 const context_t esc{exec};
324
325 stdexec::sender auto sndr =
326 stdexec::read_env(stdexec::get_allocator)
327 | stdexec::then([&value](auto allocator) { value = Tests::Utils::round_trip_allocate(allocator, 42); })
328 | stdexec::continues_on(esc.get_scheduler())
330 | stdexec::write_env(stdexec::prop{stdexec::get_allocator, Tests::Utils::TrackingAllocator<int>{&count}});
331
332 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
333
334 const auto recorded_events = Tests::Utils::record_sync_wait<recorder_listener_t>(std::move(sndr));
335
336 ASSERT_THAT(recorded_events, [&]() {
338 return testing::ElementsAre(
341 MATCHER_FOR_WAIT_EVENT(recorded_events.at(1)));
342 } else {
343 return testing::ElementsAre(
345 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch")));
346 }
347 }());
348
349 ASSERT_EQ(data(), 1);
350
351 ASSERT_EQ(value, 42);
352 ASSERT_EQ(count, 1);
353}
354
355} // 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_)
typename recorder_listener_t::event_variant_t variant_t
Definition test_then.cpp:46
RecorderListener< EventDiscardMatcher< TEST_EXECUTION_SPACE >, BeginFenceEvent, BeginParallelForEvent, AllocateDataEvent, DeallocateDataEvent, Kokkos::Execution::Impl::RecordEvent, Kokkos::Execution::Impl::WaitEvent > recorder_listener_t
Definition test_then.cpp:37
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:59
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:83
typename stdexec::__basic_sender< Args... >::type basic_sender_t
See https://github.com/NVIDIA/stdexec/pull/1873#discussion_r2834863237.
Definition stdexec.hpp:12
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< Exec >
Event to be sent to Kokkos::utils::callbacks::dispatch when calling record.
Definition event.hpp:54
Event to be sent to Kokkos::utils::callbacks::dispatch when calling wait.
Definition event.hpp:75
decltype(std::declval< const context_t >().get_scheduler()) scheduler_t
Definition context.hpp:28
decltype(stdexec::schedule(std::declval< scheduler_t >())) schedule_sender_t
Definition context.hpp:29
Kokkos::Execution::ExecutionSpaceContext< Exec > context_t
Definition context.hpp:27
This helper struct throws when copy constructed.
A minimal tracking allocator.