Skip to content

Commit 3467780

Browse files
committed
[UR] Fix correct usage of In Order sync list given counting events
- Fixes a race condition when the wait events are counting events when executing the context's synchronous immediate command list. - If a counting event is used in a non immediate command list, then an error will be returned. - Two list types are created such that the in order sync list is only used when needed. In the future in order may be used everywhere, but currently the in order list will only be used where needed. Signed-off-by: Neil R. Spruit <[email protected]>
1 parent 6e5d0e6 commit 3467780

File tree

6 files changed

+63
-11
lines changed

6 files changed

+63
-11
lines changed

source/adapters/level_zero/context.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,19 @@ ur_result_t ur_context_handle_t_::initialize() {
322322
ZE2UR_CALL(
323323
zeCommandListCreateImmediate,
324324
(ZeContext, Device->ZeDevice, &ZeCommandQueueDesc, &ZeCommandListInit));
325+
326+
if (Device->useDriverInOrderLists() &&
327+
Device->useDriverCounterBasedEvents()) {
328+
logger::debug(
329+
"L0 Synchronous Immediate Command List needed with In Order property.");
330+
ZeStruct<ze_command_queue_desc_t> ZeCommandQueueDescInOrder;
331+
ZeCommandQueueDescInOrder = ZeCommandQueueDesc;
332+
ZeCommandQueueDescInOrder.flags |= ZE_COMMAND_LIST_FLAG_IN_ORDER;
333+
ZE2UR_CALL(zeCommandListCreateImmediate,
334+
(ZeContext, Device->ZeDevice, &ZeCommandQueueDescInOrder,
335+
&ZeCommandListInitInOrder));
336+
this->InOrderListInitEnabled = true;
337+
}
325338
return UR_RESULT_SUCCESS;
326339
}
327340

@@ -434,6 +447,15 @@ ur_result_t ur_context_handle_t_::finalize() {
434447
if (ZeResult && ZeResult != ZE_RESULT_ERROR_UNINITIALIZED)
435448
return ze2urResult(ZeResult);
436449

450+
if (this->InOrderListInitEnabled) {
451+
// Destroy the in order command list used for initializations
452+
auto ZeResultInOrder =
453+
ZE_CALL_NOCHECK(zeCommandListDestroy, (ZeCommandListInitInOrder));
454+
// Gracefully handle the case that L0 was already unloaded.
455+
if (ZeResultInOrder && ZeResultInOrder != ZE_RESULT_ERROR_UNINITIALIZED)
456+
return ze2urResult(ZeResultInOrder);
457+
}
458+
437459
std::scoped_lock<ur_mutex> Lock(ZeCommandListCacheMutex);
438460
for (auto &List : ZeComputeCommandListCache) {
439461
for (auto &Item : List.second) {

source/adapters/level_zero/context.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ struct ur_context_handle_t_ : _ur_object {
8585
// support of the multiple devices per context will be added.
8686
ze_command_list_handle_t ZeCommandListInit{};
8787

88+
// Immediate Level Zero command list for the device that has the property of
89+
// in-order execution. This command list is used for memory copy operations.
90+
// Due to different event types supported, one needs to use separate command
91+
// list types given Counting Events are being used.
92+
ze_command_list_handle_t ZeCommandListInitInOrder{};
93+
94+
// Indicates if the immediate command list with in-order property is enabled.
95+
bool InOrderListInitEnabled = false;
96+
8897
// Mutex for the immediate command list. Per the Level Zero spec memory copy
8998
// operations submitted to an immediate command list are not allowed to be
9099
// called from simultaneous threads.

source/adapters/level_zero/device.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,20 @@ bool ur_device_handle_t_::useDriverInOrderLists() {
15281528
return UseDriverInOrderLists;
15291529
}
15301530

1531+
bool ur_device_handle_t_::useDriverCounterBasedEvents() {
1532+
// Use counter-based events implementation from L0 driver.
1533+
1534+
static const bool DriverCounterBasedEventsEnabled = [] {
1535+
const char *UrRet = std::getenv("UR_L0_USE_DRIVER_COUNTER_BASED_EVENTS");
1536+
if (!UrRet) {
1537+
return true;
1538+
}
1539+
return std::atoi(UrRet) != 0;
1540+
}();
1541+
1542+
return DriverCounterBasedEventsEnabled;
1543+
}
1544+
15311545
ur_result_t ur_device_handle_t_::initialize(int SubSubDeviceOrdinal,
15321546
int SubSubDeviceIndex) {
15331547
// Maintain various device properties cache.

source/adapters/level_zero/device.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ struct ur_device_handle_t_ : _ur_object {
159159
// Whether Adapter uses driver's implementation of in-order lists or not
160160
bool useDriverInOrderLists();
161161

162+
// Whether Adapter uses driver's implementation of counter-based events or not
163+
bool useDriverCounterBasedEvents();
164+
162165
// Returns whether immediate command lists are used on this device.
163166
ImmCmdlistMode ImmCommandListUsed{};
164167

source/adapters/level_zero/memory.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,7 +2165,13 @@ ur_result_t _ur_buffer::getZeHandle(char *&ZeHandle, access_mode_t AccessMode,
21652165
waitlist.ZeEventList = nullptr;
21662166
waitlist.Length = 0;
21672167
uint32_t EventListIndex = 0;
2168+
bool InOrderListRequired = false;
21682169
for (unsigned i = 0; i < numWaitEvents; ++i) {
2170+
// If any of the wait events are of the type "counter" then we need to
2171+
// use an in order list otherwise the event is invalid in this list.
2172+
if (phWaitEvents[i]->CounterBasedEventsEnabled) {
2173+
InOrderListRequired = true;
2174+
}
21692175
if (phWaitEvents[i]->HostVisibleEvent) {
21702176
ZE2UR_CALL(zeEventHostSynchronize,
21712177
(phWaitEvents[i]->ZeEvent, UINT64_MAX));
@@ -2181,9 +2187,14 @@ ur_result_t _ur_buffer::getZeHandle(char *&ZeHandle, access_mode_t AccessMode,
21812187
}
21822188
}
21832189
if (waitlist.Length > 0) {
2184-
ZE2UR_CALL(zeCommandListAppendWaitOnEvents,
2185-
(UrContext->ZeCommandListInit, waitlist.Length,
2186-
waitlist.ZeEventList));
2190+
ze_command_list_handle_t ZeCommandListForInit =
2191+
UrContext->ZeCommandListInit;
2192+
if (InOrderListRequired) {
2193+
ZeCommandListForInit = UrContext->ZeCommandListInitInOrder;
2194+
}
2195+
ZE2UR_CALL(
2196+
zeCommandListAppendWaitOnEvents,
2197+
(ZeCommandListForInit, waitlist.Length, waitlist.ZeEventList));
21872198
}
21882199

21892200
// Copy valid buffer data to this allocation.

source/adapters/level_zero/queue.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,16 +1186,9 @@ ur_queue_handle_t_::ur_queue_handle_t_(
11861186
ZeCommandListBatchComputeConfig.startSize();
11871187
CopyCommandBatch.QueueBatchSize = ZeCommandListBatchCopyConfig.startSize();
11881188

1189-
static const bool useDriverCounterBasedEvents = [] {
1190-
const char *UrRet = std::getenv("UR_L0_USE_DRIVER_COUNTER_BASED_EVENTS");
1191-
if (!UrRet) {
1192-
return true;
1193-
}
1194-
return std::atoi(UrRet) != 0;
1195-
}();
11961189
this->CounterBasedEventsEnabled =
11971190
UsingImmCmdLists && isInOrderQueue() && Device->useDriverInOrderLists() &&
1198-
useDriverCounterBasedEvents &&
1191+
Device->useDriverCounterBasedEvents() &&
11991192
Device->Platform->ZeDriverEventPoolCountingEventsExtensionFound;
12001193
this->InterruptBasedEventsEnabled =
12011194
isLowPowerEvents() && isInOrderQueue() && Device->useDriverInOrderLists();

0 commit comments

Comments
 (0)