kokkos-execution 0.0.1
Loading...
Searching...
No Matches
test_then.cpp
Go to the documentation of this file.
4
7
22
34
35namespace Tests::GraphImpl {
36
37using namespace Kokkos::utils::callbacks;
38
57
59consteval bool test_sndr_traits() {
61 using schd_sndr_t = typename ThenTest::schedule_sender_t;
62
65 using then_sndr_t = stdexec::transform_sender_result_t<
66 decltype(stdexec::then(std::declval<schd_sndr_t>(), std::declval<functor_t>())),
67 stdexec::env<>
68 >;
69
72 static_assert(std::same_as<Kokkos::Execution::Impl::exec_of_t<then_sndr_t>, TEST_EXECUTION_SPACE>);
73
76
77 return true;
78}
79static_assert(test_sndr_traits());
80
83 typename ThenTest::scheduler_t,
84 stdexec::then_t,
86>());
87
89consteval bool test_sndr_nothrow_transformable() {
90 using sndr_then_t =
91 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(Tests::Utils::Functors::NoOp<false, false, false>{}));
92
93 static_assert(std::same_as<
94 stdexec::__demangle_t<sndr_then_t>,
96 stdexec::then_t,
99 >
100 >);
101
102 static_assert(stdexec::__detail::__has_nothrow_transform_sender<
104 stdexec::set_value_t,
105 sndr_then_t&&,
106 stdexec::env<>
107 >);
108
109 using sndr_then_maythrow_on_move_t =
110 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(Tests::Utils::Functors::NoOp<false, false, true>{}));
111
112 static_assert(!stdexec::__detail::__has_nothrow_transform_sender<
113 Kokkos::Execution::GraphImpl::Domain,
114 stdexec::set_value_t,
115 sndr_then_maythrow_on_move_t&&,
116 stdexec::env<>
117 >);
118
119 return true;
120}
121static_assert(test_sndr_nothrow_transformable());
122
124consteval bool test_sndr_nothrow_connectable() {
126 static_assert(!std::is_nothrow_constructible_v<Kokkos::Experimental::Graph<TEST_EXECUTION_SPACE>>);
127
128 using sndr_then_t =
129 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(Tests::Utils::Functors::NoOp<false, false, false>{}));
130
131 static_assert(!stdexec::__nothrow_connectable<sndr_then_t, Tests::Utils::SinkReceiver>);
132
133 return true;
134}
135static_assert(test_sndr_nothrow_connectable());
136
140
141 using sndr_t =
142 decltype(stdexec::schedule(std::declval<typename ThenTest::scheduler_t>()) | stdexec::then(functor_t{}) | stdexec::then(functor_t{}));
143 using connect_result_t = stdexec::connect_result_t<sndr_t, Tests::Utils::SinkReceiver>;
144
145 static_assert(stdexec::__is_instance_of<connect_result_t, Kokkos::Execution::GraphImpl::OpState>);
146
147 using root_t = typename ThenTest::graph_t::root_t;
148 using then_A_t = Kokkos::Experimental::GraphNodeRef<
149 TEST_EXECUTION_SPACE,
150 Kokkos::Impl::GraphNodeThenImpl<TEST_EXECUTION_SPACE, Kokkos::Experimental::ThenPolicy<>, functor_t>,
151 root_t
152 >;
153 using then_B_t = Kokkos::Experimental::GraphNodeRef<
154 TEST_EXECUTION_SPACE,
155 Kokkos::Impl::GraphNodeThenImpl<TEST_EXECUTION_SPACE, Kokkos::Experimental::ThenPolicy<>, functor_t>,
156 then_A_t
157 >;
158
159 static_assert(std::same_as<typename connect_result_t::predecessor_t, root_t>);
160 static_assert(std::same_as<typename connect_result_t::node_t, then_B_t>);
161
162 return true;
163}
164static_assert(test_then_op_state_traits());
165
170TEST_F(ThenTest, then_schedule) {
171 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
172
173 const context_t gctx{exec};
174
176
177 auto sndr = stdexec::schedule(gctx.get_scheduler())
178 | stdexec::then(functor_t{.prev = 0, .value = 4, .data = data.data()})
179 | stdexec::then(functor_t{.prev = 4, .value = 3, .data = data.data()});
180
181 using sndr_t = decltype(sndr);
182
183 static_assert(std::same_as<
184 stdexec::__demangle_t<stdexec::transform_sender_result_t<sndr_t, stdexec::env<>>>,
186 TEST_EXECUTION_SPACE,
188 functor_t
189 >
190 >);
191
193 static_assert(std::same_as<stdexec::__domain_of_t<stdexec::env_of_t<sndr_t>>, stdexec::default_domain>);
194 static_assert(std::same_as<
195 stdexec::__detail::__completing_domain_t<stdexec::set_value_t, sndr_t>,
197 >);
198
200 static_assert(std::same_as<
202 typename ThenTest::scheduler_t
203 >);
204
205 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
206
207 const auto recorded_events = Tests::Utils::record_sync_wait<recorder_listener_t>(
208 std::move(sndr)); // NOLINT(performance-move-const-arg)
209
210 ASSERT_THAT(
211 recorded_events,
212 testing::ElementsAre(
215 recorded_events.at(0), device_handle, MATCHER_FOR_GRAPH_ROOT_NODE_OF(recorded_events.at(0))),
217 recorded_events.at(0), device_handle, MATCHER_FOR_GRAPH_NODE_OF(recorded_events.at(1))),
218 MATCHER_FOR_GRAPH_SUBMIT(exec, recorded_events.at(0)),
220
221 ASSERT_EQ(data(), 7);
222}
223
228TEST_F(ThenTest, then_starts_on) {
229 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
230
231 const context_t gctx{exec};
232
234 auto chain = stdexec::just() | THEN_INCREMENT(data);
235
238 using chain_t = decltype(chain);
239
240 static_assert(
241 stdexec::get_completion_signatures<chain_t>()
242 == stdexec::completion_signatures<stdexec::set_value_t(), stdexec::set_error_t(std::exception_ptr)>{});
244 static_assert(
245 std::same_as<stdexec::__completion_domain_of_t<stdexec::set_value_t, chain_t>, stdexec::indeterminate_domain<>>);
246
248 auto starts_on = stdexec::starts_on(gctx.get_scheduler(), std::move(chain));
249
250 using starts_on_t = decltype(starts_on);
251
253 static_assert(stdexec::__has_eptr_completion<chain_t>);
254 static_assert(!stdexec::dependent_sender<starts_on_t>);
255 static_assert(
256 stdexec::get_completion_signatures<starts_on_t>()
257 == stdexec::completion_signatures<stdexec::set_value_t(), stdexec::set_error_t(std::exception_ptr)>{});
258
260 static_assert(stdexec::__completes_where_it_starts<stdexec::set_value_t, stdexec::env_of_t<chain_t>>);
262 static_assert(std::same_as<
265 >);
266 static_assert(std::same_as<
267 stdexec::__completion_domain_of_t<stdexec::set_value_t, starts_on_t, stdexec::env<>>,
269 >);
270
271 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
272
273 const auto recorded_events = Tests::Utils::record_sync_wait<recorder_listener_t>(std::move(starts_on));
274
275 ASSERT_THAT(
276 recorded_events,
277 testing::ElementsAre(
280 recorded_events.at(0), device_handle, MATCHER_FOR_GRAPH_ROOT_NODE_OF(recorded_events.at(0))),
281 MATCHER_FOR_GRAPH_SUBMIT(exec, recorded_events.at(0)),
282 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch"))));
283
284 ASSERT_EQ(data(), 1);
285}
286
288TEST_F(ThenTest, forwarding_env) {
289 const view_s_t data(Kokkos::view_alloc(exec, "data - shared space"));
290
291 std::atomic<size_t> count = 0;
292
293 int value;
294
295 const context_t gctx{exec};
296
297 stdexec::sender auto sndr =
298 stdexec::read_env(stdexec::get_allocator)
299 | stdexec::then([&value](auto allocator) { value = Tests::Utils::round_trip_allocate(allocator, 42); })
300 | stdexec::continues_on(gctx.get_scheduler())
302 | stdexec::write_env(stdexec::prop{stdexec::get_allocator, Tests::Utils::TrackingAllocator<int>{&count}});
303
304 ASSERT_EQ(data(), 0) << "Eager execution is not allowed.";
305
307
308 const auto recorded_events = Tests::Utils::record_sync_wait<recorder_listener_t>(std::move(sndr));
309
310 ASSERT_THAT(
311 recorded_events,
312 testing::ElementsAre(
315 recorded_events.at(0), device_handle, MATCHER_FOR_GRAPH_ROOT_NODE_OF(recorded_events.at(0))),
316 MATCHER_FOR_GRAPH_SUBMIT(exec, recorded_events.at(0)),
317 MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch"))));
318
319 ASSERT_EQ(data(), 1);
320
321 ASSERT_EQ(value, 42);
322 ASSERT_EQ(count, 1);
323}
324
325} // namespace Tests::GraphImpl
constexpr std::string dispatch_label(const Exec &, Label &&label)
Get the dispatch label from Exec and label.
#define MATCHER_FOR_BEGIN_FENCE(_exec_, _label_)
RecorderListener< ConjunctionMatcher< EventDiscardMatcher< TEST_EXECUTION_SPACE >, GraphEventDiscardMatcher< TEST_EXECUTION_SPACE > >, BeginFenceEvent, BeginParallelForEvent, AllocateDataEvent, DeallocateDataEvent, Kokkos::Execution::Impl::RecordEvent, Kokkos::Execution::Impl::WaitEvent, Kokkos::Execution::GraphImpl::GraphAddNodeEvent, Kokkos::Execution::GraphImpl::GraphCreateEvent, Kokkos::Execution::GraphImpl::GraphInstantiateEvent, Kokkos::Execution::GraphImpl::GraphSubmitEvent > recorder_listener_t
Definition test_then.cpp:43
Concept for a sender whose completion scheduler is Kokkos::Execution::GraphImpl::Scheduler.
Concept that constrains the type of a sender that dispatches a functor for execution.
#define KOKKOS_EXECUTION_TEST_UTILS_GRAPH_FENCE(_exec_)
#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.
consteval bool test_sndr_nothrow_transformable()
Definition test_bulk.cpp:89
consteval bool test_then_op_state_traits()
consteval bool test_sndr_traits()
Definition test_bulk.cpp:57
consteval bool test_sndr_nothrow_connectable()
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)
auto get_scheduler() const noexcept -> GraphImpl::Scheduler< Exec >
Definition graph.hpp:134
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph node is added.
Definition events.hpp:36
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph is created.
Definition events.hpp:16
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph is instantiated.
Definition events.hpp:66
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph is submitted.
Definition events.hpp:77
Sender for stdexec::then.
Definition then.hpp:51
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
Similar to EventDiscardMatcher, for graph-related events.
Definition events.hpp:80
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::View< value_t, Kokkos::SharedSpace > view_s_t
Definition context.hpp:32
Load the value at data and check it is equal to prev. Then, add value to it.
A minimal tracking allocator.
#define MATCHER_FOR_GRAPH_CREATE(_device_handle_)
Definition events.hpp:17
#define MATCHER_FOR_GRAPH_SUBMIT(_exec_, _graph_create_event_variant_)
Definition events.hpp:67
#define MATCHER_FOR_GRAPH_ADDNODE(_graph_create_event_variant_, _device_handle_, _predecessor_)
Definition events.hpp:24
#define MATCHER_FOR_GRAPH_ROOT_NODE_OF(_graph_create_event_)
Definition events.hpp:47
#define MATCHER_FOR_GRAPH_NODE_OF(_graph_add_node_event_)
Definition events.hpp:51