From bf9a906395e40d819f5df1cf7925b7291795b16d Mon Sep 17 00:00:00 2001 From: m moadeli Date: Mon, 18 Dec 2023 09:40:52 +0000 Subject: [PATCH 1/4] Invoke asynchronous handlers linked to the events; the occurrence of this event relies on. --- sycl/source/detail/event_impl.cpp | 5 ++ .../Basic/dependent_event_async_exception.cpp | 74 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 sycl/test-e2e/Basic/dependent_event_async_exception.cpp diff --git a/sycl/source/detail/event_impl.cpp b/sycl/source/detail/event_impl.cpp index 34a2514d5c0f9..3ccbf11f2a693 100644 --- a/sycl/source/detail/event_impl.cpp +++ b/sycl/source/detail/event_impl.cpp @@ -260,6 +260,11 @@ void event_impl::wait_and_throw( std::shared_ptr Self) { wait(Self); + auto WaitList = getWaitList(); + for (const auto &Event : WaitList) { + Event->getSubmittedQueue()->throw_asynchronous(); + } + if (QueueImplPtr SubmittedQueue = MSubmittedQueue.lock()) SubmittedQueue->throw_asynchronous(); } diff --git a/sycl/test-e2e/Basic/dependent_event_async_exception.cpp b/sycl/test-e2e/Basic/dependent_event_async_exception.cpp new file mode 100644 index 0000000000000..c6068b3d1af64 --- /dev/null +++ b/sycl/test-e2e/Basic/dependent_event_async_exception.cpp @@ -0,0 +1,74 @@ +// RUN: %{build} -o %t.out +// RUN: %{run} %t.out + +//==----- dependent_event_async_exception.cpp - Test for event async exceptions +//-----==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include + +struct test_exception { + std::string name; +}; + +class test_exception_handler { +public: + test_exception_handler() + : queue{[this](sycl::exception_list el) { capture(std::move(el)); }} {} + sycl::queue &get_queue() { return queue; } + + bool has(const std::string &name) const { + return captured_exceptions.count(name) != 0; + } + + size_t count() const { return captured_exceptions.size(); } + + void clear() { captured_exceptions.clear(); } + +private: + std::unordered_set captured_exceptions; + sycl::queue queue; + + void capture(sycl::exception_list el) { + for (auto &e : el) { + try { + std::rethrow_exception(e); + } catch (test_exception &te) { + captured_exceptions.insert(te.name); + } + } + } +}; + +static sycl::event +make_throwing_host_event(sycl::queue &queue, std::string name, + const std::vector &dependencies = {}) { + return queue.submit([name, &dependencies](sycl::handler &cgh) { + for (auto &dep : dependencies) { + cgh.depends_on(dep); + } + cgh.host_task([name](auto) { throw test_exception{name}; }); + }); +} + +int main() { + test_exception_handler teh1; + test_exception_handler teh2; + + auto e1 = make_throwing_host_event(teh1.get_queue(), "some-error"); + auto e2 = make_throwing_host_event(teh2.get_queue(), "another-error", {e1}); + + e2.wait_and_throw(); + + assert(teh2.count() == 1); + assert(teh2.has("another-error")); + + assert(teh1.count() == 1); + assert(teh1.has("some-error")); +} From 89a25c03a3560b45d0ed2f63391d8966e49f20f0 Mon Sep 17 00:00:00 2001 From: m moadeli Date: Wed, 3 Jan 2024 11:22:46 +0000 Subject: [PATCH 2/4] Improve test to cover cases where the dependence comes from accessor requirements between two queues. --- .../Basic/dependent_event_async_exception.cpp | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/sycl/test-e2e/Basic/dependent_event_async_exception.cpp b/sycl/test-e2e/Basic/dependent_event_async_exception.cpp index c6068b3d1af64..683229af67b52 100644 --- a/sycl/test-e2e/Basic/dependent_event_async_exception.cpp +++ b/sycl/test-e2e/Basic/dependent_event_async_exception.cpp @@ -58,17 +58,52 @@ make_throwing_host_event(sycl::queue &queue, std::string name, } int main() { - test_exception_handler teh1; - test_exception_handler teh2; + { + test_exception_handler teh1; + test_exception_handler teh2; - auto e1 = make_throwing_host_event(teh1.get_queue(), "some-error"); - auto e2 = make_throwing_host_event(teh2.get_queue(), "another-error", {e1}); + auto e1 = make_throwing_host_event(teh1.get_queue(), "some-error"); + auto e2 = make_throwing_host_event(teh2.get_queue(), "another-error", {e1}); - e2.wait_and_throw(); + e2.wait_and_throw(); - assert(teh2.count() == 1); - assert(teh2.has("another-error")); + assert(teh2.count() == 1); + assert(teh2.has("another-error")); - assert(teh1.count() == 1); - assert(teh1.has("some-error")); + assert(teh1.count() == 1); + assert(teh1.has("some-error")); + } + { + int data = 0; + { + sycl::buffer Buf(&data, sycl::range<1>(1)); + test_exception_handler teh1; + test_exception_handler teh2; + + auto e1 = teh1.get_queue().submit([&](sycl::handler &cgh) { + auto B = Buf.template get_access(cgh); + cgh.host_task([=]() { + B[0] = 10; + throw test_exception{"some-error"}; + }); + }); + + auto e2 = teh2.get_queue().submit([&](sycl::handler &cgh) { + auto B = Buf.template get_access(cgh); + cgh.host_task([=]() { + B[0] *= 10; + throw test_exception{"another-error"}; + }); + }); + + e2.wait_and_throw(); + + assert(data == 100); + assert(teh2.count() == 1); + assert(teh2.has("another-error")); + + assert(teh1.count() == 1); + assert(teh1.has("some-error")); + } + } } From fbeb80c7fc040ae84915a8b72b3bb12a1b63f075 Mon Sep 17 00:00:00 2001 From: m moadeli Date: Wed, 3 Jan 2024 13:55:17 +0000 Subject: [PATCH 3/4] Use `sycl::read_write_host_task` for accessor creation. --- sycl/test-e2e/Basic/dependent_event_async_exception.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sycl/test-e2e/Basic/dependent_event_async_exception.cpp b/sycl/test-e2e/Basic/dependent_event_async_exception.cpp index 683229af67b52..89512e768cb86 100644 --- a/sycl/test-e2e/Basic/dependent_event_async_exception.cpp +++ b/sycl/test-e2e/Basic/dependent_event_async_exception.cpp @@ -81,7 +81,7 @@ int main() { test_exception_handler teh2; auto e1 = teh1.get_queue().submit([&](sycl::handler &cgh) { - auto B = Buf.template get_access(cgh); + auto B = sycl::accessor(Buf, cgh, sycl::read_write_host_task); cgh.host_task([=]() { B[0] = 10; throw test_exception{"some-error"}; @@ -89,7 +89,7 @@ int main() { }); auto e2 = teh2.get_queue().submit([&](sycl::handler &cgh) { - auto B = Buf.template get_access(cgh); + auto B = sycl::accessor(Buf, cgh, sycl::read_write_host_task); cgh.host_task([=]() { B[0] *= 10; throw test_exception{"another-error"}; From 81789cbb4239cbe41a250f72819a2295408f66df Mon Sep 17 00:00:00 2001 From: M Moadeli Date: Fri, 29 Mar 2024 16:18:53 +0000 Subject: [PATCH 4/4] Add a test case for the situation where there is no dependency chain between the two kernels but they are enqueued to the same queue. --- .../Basic/dependent_event_async_exception.cpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/sycl/test-e2e/Basic/dependent_event_async_exception.cpp b/sycl/test-e2e/Basic/dependent_event_async_exception.cpp index 89512e768cb86..8daaccfb1bb77 100644 --- a/sycl/test-e2e/Basic/dependent_event_async_exception.cpp +++ b/sycl/test-e2e/Basic/dependent_event_async_exception.cpp @@ -106,4 +106,36 @@ int main() { assert(teh1.has("some-error")); } } + { + int data1 = 0, data2 = 0; + { + sycl::buffer Buf1(&data1, sycl::range<1>(1)); + sycl::buffer Buf2(&data2, sycl::range<1>(1)); + test_exception_handler teh; + + auto e1 = teh.get_queue().submit([&](sycl::handler &cgh) { + auto B = sycl::accessor(Buf1, cgh, sycl::read_write_host_task); + cgh.host_task([=]() { + B[0] = 10; + throw test_exception{"some-error"}; + }); + }); + + auto e2 = teh.get_queue().submit([&](sycl::handler &cgh) { + auto B = sycl::accessor(Buf2, cgh, sycl::read_write_host_task); + cgh.host_task([=]() { + B[0] = 20; + throw test_exception{"another-error"}; + }); + }); + + e2.wait_and_throw(); + + assert(data1 == 10); + assert(data2 == 20); + assert(teh.count() == 2); + assert(teh.has("another-error")); + assert(teh.has("some-error")); + } + } }