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_passthrough_event_t = Kokkos::Execution::Impl::CompletionSignal<
84 TEST_EXECUTION_SPACE,
86 >;
87
88 static_assert(
89 sizeof(completion_signal_passthrough_event_t)
91
92 using completion_signal_defer_wait_event_t = Kokkos::Execution::Impl::CompletionSignal<
94 TEST_EXECUTION_SPACE,
96 >;
97
99 static_assert(
100 sizeof(completion_signal_defer_wait_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(
115 std::same_as<typename decltype(op_state)::sync_policy_t, Kokkos::Execution::Impl::SyncPolicy::InlineFenceExec>);
116
117 ASSERT_THAT(
118 recorder_listener_t::record([&]() { op_state.start(); }),
119 testing::ElementsAre(MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "after dispatch"))));
120
121 ASSERT_EQ(data(), size / 2 * (size - 1));
122}
123
124template <Kokkos::ExecutionSpace Exec, bool IsDeferredCompletionReceiver>
125struct Receiver {
126 using receiver_concept = std::conditional_t<
127 IsDeferredCompletionReceiver,
129 stdexec::receiver_tag
130 >;
131
133 stdexec::run_loop* loop;
134
135 void set_value() && noexcept {
136 loop->finish();
137 }
138
139 template <typename Error>
140 void set_error(Error&&) && noexcept {
141 loop->finish();
142 }
143
144 void continues_after() && noexcept requires(IsDeferredCompletionReceiver)
145 {
146 loop->finish();
147 }
148
150 requires(IsDeferredCompletionReceiver)
151 {
153 loop->finish();
154 }
155
156 [[nodiscard]]
157 constexpr auto get_env() const noexcept {
159 stdexec::prop{stdexec::get_delegation_scheduler, loop->get_scheduler()}, state->exec);
160 }
161};
162
164TEST_F(CompletionSignalTest, schedule_wait_event_policy) {
166 GTEST_SKIP() << "The execution space does not have non-blocking dispatch.";
167 }
168
169 const auto [exec_A, exec_B] = Kokkos::Experimental::partition_space(exec, 1, 1);
170 const context_t esc_A{exec_A}, esc_B{exec_B};
171
172 stdexec::run_loop loop;
173
174 auto op_state = stdexec::connect(
175 stdexec::schedule(esc_A.get_scheduler())
177 Receiver<TEST_EXECUTION_SPACE, false>{&esc_B.m_state, &loop});
178
179 const auto recorded_events_before_run = recorder_listener_t::record([&]() { op_state.start(); });
180
181 ASSERT_THAT(recorded_events_before_run, testing::ElementsAre(MATCHER_FOR_RECORD_EVENT(exec_A)));
182
183 const auto recorded_events_after_run = recorder_listener_t::record([&]() { loop.run(); });
184
185 ASSERT_THAT(
186 recorded_events_after_run, testing::ElementsAre(MATCHER_FOR_WAIT_EVENT(recorded_events_before_run.at(0))));
187
188 ASSERT_EQ(data(), size / 2 * (size - 1));
189}
190
192TEST_F(CompletionSignalTest, passthrough_policy) {
194 std::optional<std::tuple<>> result;
195
196 auto op_state = stdexec::connect(
197 stdexec::schedule(esc.get_scheduler())
200 .state = std::addressof(esc.m_state),
201 .runloop_state = std::addressof(runloop_state),
202 .result = std::addressof(result)});
203
204 static_assert(
205 std::same_as<typename decltype(op_state)::sync_policy_t, Kokkos::Execution::Impl::SyncPolicy::PassThrough>);
206
207 ASSERT_THAT(
208 recorder_listener_t::record([&]() { op_state.start(); }),
209 testing::ElementsAre(MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "sync_wait"))));
210
211 ASSERT_EQ(data(), size / 2 * (size - 1));
212
213 runloop_state.loop.run();
214}
215
217TEST_F(CompletionSignalTest, defer_wait_event_policy) {
218 const auto [exec_A, exec_B] = Kokkos::Experimental::partition_space(exec, 1, 1);
219 const context_t esc_A{exec_A}, esc_B{exec_B};
220
221 stdexec::run_loop loop;
222
223 auto op_state = stdexec::connect(
224 stdexec::schedule(esc_A.get_scheduler())
226 Receiver<TEST_EXECUTION_SPACE, true>{&esc_B.m_state, &loop});
227
230 TEST_EXECUTION_SPACE
231 >);
232 static_assert(
233 std::same_as<typename decltype(op_state)::sync_policy_t, Kokkos::Execution::Impl::SyncPolicy::DeferWaitEvent>);
234
235 const auto recorded_events = recorder_listener_t::record([&]() { op_state.start(); });
236
237 if (Tests::Utils::are_same_instances(exec_A, exec_B)) {
238 ASSERT_THAT(recorded_events, testing::IsEmpty());
239 } else {
240 ASSERT_THAT(
241 recorded_events,
242 testing::ElementsAre(MATCHER_FOR_RECORD_EVENT(exec_A), MATCHER_FOR_WAIT_EVENT(recorded_events.at(0))));
243 }
244
245 ASSERT_EQ(data(), size / 2 * (size - 1));
246
247 loop.run();
248}
249
250} // 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
std::optional< Event< Exec > > event_storage_t
Definition event.hpp:167
void wait(const Event< Exec > &event)
Wait for event to complete.
Definition event.hpp:145
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 >
An event that can be recorded on an execution space instance.
Definition event.hpp:108
Event to be sent to Kokkos::utils::callbacks::dispatch when calling record.
Definition event.hpp:52
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:73
std::conditional_t< IsDeferredCompletionReceiver, Kokkos::Execution::Impl::DeferredCompletionReceiverTag, stdexec::receiver_tag > receiver_concept
void set_error(Error &&) &&noexcept
void continues_after(const Kokkos::Execution::Impl::Event< Exec > &event) &&noexcept
Kokkos::Execution::Impl::State< Exec > const * state
constexpr auto get_env() const noexcept
Kokkos::Execution::ExecutionSpaceContext< Exec > context_t
Definition context.hpp:27
A receiver that can handle all completions and does nothing with them.