1#include "gtest/gtest.h"
26#if !defined(KOKKOS_EXECUTION_ENABLE_EVENT_DISPATCH)
27# error "This is not supported."
32using namespace Kokkos::utils::callbacks;
48template <Kokkos::ExecutionSpace Exec>
57template <Kokkos::ExecutionSpace Exec>
59#if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_HIP) || defined(KOKKOS_ENABLE_SYCL)
60 if constexpr (std::same_as<Exec, Kokkos::DefaultExecutionSpace>) {
65#if defined(KOKKOS_ENABLE_HPX)
66 if constexpr (std::same_as<Exec, Kokkos::Experimental::HPX>) {
79TEST(RecordEvent, description) {
82 std::ostringstream oss;
85 ASSERT_EQ(oss.str(),
"RecordEvent: {dev_id = 42, event_id = 1337}");
89TEST(WaitEvent, description) {
92 std::ostringstream oss;
95 ASSERT_EQ(oss.str(),
"WaitEvent: {dev_id = 0, event_id = 1337}");
100 const auto recorded_events = recorder_listener_t::record([
this]() {
106 ASSERT_THAT(recorded_events, testing::SizeIs(2));
113 const auto recorded_events = recorder_listener_t::record([
this]() {
118 exec.fence(
"some-label");
121 ASSERT_THAT(recorded_events, testing::SizeIs(2));
128 const auto recorded_events = recorder_listener_t::record([
this]() {
136 ASSERT_THAT(recorded_events, ::testing::SizeIs(4));
147 const auto recorded_events = recorder_listener_t::record([
this]() {
153 exec.fence(
"some-label");
156 ASSERT_THAT(recorded_events, ::testing::SizeIs(3));
163 std::get<Kokkos::Execution::Impl::RecordEvent>(recorded_events.at(0)).event_id,
164 std::get<Kokkos::Execution::Impl::RecordEvent>(recorded_events.at(1)).event_id);
171 const TEST_EXECUTION_SPACE default_exec{};
173 const auto recorded_events = recorder_listener_t::record([&default_exec]() {
180 ASSERT_THAT(recorded_events, ::testing::SizeIs(2));
187 const auto [exec_A, exec_B] = Kokkos::Experimental::partition_space(
exec, 1, 1);
189 const auto recorded_events = recorder_listener_t::record([&exec_A, &exec_B]() {
198 ASSERT_THAT(recorded_events, ::testing::SizeIs(3));
205 const auto [exec_A, exec_B] = Kokkos::Experimental::partition_space(
exec, 1, 1);
207 const auto recorded_events = recorder_listener_t::record([&exec_A, &exec_B]() {
215 ASSERT_THAT(recorded_events, ::testing::SizeIs(6));
226 if constexpr (std::same_as<TEST_EXECUTION_SPACE, Kokkos::DefaultHostExecutionSpace>) {
227 GTEST_SKIP() <<
"The default host execution space is the same type as the test execution space.";
230 const Kokkos::DefaultHostExecutionSpace exec_h;
232 const auto recorded_events = recorder_listener_t::record([
this, &exec_h]() {
238 ASSERT_THAT(recorded_events, ::testing::SizeIs(2));
250 constexpr size_t size = 128;
252 const auto [exec_A, exec_B, exec_C] = Kokkos::Experimental::partition_space(
exec, 1, 1, 1);
254 const Kokkos::View<int, TEST_EXECUTION_SPACE> data(Kokkos::view_alloc(exec_A,
"data"));
255 const auto data_h = Kokkos::create_mirror_view(Kokkos::WithoutInitializing, data);
257 std::optional<Kokkos::Execution::Impl::Event<TEST_EXECUTION_SPACE>> event_A;
259 stdexec::run_loop loop;
260 std::thread consumer([&] { loop.run(); });
262 Kokkos::parallel_for(
263 Kokkos::RangePolicy(exec_A, 0, size), KOKKOS_LAMBDA(
const auto idx) { Kokkos::atomic_add(&data(), idx); });
267 bool upon_error =
false;
269 auto opstate = stdexec::connect(
270 stdexec::schedule(loop.get_scheduler()) | stdexec::then([&] {
273 Kokkos::parallel_for(
274 Kokkos::RangePolicy(exec_B, 0, size),
275 KOKKOS_LAMBDA(const auto idx) { Kokkos::atomic_add(&data(), idx); });
279 Kokkos::parallel_for(
280 Kokkos::RangePolicy(exec_C, 0, 1),
281 KOKKOS_LAMBDA(
const auto) { Kokkos::atomic_compare_exchange(&data(), size * (size - 1), 1); });
282 Kokkos::deep_copy(exec_C, data_h, data);
283 exec_C.fence(
"wait for the deep copy to complete");
285 }) | stdexec::upon_error([&](
const auto& eptr) {
288 std::rethrow_exception(eptr);
289 }
catch (
const std::exception& exc) {
290 Kokkos::printf(
"%s\n", exc.what());
294 Tests::Utils::SinkReceiver{});
300 ASSERT_FALSE(event_A.has_value());
303#if defined(KOKKOS_ENABLE_THREADS)
304 if constexpr (std::same_as<TEST_EXECUTION_SPACE, Kokkos::Threads>) {
305 ASSERT_EQ(data_h(), size / 2 * (size - 1));
306 ASSERT_TRUE(upon_error);
310 ASSERT_EQ(data_h(), 1);
311 ASSERT_FALSE(upon_error);
#define MATCHER_FOR_WAIT_EVENT(_record_event_variant_)
#define MATCHER_FOR_WAIT_EXEC_EVENT(_exec_, _record_event_variant_)
#define MATCHER_FOR_RECORD_EVENT(_exec_)
#define MATCHER_FOR_BEGIN_FENCE(_exec_, _label_)
Fixture that enables callbacks with Kokkos::utils::tests::scoped::callbacks::Manager.
RecorderListener< EventDiscardMatcher< TEST_EXECUTION_SPACE >, BeginFenceEvent, Kokkos::Execution::Impl::RecordEvent, Kokkos::Execution::Impl::WaitEvent > recorder_listener_t
Constrain an EventType type to be a valid event type for Exec execution space type.
Determine if the Kokkos backend can enqueue a wait for an event into an execution space instance.
void record(Event< Exec > &event, const Exec &exec)
Record event on exec.
void wait(const Event< Exec > &... events)
Wait for events to complete.
consteval bool test_models_event()
consteval bool test_has_exec_wait_event()
Matcher to filter out events that are just noise for tests.
An event that can be recorded on an execution space instance.
Event to be sent to Kokkos::utils::callbacks::dispatch when calling record.
Event to be sent to Kokkos::utils::callbacks::dispatch when calling wait.