kokkos-execution 0.0.1
Loading...
Searching...
No Matches
test_completion_signal.cpp
Go to the documentation of this file.
3
5
10
22
23namespace Tests::Impl {
24
25using namespace Kokkos::utils::callbacks;
26
28 : public Tests::Utils::ExecutionSpaceContextTest<TEST_EXECUTION_SPACE>
30 public:
32 std::string,
34 Kokkos::RangePolicy<TEST_EXECUTION_SPACE>
35 >;
36
42 >;
43
44 public:
46 : data(Kokkos::view_alloc(exec, "data - shared space"))
47 , esc{exec}
48 , pfor_data{
49 "hello from pfor",
50 Tests::Utils::Functors::SumIndices{.data = data},
51 Kokkos::RangePolicy<TEST_EXECUTION_SPACE>(0, size)} {
52 }
53
54 protected:
55 static constexpr size_t size = 10;
59};
60
63 using completion_signal_inline_fence_exec_t = Kokkos::Execution::Impl::CompletionSignal<
65 TEST_EXECUTION_SPACE,
67 >;
68
69 static_assert(sizeof(completion_signal_inline_fence_exec_t) == sizeof(Tests::Utils::SinkReceiver));
70
71 using completion_signal_schedule_wait_event_t = Kokkos::Execution::Impl::CompletionSignal<
73 TEST_EXECUTION_SPACE,
75 >;
76
77 static_assert(
78 sizeof(completion_signal_schedule_wait_event_t)
81
82 using completion_signal_order_on_exec_t = Kokkos::Execution::Impl::CompletionSignal<
84 TEST_EXECUTION_SPACE,
86 >;
87
88 static_assert(
89 sizeof(completion_signal_order_on_exec_t)
91
92 using completion_signal_depend_on_event_t = Kokkos::Execution::Impl::CompletionSignal<
94 TEST_EXECUTION_SPACE,
96 >;
97
99 static_assert(
100 sizeof(completion_signal_depend_on_event_t)
102
103 return true;
104}
105static_assert(test_completion_signal_traits());
106
108TEST_F(CompletionSignalTest, inline_fence_exec_policy) {
109 auto op_state = stdexec::connect(
110 stdexec::schedule(esc.get_scheduler())
113
114 static_assert(std::same_as<
115 typename decltype(op_state)::completion_signal_policy_t,
117 >);
118 static_assert(!Kokkos::Execution::Impl::signals_submitted<decltype(op_state)>);
119
120 ASSERT_THAT(
121 recorder_listener_t::record([&]() { op_state.start(); }),
122 testing::ElementsAre(MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch"))));
123
124 ASSERT_EQ(data(), size / 2 * (size - 1));
125}
126
127template <Kokkos::ExecutionSpace Exec, bool SubmittedOrderOn, bool SubmittedDependOn>
128struct Receiver {
129 using receiver_concept = std::conditional_t<
130 SubmittedOrderOn || SubmittedDependOn,
132 stdexec::receiver_tag
133 >;
134
136 stdexec::run_loop* loop;
137
138 void set_value() && noexcept {
139 loop->finish();
140 }
141
142 template <typename Error>
143 void set_error(Error&&) && noexcept {
144 loop->finish();
145 }
146
147 void submitted() && noexcept requires(SubmittedOrderOn)
148 {
149 loop->finish();
150 }
151
152 void submitted(Kokkos::Execution::Impl::OptionalConstEventRef<Exec> dep) && noexcept requires(SubmittedDependOn)
153 {
154 if (dep.has_value()) {
156 }
157 loop->finish();
158 }
159
160 [[nodiscard]]
161 constexpr auto get_env() const noexcept {
163 stdexec::prop{stdexec::get_delegation_scheduler, loop->get_scheduler()}, state->exec);
164 }
165};
166
168TEST_F(CompletionSignalTest, schedule_wait_event_policy) {
170 GTEST_SKIP() << "The execution space does not have non-blocking dispatch.";
171 }
172
173 const auto [exec_A, exec_B] = Kokkos::Experimental::partition_space(exec, 1, 1);
174 const context_t esc_A{exec_A}, esc_B{exec_B};
175
176 stdexec::run_loop loop;
177
178 auto op_state = stdexec::connect(
179 stdexec::schedule(esc_A.get_scheduler())
181 Receiver<TEST_EXECUTION_SPACE, false, false>{&esc_B.m_state, &loop});
182
183 const auto recorded_events_before_run = recorder_listener_t::record([&]() { op_state.start(); });
184
185 ASSERT_THAT(recorded_events_before_run, testing::ElementsAre(MATCHER_FOR_RECORD_EVENT(exec_A)));
186
187 const auto recorded_events_after_run = recorder_listener_t::record([&]() { loop.run(); });
188
189 ASSERT_THAT(
190 recorded_events_after_run, testing::ElementsAre(MATCHER_FOR_WAIT_EVENT(recorded_events_before_run.at(0))));
191
192 ASSERT_EQ(data(), size / 2 * (size - 1));
193}
194
196TEST_F(CompletionSignalTest, order_on_exec_policy) {
198 std::optional<std::tuple<>> result;
199
200 auto op_state = stdexec::connect(
201 stdexec::schedule(esc.get_scheduler())
204 .state = std::addressof(esc.m_state),
205 .runloop_state = std::addressof(runloop_state),
206 .result = std::addressof(result)});
207
208 static_assert(std::same_as<
209 typename decltype(op_state)::completion_signal_policy_t,
211 >);
212 static_assert(Kokkos::Execution::Impl::signals_submitted<decltype(op_state)>);
213
214 ASSERT_THAT(
215 recorder_listener_t::record([&]() { op_state.start(); }),
216 testing::ElementsAre(MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "sync_wait"))));
217
218 ASSERT_EQ(data(), size / 2 * (size - 1));
219
220 runloop_state.loop.run();
221}
222
224TEST_F(CompletionSignalTest, depend_on_event_policy) {
225 const auto [exec_A, exec_B] = Kokkos::Experimental::partition_space(exec, 1, 1);
226 const context_t esc_A{exec_A}, esc_B{exec_B};
227
228 stdexec::run_loop loop;
229
230 auto op_state = stdexec::connect(
231 stdexec::schedule(esc_A.get_scheduler())
233 Receiver<TEST_EXECUTION_SPACE, false, true>{&esc_B.m_state, &loop});
234
236 static_assert(std::same_as<
237 typename decltype(op_state)::completion_signal_policy_t,
239 >);
240 static_assert(Kokkos::Execution::Impl::signals_submitted<decltype(op_state)>);
241
242 const auto recorded_events = recorder_listener_t::record([&]() { op_state.start(); });
243
244 if (Tests::Utils::are_same_instances(exec_A, exec_B)) {
245 ASSERT_THAT(recorded_events, testing::IsEmpty());
246 } else {
247 ASSERT_THAT(
248 recorded_events,
249 testing::ElementsAre(MATCHER_FOR_RECORD_EVENT(exec_A), MATCHER_FOR_WAIT_EVENT(recorded_events.at(0))));
250 }
251
252 ASSERT_EQ(data(), size / 2 * (size - 1));
253
254 loop.run();
255}
256
257} // namespace Tests::Impl
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_RECORD_EVENT(_exec_)
#define MATCHER_FOR_BEGIN_FENCE(_exec_, _label_)
Kokkos::Execution::Impl::ParallelForData< std::string, Tests::Utils::Functors::SumIndices< view_s_t >, Kokkos::RangePolicy< TEST_EXECUTION_SPACE > > parallel_for_data_t
RecorderListener< EventDiscardMatcher< TEST_EXECUTION_SPACE >, BeginFenceEvent, Kokkos::Execution::Impl::RecordEvent, Kokkos::Execution::Impl::WaitEvent > recorder_listener_t
constexpr auto join_env_with_exec(Env &&env, const Exec &exec) noexcept
Unconditionally join exec to env.
Definition env.hpp:15
OptionalRef< const Event< Exec > > OptionalConstEventRef
Optionally stores a reference to a const Impl::Event.
Definition event.hpp:178
std::optional< Event< Exec > > event_storage_t
Definition event.hpp:174
void wait(const Event< Exec > &... events)
Wait for events to complete.
Definition event.hpp:152
constexpr parallel_for_t parallel_for
consteval bool test_completion_signal_traits()
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.
auto get_scheduler() const noexcept -> ExecutionSpaceImpl::Scheduler< Exec >
Event to be sent to Kokkos::utils::callbacks::dispatch when calling record.
Definition event.hpp:54
Receiver for stdexec::sync_wait.
Definition sync_wait.hpp:46
Inspired by https://github.com/NVIDIA/stdexec/blob/16076a81efa4477513e6ede9c2741fd034ecef99/include/s...
Definition sync_wait.hpp:31
Event to be sent to Kokkos::utils::callbacks::dispatch when calling wait.
Definition event.hpp:75
void submitted(Kokkos::Execution::Impl::OptionalConstEventRef< Exec > dep) &&noexcept
void set_error(Error &&) &&noexcept
constexpr auto get_env() const noexcept
std::conditional_t< SubmittedOrderOn||SubmittedDependOn, Kokkos::Execution::Impl::SubmittedReceiverTag, stdexec::receiver_tag > receiver_concept
Kokkos::Execution::Impl::State< Exec > const * state
Kokkos::Execution::ExecutionSpaceContext< Exec > context_t
Definition context.hpp:27
A receiver that can handle all completions and does nothing with them.