diff --git a/sycl/plugins/level_zero/pi_level_zero.cpp b/sycl/plugins/level_zero/pi_level_zero.cpp index 183f1285057e6..b5434ff2f0f4a 100644 --- a/sycl/plugins/level_zero/pi_level_zero.cpp +++ b/sycl/plugins/level_zero/pi_level_zero.cpp @@ -450,6 +450,15 @@ createEventAndAssociateQueue(pi_queue Queue, pi_event *Event, // In piEventRelease, the reference counter of the Queue is decremented // to release it. piQueueRetainNoLock(Queue); + + // SYCL RT does not track completion of the events, so it could + // release a PI event as soon as that's not being waited in the app. + // But we have to ensure that the event is not destroyed before + // it is really signalled, so retain it explicitly here and + // release in cleanupAfterEvent. + // + PI_CALL(piEventRetain(*Event)); + return PI_SUCCESS; } @@ -3840,6 +3849,15 @@ static pi_result cleanupAfterEvent(pi_event Event) { PI_CALL(piKernelRelease(pi_cast(Event->CommandData))); Event->CommandData = nullptr; } + + if (!Event->CleanedUp) { + Event->CleanedUp = true; + // Release this event since we explicitly retained it on creation. + // NOTE: that this needs to be done only once for an event so + // this is guarded with the CleanedUp flag. + // + PI_CALL(piEventRelease(Event)); + } } // Make a list of all the dependent events that must have signalled @@ -3863,6 +3881,7 @@ static pi_result cleanupAfterEvent(pi_event Event) { EventsToBeReleased); PI_CALL(piEventRelease(DepEvent)); } + return PI_SUCCESS; } @@ -3924,6 +3943,9 @@ pi_result piEventRetain(pi_event Event) { pi_result piEventRelease(pi_event Event) { PI_ASSERT(Event, PI_INVALID_EVENT); + if (!Event->RefCount) { + die("piEventRelease: called on a destroyed event"); + } if (--(Event->RefCount) == 0) { cleanupAfterEvent(Event); diff --git a/sycl/plugins/level_zero/pi_level_zero.hpp b/sycl/plugins/level_zero/pi_level_zero.hpp index d92b9d6a26020..724cb7b599022 100644 --- a/sycl/plugins/level_zero/pi_level_zero.hpp +++ b/sycl/plugins/level_zero/pi_level_zero.hpp @@ -584,6 +584,12 @@ struct _pi_event : _pi_object { // enqueued, and must then be released when this event has signalled. // This list must be destroyed once the event has signalled. _pi_ze_event_list_t WaitList; + + // Tracks if the needed cleanupAfterEvent was already performed for + // a completed event. This allows to control that some cleanup + // actions are performed only once. + // + bool CleanedUp = {false}; }; struct _pi_program : _pi_object {