diff --git a/opencl/source/api/api.cpp b/opencl/source/api/api.cpp index ec074c09af..68fc0a8412 100644 --- a/opencl/source/api/api.cpp +++ b/opencl/source/api/api.cpp @@ -2131,6 +2131,7 @@ cl_int CL_API_CALL clReleaseEvent(cl_event event) { DBG_LOG_INPUTS("cl_event", event, "Event", pEvent); if (pEvent) { + pEvent->handleCompletionBeforeDestruction(); pEvent->release(); TRACING_EXIT(clReleaseEvent, &retVal); return retVal; diff --git a/opencl/source/event/event.cpp b/opencl/source/event/event.cpp index 142a62c6a1..83adc33c3e 100644 --- a/opencl/source/event/event.cpp +++ b/opencl/source/event/event.cpp @@ -144,6 +144,15 @@ Event::~Event() { unblockEventsBlockedByThis(executionStatus); } +void Event::handleCompletionBeforeDestruction() { + if (!cmdQueue || isCompleted() || peekExecutionStatus() < 0 || (getRefInternalCount() > 1)) { + return; + } + + cmdQueue->flush(); + ctx->getAsyncEventsHandler().registerEvent(this); +} + cl_int Event::getEventProfilingInfo(cl_profiling_info paramName, size_t paramValueSize, void *paramValue, diff --git a/opencl/source/event/event.h b/opencl/source/event/event.h index bdc441471d..45787461ce 100644 --- a/opencl/source/event/event.h +++ b/opencl/source/event/event.h @@ -301,6 +301,8 @@ class Event : public BaseObject<_cl_event>, public IDNode { this->cmdType = cmdType; } + void handleCompletionBeforeDestruction(); + std::vector &getParentEvents() { return this->parentEvents; } virtual bool isExternallySynchronized() const { diff --git a/opencl/test/unit_test/api/cl_release_event_tests.inl b/opencl/test/unit_test/api/cl_release_event_tests.inl index 509496f048..0cf2d1265f 100644 --- a/opencl/test/unit_test/api/cl_release_event_tests.inl +++ b/opencl/test/unit_test/api/cl_release_event_tests.inl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -9,6 +9,7 @@ #include "opencl/source/context/context.h" #include "opencl/source/event/event.h" +#include "opencl/test/unit_test/mocks/mock_event.h" #include "cl_api_tests.h" @@ -35,7 +36,7 @@ TEST_F(clEventTests, GivenNullEventWhenReleasingEventThenClInvalidEventErrorIsRe } TEST_F(clEventTests, GivenValidEventWhenReleasingEventThenSuccessIsReturned) { - auto *pEvent = new Event(nullptr, 0, 0, 0); + auto *pEvent = new MockEvent(pContext, pCommandQueue, CL_COMMAND_NDRANGE_KERNEL, 0, 0); ASSERT_NE(nullptr, pEvent); cl_event event = (cl_event)pEvent; @@ -45,7 +46,7 @@ TEST_F(clEventTests, GivenValidEventWhenReleasingEventThenSuccessIsReturned) { } TEST_F(clEventTests, GivenValidEventWhenRetainedAndReleasedThenReferenceCountIsUpdated) { - auto *pEvent = new Event(nullptr, 0, 0, 0); + auto *pEvent = new MockEvent(pContext, pCommandQueue, CL_COMMAND_NDRANGE_KERNEL, 0, 0); ASSERT_NE(nullptr, pEvent); cl_event event = (cl_event)pEvent; @@ -61,7 +62,7 @@ TEST_F(clEventTests, GivenValidEventWhenRetainedAndReleasedThenReferenceCountIsU } TEST_F(clEventTests, GivenValidEventWhenRetainedAndReleasedTwiceThenClSuccessIsReturned) { - auto *pEvent = new Event(nullptr, 0, 0, 0); + auto *pEvent = new MockEvent(pContext, pCommandQueue, CL_COMMAND_NDRANGE_KERNEL, 0, 0); ASSERT_NE(nullptr, pEvent); cl_event event = (cl_event)pEvent; diff --git a/opencl/test/unit_test/command_queue/command_queue_hw_1_tests.cpp b/opencl/test/unit_test/command_queue/command_queue_hw_1_tests.cpp index efade1211d..80d3902680 100644 --- a/opencl/test/unit_test/command_queue/command_queue_hw_1_tests.cpp +++ b/opencl/test/unit_test/command_queue/command_queue_hw_1_tests.cpp @@ -861,7 +861,12 @@ HWTEST_F(CommandQueueHwTest, givenCommandQueueThatIsBlockedAndUsesCpuCopyWhenEve EventsRequest eventsRequest(0, nullptr, &returnEvent); cmdQHw->cpuDataTransferHandler(transferProperties, eventsRequest, retVal); EXPECT_EQ(CL_SUCCESS, retVal); - EXPECT_EQ(CompletionStamp::notReady, castToObject(returnEvent)->peekTaskCount()); + + auto neoEvent = castToObject(returnEvent); + + EXPECT_EQ(CompletionStamp::notReady, neoEvent->peekTaskCount()); + + neoEvent->updateTaskCount(1, 1); clReleaseEvent(returnEvent); } diff --git a/opencl/test/unit_test/event/async_events_handler_tests.cpp b/opencl/test/unit_test/event/async_events_handler_tests.cpp index 72e2a5b077..9251dce252 100644 --- a/opencl/test/unit_test/event/async_events_handler_tests.cpp +++ b/opencl/test/unit_test/event/async_events_handler_tests.cpp @@ -18,6 +18,7 @@ #include "opencl/test/unit_test/mocks/mock_async_event_handler.h" #include "opencl/test/unit_test/mocks/mock_command_queue.h" #include "opencl/test/unit_test/mocks/mock_context.h" +#include "opencl/test/unit_test/mocks/mock_event.h" using namespace NEO; using namespace ::testing; @@ -54,6 +55,10 @@ class AsyncEventsHandlerTests : public ::testing::Test { ++(*(int *)data); } + void setTagValue(uint32_t newValue) { + *(commandQueue->getGpgpuCommandStreamReceiver().getTagAddress()) = newValue; + } + void SetUp() override { dbgRestore.reset(new DebugManagerStateRestore()); DebugManager.flags.EnableAsyncEventsHandler.set(false); @@ -62,7 +67,7 @@ class AsyncEventsHandlerTests : public ::testing::Test { commandQueue = make_releaseable(context.get(), context->getDevice(0), nullptr, false); - *(commandQueue->getGpgpuCommandStreamReceiver().getTagAddress()) = 0; + setTagValue(0); event1 = make_releaseable(context.get(), commandQueue.get(), CL_COMMAND_BARRIER, CompletionStamp::notReady, CompletionStamp::notReady); event2 = make_releaseable(context.get(), commandQueue.get(), CL_COMMAND_BARRIER, CompletionStamp::notReady, CompletionStamp::notReady); @@ -311,6 +316,71 @@ TEST_F(AsyncEventsHandlerTests, givenUserEventWhenCallbackIsAddedThenDontRegiste userEvent.decRefInternal(); } +TEST_F(AsyncEventsHandlerTests, givenNotReadyEventWhenReleasingThenRegister) { + DebugManager.flags.EnableAsyncEventsHandler.set(true); + auto myHandler = new MockHandler(false); + context->getAsyncEventsHandlerUniquePtr().reset(myHandler); + + constexpr uint32_t eventTaskCount = 1; + setTagValue(0); + + auto mockEvent = new MockEvent(context.get(), commandQueue.get(), CL_COMMAND_NDRANGE_KERNEL, 0, eventTaskCount); + + EXPECT_TRUE(myHandler->peekIsRegisterListEmpty()); + clReleaseEvent(mockEvent); + EXPECT_FALSE(myHandler->peekIsRegisterListEmpty()); + + setTagValue(eventTaskCount); + myHandler->process(); + EXPECT_TRUE(myHandler->peekIsRegisterListEmpty()); + EXPECT_TRUE(myHandler->peekIsListEmpty()); +} + +TEST_F(AsyncEventsHandlerTests, givenTerminatedEventWhenReleasingThenDontRegister) { + DebugManager.flags.EnableAsyncEventsHandler.set(true); + auto myHandler = new MockHandler(false); + context->getAsyncEventsHandlerUniquePtr().reset(myHandler); + + constexpr uint32_t eventTaskCount = 1; + setTagValue(0); + + auto mockEvent = new MockEvent(context.get(), commandQueue.get(), CL_COMMAND_NDRANGE_KERNEL, 0, eventTaskCount); + mockEvent->setStatus(-1); + + clReleaseEvent(mockEvent); + EXPECT_TRUE(myHandler->peekIsRegisterListEmpty()); +} + +TEST_F(AsyncEventsHandlerTests, givenNotReadyEventWithRefCountWhenReleasingThenDontRegister) { + DebugManager.flags.EnableAsyncEventsHandler.set(true); + auto myHandler = new MockHandler(false); + context->getAsyncEventsHandlerUniquePtr().reset(myHandler); + + constexpr uint32_t eventTaskCount = 1; + setTagValue(0); + + auto mockEvent = new MockEvent(context.get(), commandQueue.get(), CL_COMMAND_NDRANGE_KERNEL, 0, eventTaskCount); + mockEvent->incRefInternal(); + + clReleaseEvent(mockEvent); + EXPECT_TRUE(myHandler->peekIsRegisterListEmpty()); + + setTagValue(eventTaskCount); + mockEvent->decRefInternal(); +} + +TEST_F(AsyncEventsHandlerTests, givenEventWithoutCommandQueueWhenReleasingThenDontRegister) { + DebugManager.flags.EnableAsyncEventsHandler.set(true); + auto myHandler = new MockHandler(false); + context->getAsyncEventsHandlerUniquePtr().reset(myHandler); + + auto userEvent = new UserEvent(context.get()); + userEvent->setStatus(CL_QUEUED); + + clReleaseEvent(userEvent); + EXPECT_TRUE(myHandler->peekIsRegisterListEmpty()); +} + TEST_F(AsyncEventsHandlerTests, givenRegistredEventsWhenProcessIsCalledThenReturnCandidateWithLowestTaskCount) { int event1Counter(0), event2Counter(0), event3Counter(0);