Skip to content

Commit bfef316

Browse files
[SYCL][PI][L0] Submit open command batch on event status query (#3612)
This closes and executes a queue's open command batch list when an event that was created in the queue has its execution status queried. This isn't strictly required, but if the execution status is being queried, it seems like a good idea to make sure any existing commands have been submitted. This fixes a situation where if you query over and over on the event's status without ever enqueueing more commands, or doing a wait, the command may remain unsubmitted.
1 parent 2183361 commit bfef316

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

sycl/plugins/level_zero/pi_level_zero.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3942,6 +3942,19 @@ pi_result piEventGetInfo(pi_event Event, pi_event_info ParamName,
39423942
case PI_EVENT_INFO_COMMAND_TYPE:
39433943
return ReturnValue(pi_cast<pi_uint64>(Event->CommandType));
39443944
case PI_EVENT_INFO_COMMAND_EXECUTION_STATUS: {
3945+
// Check to see if the event's Queue has an open command list due to
3946+
// batching. If so, go ahead and close and submit it, because it is
3947+
// possible that this is trying to query some event's status that
3948+
// is part of the batch. This isn't strictly required, but it seems
3949+
// like a reasonable thing to do.
3950+
{
3951+
// Lock automatically releases when this goes out of scope.
3952+
std::lock_guard<std::mutex> lock(Event->Queue->PiQueueMutex);
3953+
3954+
if (auto Res = Event->Queue->executeOpenCommandList())
3955+
return Res;
3956+
}
3957+
39453958
ze_result_t ZeResult;
39463959
ZeResult = ZE_CALL_NOCHECK(zeEventQueryStatus, (Event->ZeEvent));
39473960
if (ZeResult == ZE_RESULT_SUCCESS) {
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// REQUIRES: gpu, level_zero
2+
3+
// RUN: %clangxx -fsycl -fsycl-unnamed-lambda -fsycl-targets=%sycl_triple %s -o %t.out
4+
5+
// Set batching to 4 explicitly
6+
// RUN: env SYCL_PI_LEVEL_ZERO_BATCH_SIZE=4 SYCL_PI_TRACE=2 ZE_DEBUG=1 %GPU_RUN_PLACEHOLDER %t.out 2>&1 | FileCheck %s
7+
8+
// level_zero_batch_test.cpp
9+
//
10+
// This tests the level zero plugin's kernel batching code. It specifically
11+
// tests that the current batch is submitted when an Event execution status
12+
// request is made. This test uses explicit SYCL_PI_LEVEL_ZERO_BATCH_SIZE=4
13+
// to make sure that the batching is submitted when the piEventGetInfo is
14+
// done, rather than some other dynamic batching criteria.
15+
//
16+
// CHECK: ---> piEnqueueKernelLaunch
17+
// CHECK: ZE ---> zeCommandListAppendLaunchKernel
18+
// Shouldn't have closed until we see a piEventGetInfo
19+
// CHECK-NOT: ZE ---> zeCommandListClose
20+
// CHECK-NOT: ZE ---> zeCommandQueueExecuteCommandLists
21+
// CHECK: ---> piEventGetInfo
22+
// Shouldn't see another piGetEventInfo until after closing command list
23+
// CHECK-NOT: ---> piEventGetInfo
24+
// Look for close and Execute after piEventGetInfo
25+
// CHECK: ZE ---> zeCommandListClose
26+
// CHECK: ZE ---> zeCommandQueueExecuteCommandLists
27+
// CHECK: ---> piEventGetInfo
28+
// CHECK-NOT: piEventsWait
29+
// CHECK: ---> piEnqueueKernelLaunch
30+
// CHECK: ZE ---> zeCommandListAppendLaunchKernel
31+
// CHECK: ---> piEventsWait
32+
// Look for close and Execute after piEventsWait
33+
// CHECK: ZE ---> zeCommandListClose
34+
// CHECK: ZE ---> zeCommandQueueExecuteCommandLists
35+
// CHECK: ---> piEventGetInfo
36+
// No close and execute here, should already have happened.
37+
// CHECK-NOT: ZE ---> zeCommandListClose
38+
// CHECK-NOT: ZE ---> zeCommandQueueExecuteCommandLists
39+
// CHECK-NOT: Test Fail
40+
// CHECK: Test Pass
41+
42+
#include <cassert>
43+
#include <chrono>
44+
#include <iostream>
45+
#include <sycl/sycl.hpp>
46+
#include <thread>
47+
48+
int main(void) {
49+
sycl::default_selector ds{};
50+
sycl::queue q{ds};
51+
sycl::vector_class<sycl::event> events(10);
52+
53+
sycl::event ev1 = q.submit([&](sycl::handler &cgh) {
54+
cgh.depends_on(events);
55+
cgh.single_task([=] {});
56+
});
57+
58+
bool ev1_completed = false;
59+
int try_count = 0;
60+
while (true) {
61+
auto ev1_status =
62+
ev1.get_info<sycl::info::event::command_execution_status>();
63+
if (ev1_status == sycl::info::event_command_status::complete) {
64+
std::cout << "Ev1 has completed" << std::endl;
65+
ev1_completed = true;
66+
break;
67+
}
68+
69+
std::cout << "Ev1 has not yet completed: ";
70+
switch (ev1_status) {
71+
case sycl::info::event_command_status::submitted:
72+
std::cout << "submitted";
73+
break;
74+
case sycl::info::event_command_status::running:
75+
std::cout << "running";
76+
break;
77+
default:
78+
std::cout << "unrecognized";
79+
break;
80+
}
81+
std::cout << std::endl;
82+
83+
std::chrono::milliseconds timespan(300);
84+
std::this_thread::sleep_for(timespan);
85+
86+
try_count += 1;
87+
if (try_count > 10) {
88+
ev1.wait();
89+
}
90+
}
91+
assert(ev1_completed);
92+
93+
sycl::event ev2 = q.submit([&](sycl::handler &cgh) {
94+
cgh.depends_on(events);
95+
cgh.single_task([=] {});
96+
});
97+
q.wait();
98+
99+
auto ev2_status = ev2.get_info<sycl::info::event::command_execution_status>();
100+
if (ev2_status != sycl::info::event_command_status::complete) {
101+
std::cout << "Test Fail" << std::endl;
102+
exit(1);
103+
}
104+
105+
std::cout << "Ev2 has completed" << std::endl;
106+
std::cout << "Test Pass" << std::endl;
107+
return 0;
108+
}

0 commit comments

Comments
 (0)