kokkos-execution 0.0.1
Loading...
Searching...
No Matches
test_parallel_for.cpp
Go to the documentation of this file.
1#include <bit>
2
5
12
23
25
26using namespace Kokkos::utils::callbacks;
27
38
43template <template <typename, typename, typename, typename> class SndrAdptr>
44consteval bool test_sndr_traits() {
46 using schd_sndr_t = typename ParallelForTest::schedule_sender_t;
47
49 using label_t = std::string;
51 using policy_t = Kokkos::RangePolicy<TEST_EXECUTION_SPACE>;
52 using pfor_sndr_t = SndrAdptr<schd_sndr_t, label_t, functor_t, policy_t>;
53
56 static_assert(std::same_as<Kokkos::Execution::ExecutionSpaceImpl::exec_of_t<pfor_sndr_t>, TEST_EXECUTION_SPACE>);
57
60
62 using completion_signatures_t = stdexec::__completion_signatures_of_t<pfor_sndr_t, stdexec::env<>>;
63
64 static_assert(stdexec::__mset_eq<
65 stdexec::__mset<stdexec::set_value_t(), stdexec::set_error_t(std::exception_ptr)>,
66 completion_signatures_t
67 >);
68
70 static_assert(std::same_as<
71 stdexec::__completion_domain_of_t<stdexec::set_value_t, pfor_sndr_t, stdexec::env<>>,
73 >);
74
76 static_assert(std::same_as<
77 stdexec::__completion_scheduler_of_t<stdexec::set_value_t, pfor_sndr_t, stdexec::env<>>,
79 >);
80
82 static_assert(stdexec::sender_to<pfor_sndr_t, Tests::Utils::SinkReceiver>);
83
84 static_assert(std::same_as<
85 stdexec::transform_sender_result_t<pfor_sndr_t, stdexec::env_of_t<Tests::Utils::SinkReceiver>>,
87 >);
88
90#if defined(KOKKOS_COMPILER_CLANG) && defined(KOKKOS_ENABLE_CUDA)
98 static_assert(!std::is_nothrow_move_constructible_v<typename ParallelForTest::view_s_t>);
99 static_assert(!std::is_nothrow_move_constructible_v<functor_t>);
101 static_assert(!std::is_nothrow_move_constructible_v<closure_t>);
102 static_assert(!stdexec::__nothrow_connectable<pfor_sndr_t, Tests::Utils::SinkReceiver>);
103#else
105 static_assert(stdexec::__nothrow_connectable<pfor_sndr_t, Tests::Utils::SinkReceiver>);
106#endif
107
108 return true;
109}
112
114consteval bool test_sndr_decomposition() {
116 using schd_sndr_t = typename ParallelForTest::schedule_sender_t;
117
119 using label_t = std::string;
121 using policy_t = Kokkos::RangePolicy<TEST_EXECUTION_SPACE>;
123
125 static_assert(std::same_as<stdexec::tag_of_t<pfor_sndr_t>, Kokkos::Execution::parallel_for_t>);
126
127 static_assert(std::same_as<
128 stdexec::__data_of<pfor_sndr_t>,
130 >);
131
132 static_assert(stdexec::__nbr_children_of<pfor_sndr_t> == 1);
133 static_assert(std::same_as<stdexec::__child_of<pfor_sndr_t>, schd_sndr_t>);
134
136 static_assert(stdexec::__applicable<
138 pfor_sndr_t,
139 const stdexec::env<>&
140 >);
141
142 return true;
143}
144static_assert(test_sndr_decomposition());
145
147template <typename ViewType, bool ExpectNoThrowMoveConstructible>
148consteval bool test_closure_traits() {
150 using policy_t = Kokkos::RangePolicy<TEST_EXECUTION_SPACE>;
152
155
156 static_assert(std::is_nothrow_move_constructible_v<closure_t> == ExpectNoThrowMoveConstructible);
157
158 return true;
159}
160
161#if defined(KOKKOS_COMPILER_CLANG) && defined(KOKKOS_ENABLE_CUDA)
163#else
165#endif
166static_assert(test_closure_traits<std::span<int>, true>());
167
169TEST_F(ParallelForTest, team_policy) {
170 constexpr int size = 32;
171
172 const auto [num_teams, team_size] = [&]() {
174#if defined(KOKKOS_ENABLE_HPX)
175 if constexpr (std::same_as<TEST_EXECUTION_SPACE, Kokkos::Experimental::HPX>) {
176 return std::make_tuple(size, 1);
177 }
178#endif
179 const int team_size_ = std::bit_floor(static_cast<unsigned short>(std::min(exec.concurrency(), size / 2)));
180 return std::make_tuple(size / team_size_, team_size_);
181 }();
182
183 ASSERT_EQ(team_size * num_teams, size);
184
185 const view_s_t witness(Kokkos::view_alloc(exec, "data - shared space"));
186
187 const context_t esc{exec};
188
189 auto chain = stdexec::schedule(esc.get_scheduler())
191 "hello from pfor",
192 Kokkos::TeamPolicy<TEST_EXECUTION_SPACE>(num_teams, team_size),
193 Tests::Utils::Functors::SumIndices{.data = witness});
194
195 stdexec::sync_wait(std::move(chain));
196
197 ASSERT_EQ(witness(), size / 2 * (size - 1));
198}
199
200template <typename ViewType, Kokkos::ExecutionSpace Exec>
202 const size_t size,
203 const ViewType& witness,
204 const Kokkos::Execution::ExecutionSpaceContext<Exec>& esc) -> stdexec::sender auto {
205 auto chain = stdexec::schedule(esc.get_scheduler())
207 "passing label, execution policy and functor",
208 Kokkos::RangePolicy<Exec>(0, size),
209 Tests::Utils::Functors::SumIndices{.data = witness})
211 Kokkos::RangePolicy<Exec>(0, size), Tests::Utils::Functors::SumIndices{.data = witness});
212
213 if constexpr (std::same_as<Exec, Kokkos::DefaultExecutionSpace>) {
214 return std::move(chain)
216 "passing label, work count and functor", size, Tests::Utils::Functors::SumIndices{.data = witness})
218 } else {
219 return chain;
220 }
221}
222
225 constexpr size_t size = 10;
226
227 const view_s_t witness(Kokkos::view_alloc(exec, "data - shared space"));
228
229 const auto recorded_events = recorder_listener_t::record(
230 [chain = closure_object_creation_overloads(size, witness, context_t{exec})]() mutable {
231 stdexec::sync_wait(std::move(chain));
232 });
233
234 unsigned short int ievent = 0;
235
236 ASSERT_GE(recorded_events.size(), 3);
237
239
240 ASSERT_THAT(
241 recorded_events,
242 ElementAt<variant_t>(ievent++, MATCHER_FOR_BEGIN_PFOR(exec, "passing label, execution policy and functor")));
243 ASSERT_THAT(
244 recorded_events,
245 ElementAt<variant_t>(ievent++, MATCHER_FOR_BEGIN_PFOR(exec, Kokkos::Impl::TypeInfo<functor_t>::name())));
246
247 if constexpr (std::same_as<TEST_EXECUTION_SPACE, Kokkos::DefaultExecutionSpace>) {
248 ASSERT_THAT(
249 recorded_events.at(ievent++), MATCHER_FOR_BEGIN_PFOR(exec, "passing label, work count and functor"));
250 ASSERT_THAT(
251 recorded_events.at(ievent++), MATCHER_FOR_BEGIN_PFOR(exec, Kokkos::Impl::TypeInfo<functor_t>::name()));
252 }
253
254 ASSERT_THAT(recorded_events.at(ievent), MATCHER_FOR_BEGIN_FENCE(exec, dispatch_label(exec, "sync_wait")));
255
256 ASSERT_EQ(witness(), ievent * size / 2 * (size - 1));
257}
258
260TEST_F(ParallelForTest, two_parallel_regions) {
261 constexpr size_t size = 10;
262
263 const view_s_t witness(Kokkos::view_alloc(exec, "data - shared space"));
264
265 const context_t esc{exec};
266
267 auto chain = stdexec::schedule(esc.get_scheduler())
269 std::format("{}: hello from pfor", Kokkos::Impl::TypeInfo<TEST_EXECUTION_SPACE>::name()),
270 Kokkos::RangePolicy<TEST_EXECUTION_SPACE>(0, size),
271 Tests::Utils::Functors::SumIndices{.data = witness})
272 | stdexec::then(
274 .prev = size / 2 * (size - 1), .value = 4, .data = witness.data()})
276 std::format("{}: hello again from pfor", Kokkos::Impl::TypeInfo<TEST_EXECUTION_SPACE>::name()),
277 Kokkos::RangePolicy<TEST_EXECUTION_SPACE>(0, 2 * size),
278 Tests::Utils::Functors::SumIndices{.data = witness});
279
280 ASSERT_THAT(
281 recorder_listener_t::record([chain = std::move(chain)]() mutable { stdexec::sync_wait(std::move(chain)); }),
282 testing::ElementsAre(
283 MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "hello from pfor")),
285 MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "hello again from pfor")),
287
288 ASSERT_EQ(witness(), size / 2 * (size - 1) + 4 + 2 * size * (2 * size - 1) / 2);
289}
290
292TEST_F(ParallelForTest, starts_on_parallel_region) {
293 constexpr size_t size = 10;
294
295 const view_s_t witness(Kokkos::view_alloc(exec, "data - shared space"));
296
297 auto sndr = stdexec::just()
299 std::format("{}: hello from pfor", Kokkos::Impl::TypeInfo<TEST_EXECUTION_SPACE>::name()),
300 Kokkos::RangePolicy<TEST_EXECUTION_SPACE>(0, size),
301 Tests::Utils::Functors::SumIndices{.data = witness});
302
303 const context_t esc{exec};
304 auto starts_on = stdexec::starts_on(esc.get_scheduler(), std::move(sndr));
305
306 ASSERT_THAT(
307 recorder_listener_t::record(
308 [starts_on = std::move(starts_on)]() mutable { stdexec::sync_wait(std::move(starts_on)); }),
309 testing::ElementsAre(
310 MATCHER_FOR_BEGIN_PFOR(exec, dispatch_label(exec, "hello from pfor")),
312
313 ASSERT_EQ(witness(), size / 2 * (size - 1));
314}
315
316} // namespace Tests::ExecutionSpaceImpl
constexpr std::string dispatch_label(const Exec &, Label &&label)
Get the dispatch label from Exec and label.
#define MATCHER_FOR_BEGIN_PFOR(_exec_, _label_)
#define MATCHER_FOR_BEGIN_FENCE(_exec_, _label_)
RecorderListener< EventDiscardMatcher< TEST_EXECUTION_SPACE >, BeginFenceEvent, BeginParallelForEvent > recorder_listener_t
typename recorder_listener_t::event_variant_t variant_t
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.
constexpr parallel_for_t parallel_for
auto ElementAt(const size_t index, ElementMatcher &&matcher)
consteval bool test_sndr_traits()
Definition test_bulk.cpp:38
auto closure_object_creation_overloads(const size_t size, const ViewType &witness, const Kokkos::Execution::ExecutionSpaceContext< Exec > &esc) -> stdexec::sender auto
consteval bool test_sndr_decomposition()
constexpr bool on_device()
Definition kokkos.hpp:22
Execution context using a Kokkos execution space under the hood.
auto get_scheduler() const noexcept -> ExecutionSpaceImpl::Scheduler< Exec >
Scheduler for a Kokkos execution space.
Custom algorithm for the Kokkos::parallel_for construct.
decltype(stdexec::schedule(std::declval< scheduler_t >())) schedule_sender_t
Definition context.hpp:27
Kokkos::Execution::ExecutionSpaceContext< Exec > context_t
Definition context.hpp:25
Load the value at data and check it is equal to prev. Then, add value to it.