@@ -3660,6 +3660,83 @@ pi_result piQueueGetInfo(pi_queue Queue, pi_queue_info ParamName,
3660
3660
case PI_QUEUE_INFO_DEVICE_DEFAULT:
3661
3661
die("PI_QUEUE_INFO_DEVICE_DEFAULT in piQueueGetInfo not implemented\n");
3662
3662
break;
3663
+ case PI_EXT_ONEAPI_QUEUE_INFO_EMPTY: {
3664
+ // We can exit early if we have in-order queue.
3665
+ if (Queue->isInOrderQueue()) {
3666
+ if (!Queue->LastCommandEvent)
3667
+ return ReturnValue(pi_bool{true});
3668
+
3669
+ // We can check status of the event only if it isn't discarded otherwise
3670
+ // it may be reset (because we are free to reuse such events) and
3671
+ // zeEventQueryStatus will hang.
3672
+ // TODO: use more robust way to check that ZeEvent is not owned by
3673
+ // LastCommandEvent.
3674
+ if (!Queue->LastCommandEvent->IsDiscarded) {
3675
+ ze_result_t ZeResult = ZE_CALL_NOCHECK(
3676
+ zeEventQueryStatus, (Queue->LastCommandEvent->ZeEvent));
3677
+ if (ZeResult == ZE_RESULT_NOT_READY) {
3678
+ return ReturnValue(pi_bool{false});
3679
+ } else if (ZeResult != ZE_RESULT_SUCCESS) {
3680
+ return mapError(ZeResult);
3681
+ }
3682
+ return ReturnValue(pi_bool{true});
3683
+ }
3684
+ // For immediate command lists we have to check status of the event
3685
+ // because immediate command lists are not associated with level zero
3686
+ // queue. Conservatively return false in this case because last event is
3687
+ // discarded and we can't check its status.
3688
+ if (Queue->Device->useImmediateCommandLists())
3689
+ return ReturnValue(pi_bool{false});
3690
+ }
3691
+
3692
+ // If we have any open command list which is not empty then return false
3693
+ // because it means that there are commands which are not even submitted for
3694
+ // execution yet.
3695
+ using IsCopy = bool;
3696
+ if (Queue->hasOpenCommandList(IsCopy{true}) ||
3697
+ Queue->hasOpenCommandList(IsCopy{false}))
3698
+ return ReturnValue(pi_bool{false});
3699
+
3700
+ for (const auto &QueueGroup :
3701
+ {Queue->ComputeQueueGroup, Queue->CopyQueueGroup}) {
3702
+ if (Queue->Device->useImmediateCommandLists()) {
3703
+ // Immediate command lists are not associated with any Level Zero queue,
3704
+ // that's why we have to check status of events in each immediate
3705
+ // command list. Start checking from the end and exit early if some
3706
+ // event is not completed.
3707
+ for (const auto &ImmCmdList : QueueGroup.ImmCmdLists) {
3708
+ if (ImmCmdList == Queue->CommandListMap.end())
3709
+ continue;
3710
+
3711
+ auto EventList = ImmCmdList->second.EventList;
3712
+ for (auto It = EventList.crbegin(); It != EventList.crend(); It++) {
3713
+ ze_result_t ZeResult =
3714
+ ZE_CALL_NOCHECK(zeEventQueryStatus, ((*It)->ZeEvent));
3715
+ if (ZeResult == ZE_RESULT_NOT_READY) {
3716
+ return ReturnValue(pi_bool{false});
3717
+ } else if (ZeResult != ZE_RESULT_SUCCESS) {
3718
+ return mapError(ZeResult);
3719
+ }
3720
+ }
3721
+ }
3722
+ } else {
3723
+ for (const auto &ZeQueue : QueueGroup.ZeQueues) {
3724
+ if (!ZeQueue)
3725
+ continue;
3726
+ // Provide 0 as the timeout parameter to immediately get the status of
3727
+ // the Level Zero queue.
3728
+ ze_result_t ZeResult = ZE_CALL_NOCHECK(zeCommandQueueSynchronize,
3729
+ (ZeQueue, /* timeout */ 0));
3730
+ if (ZeResult == ZE_RESULT_NOT_READY) {
3731
+ return ReturnValue(pi_bool{false});
3732
+ } else if (ZeResult != ZE_RESULT_SUCCESS) {
3733
+ return mapError(ZeResult);
3734
+ }
3735
+ }
3736
+ }
3737
+ }
3738
+ return ReturnValue(pi_bool{true});
3739
+ }
3663
3740
default:
3664
3741
zePrint("Unsupported ParamName in piQueueGetInfo: ParamName=%d(0x%x)\n",
3665
3742
ParamName, ParamName);
@@ -6727,6 +6804,8 @@ pi_result _pi_queue::synchronize() {
6727
6804
ZE_CALL(zeHostSynchronize, (ZeQueue));
6728
6805
}
6729
6806
6807
+ LastCommandEvent = nullptr;
6808
+
6730
6809
// With the entire queue synchronized, the active barriers must be done so we
6731
6810
// can remove them.
6732
6811
for (pi_event &BarrierEvent : ActiveBarriers)
0 commit comments