Skip to content

Commit 6cf48fa

Browse files
authored
[SYCL] Add Level-Zero interop with specification of ownership for Queue. (#4066)
The L0 backend interop functions take the ownership of the passed L0 handles. This is problematic for some cases as the users can not use the original handle when they go out of scope and destroyed. This PR provides a way for users of SYCL - L0 interop to retain the ownership of the L0 handles for the Queue. Signed-off-by: rehana begam <[email protected]>
1 parent 3661685 commit 6cf48fa

File tree

14 files changed

+71
-27
lines changed

14 files changed

+71
-27
lines changed

sycl/doc/extensions/LevelZeroBackend/LevelZeroBackend.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ a SYCL object that encapsulates a corresponding Level-Zero object:
8888
|``` make<platform>(ze_driver_handle_t);```|Constructs a SYCL platform instance from a Level-Zero ```ze_driver_handle_t```.|
8989
|``` make<device>(const platform &, ze_device_handle_t);```|Constructs a SYCL device instance from a Level-Zero ```ze_device_handle_t```. The platform argument gives a SYCL platform, encapsulating a Level-Zero driver supporting the passed Level-Zero device.|
9090
|``` make<context>(const vector_class<device> &, ze_context_handle_t, ownership = transfer);```| Constructs a SYCL context instance from a Level-Zero ```ze_context_handle_t```. The context is created against the devices passed in. There must be at least one device given and all the devices must be from the same SYCL platform and thus from the same Level-Zero driver. The ```ownership``` argument specifies if the SYCL runtime should take ownership of the passed native handle. The default behavior is to transfer the ownership to the SYCL runtime. See section 4.4 for details.|
91-
|``` make<queue>(const context &, ze_command_queue_handle_t);```| Constructs a SYCL queue instance from a Level-Zero ```ze_command_queue_handle_t```. The context argument must be a valid SYCL context encapsulating a Level-Zero context. The queue is attached to the first device in the passed SYCL context.|
91+
|``` make<queue>(const context &, ze_command_queue_handle_t, ownership = transfer);```| Constructs a SYCL queue instance from a Level-Zero ```ze_command_queue_handle_t```. The context argument must be a valid SYCL context encapsulating a Level-Zero context. The queue is attached to the first device in the passed SYCL context. The ```ownership``` argument specifies if the SYCL runtime should take ownership of the passed native handle. The default behavior is to transfer the ownership to the SYCL runtime. See section 4.4 for details.|
9292
|``` make<program>(const context &, ze_module_handle_t);```| Constructs a SYCL program instance from a Level-Zero ```ze_module_handle_t```. The context argument must be a valid SYCL context encapsulating a Level-Zero context. The Level-Zero module must be fully linked (i.e. not require further linking through [```zeModuleDynamicLink```](https://spec.oneapi.com/level-zero/latest/core/api.html?highlight=zemoduledynamiclink#_CPPv419zeModuleDynamicLink8uint32_tP18ze_module_handle_tP28ze_module_build_log_handle_t)), and thus the SYCL program is created in the "linked" state.|
9393
9494
NOTE: We shall consider adding other interoperability as needed, if possible.
@@ -189,4 +189,4 @@ struct free_memory {
189189
|1|2021-01-26|Sergey Maslov|Initial public working draft
190190
|2|2021-02-22|Sergey Maslov|Introduced explicit ownership for context
191191
|3|2021-04-13|James Brodman|Free Memory Query
192-
192+
|4|2021-07-06|Rehana Begam|Introduced explicit ownership for queue

sycl/include/CL/sycl/backend.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ __SYCL_EXPORT device make_device(pi_native_handle NativeHandle,
9090
__SYCL_EXPORT context make_context(pi_native_handle NativeHandle,
9191
const async_handler &Handler,
9292
backend Backend);
93+
__SYCL_EXPORT queue make_queue(pi_native_handle NativeHandle,
94+
const context &TargetContext, bool KeepOwnership,
95+
const async_handler &Handler, backend Backend);
9396
__SYCL_EXPORT queue make_queue(pi_native_handle NativeHandle,
9497
const context &TargetContext,
9598
const async_handler &Handler, backend Backend);
@@ -139,9 +142,10 @@ typename std::enable_if<
139142
detail::InteropFeatureSupportMap<Backend>::MakeQueue == true, queue>::type
140143
make_queue(const typename backend_traits<Backend>::template input_type<queue>
141144
&BackendObject,
142-
const context &TargetContext, const async_handler Handler = {}) {
145+
const context &TargetContext, bool KeepOwnership,
146+
const async_handler Handler = {}) {
143147
return detail::make_queue(detail::pi::cast<pi_native_handle>(BackendObject),
144-
TargetContext, Handler, Backend);
148+
TargetContext, KeepOwnership, Handler, Backend);
145149
}
146150

147151
template <backend Backend>

sycl/include/CL/sycl/backend/level_zero.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ __SYCL_EXPORT context make_context(const std::vector<device> &DeviceList,
9292
__SYCL_EXPORT program make_program(const context &Context,
9393
pi_native_handle NativeHandle);
9494
__SYCL_EXPORT queue make_queue(const context &Context,
95-
pi_native_handle InteropHandle);
95+
pi_native_handle InteropHandle,
96+
bool keep_ownership = false);
9697

9798
// Construction of SYCL platform.
9899
template <typename T, typename detail::enable_if_t<
@@ -139,8 +140,10 @@ T make(const context &Context,
139140
template <typename T, typename detail::enable_if_t<
140141
std::is_same<T, queue>::value> * = nullptr>
141142
T make(const context &Context,
142-
typename interop<backend::level_zero, T>::type Interop) {
143-
return make_queue(Context, reinterpret_cast<pi_native_handle>(Interop));
143+
typename interop<backend::level_zero, T>::type Interop,
144+
ownership Ownership = ownership::transfer) {
145+
return make_queue(Context, reinterpret_cast<pi_native_handle>(Interop),
146+
Ownership == ownership::keep);
144147
}
145148

146149
} // namespace level_zero

sycl/include/CL/sycl/detail/pi.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
// 2. A number of types needed to define pi_device_binary_property_set added.
3737
// 3. Added new ownership argument to piextContextCreateWithNativeHandle.
3838
// 4. Add interoperability interfaces for kernel.
39+
// 4.6 Added new ownership argument to piextQueueCreateWithNativeHandle which
40+
// changes the API version from 3.5 to 4.6.
3941
//
4042
#include "CL/cl.h"
41-
#define _PI_H_VERSION_MAJOR 3
42-
#define _PI_H_VERSION_MINOR 5
43+
#define _PI_H_VERSION_MAJOR 4
44+
#define _PI_H_VERSION_MINOR 6
4345

4446
#define _PI_STRING_HELPER(a) #a
4547
#define _PI_CONCAT(a, b) _PI_STRING_HELPER(a.b)
@@ -1053,8 +1055,11 @@ piextQueueGetNativeHandle(pi_queue queue, pi_native_handle *nativeHandle);
10531055
/// \param nativeHandle is the native handle to create PI queue from.
10541056
/// \param context is the PI context of the queue.
10551057
/// \param queue is the PI queue created from the native handle.
1058+
/// \param ownNativeHandle tells if SYCL RT should assume the ownership of
1059+
/// the native handle, if it can.
10561060
__SYCL_EXPORT pi_result piextQueueCreateWithNativeHandle(
1057-
pi_native_handle nativeHandle, pi_context context, pi_queue *queue);
1061+
pi_native_handle nativeHandle, pi_context context, pi_queue *queue,
1062+
bool ownNativeHandle);
10581063

10591064
//
10601065
// Memory

sycl/plugins/cuda/pi_cuda.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2193,10 +2193,14 @@ pi_result cuda_piextQueueGetNativeHandle(pi_queue queue,
21932193
/// \param[in] nativeHandle The native handle to create PI queue object from.
21942194
/// \param[in] context is the PI context of the queue.
21952195
/// \param[out] queue Set to the PI queue object created from native handle.
2196+
/// \param ownNativeHandle tells if SYCL RT should assume the ownership of
2197+
/// the native handle, if it can.
21962198
///
21972199
/// \return TBD
21982200
pi_result cuda_piextQueueCreateWithNativeHandle(pi_native_handle, pi_context,
2199-
pi_queue *) {
2201+
pi_queue *,
2202+
bool ownNativeHandle) {
2203+
(void)ownNativeHandle;
22002204
cl::sycl::detail::pi::die(
22012205
"Creation of PI queue from native handle not implemented");
22022206
return {};

sycl/plugins/esimd_cpu/pi_esimd_cpu.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ pi_result piextQueueGetNativeHandle(pi_queue, pi_native_handle *) {
675675
}
676676

677677
pi_result piextQueueCreateWithNativeHandle(pi_native_handle, pi_context,
678-
pi_queue *) {
678+
pi_queue *, bool) {
679679
DIE_NO_IMPLEMENTATION;
680680
return PI_SUCCESS;
681681
}

sycl/plugins/level_zero/pi_level_zero.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2423,7 +2423,7 @@ pi_result piQueueCreate(pi_context Context, pi_device Device,
24232423

24242424
try {
24252425
*Queue = new _pi_queue(ZeComputeCommandQueue, ZeCopyCommandQueue, Context,
2426-
Device, ZeCommandListBatchSize, Properties);
2426+
Device, ZeCommandListBatchSize, true, Properties);
24272427
} catch (const std::bad_alloc &) {
24282428
return PI_OUT_OF_HOST_MEMORY;
24292429
} catch (...) {
@@ -2506,10 +2506,16 @@ pi_result piQueueRelease(pi_queue Queue) {
25062506
ZE_CALL(zeFenceDestroy, (MapEntry.second.ZeFence));
25072507
}
25082508
Queue->ZeCommandListFenceMap.clear();
2509-
ZE_CALL(zeCommandQueueDestroy, (Queue->ZeComputeCommandQueue));
2509+
2510+
if (Queue->OwnZeCommandQueue) {
2511+
ZE_CALL(zeCommandQueueDestroy, (Queue->ZeComputeCommandQueue));
2512+
if (Queue->ZeCopyCommandQueue) {
2513+
ZE_CALL(zeCommandQueueDestroy, (Queue->ZeCopyCommandQueue));
2514+
}
2515+
}
2516+
25102517
Queue->ZeComputeCommandQueue = nullptr;
25112518
if (Queue->ZeCopyCommandQueue) {
2512-
ZE_CALL(zeCommandQueueDestroy, (Queue->ZeCopyCommandQueue));
25132519
Queue->ZeCopyCommandQueue = nullptr;
25142520
}
25152521

@@ -2557,8 +2563,8 @@ pi_result piextQueueGetNativeHandle(pi_queue Queue,
25572563
}
25582564

25592565
pi_result piextQueueCreateWithNativeHandle(pi_native_handle NativeHandle,
2560-
pi_context Context,
2561-
pi_queue *Queue) {
2566+
pi_context Context, pi_queue *Queue,
2567+
bool OwnNativeHandle) {
25622568
PI_ASSERT(Context, PI_INVALID_CONTEXT);
25632569
PI_ASSERT(NativeHandle, PI_INVALID_VALUE);
25642570
PI_ASSERT(Queue, PI_INVALID_QUEUE);
@@ -2570,8 +2576,8 @@ pi_result piextQueueCreateWithNativeHandle(pi_native_handle NativeHandle,
25702576
pi_device Device = Context->Devices[0];
25712577
// TODO: see what we can do to correctly initialize PI queue for
25722578
// compute vs. copy Level-Zero queue.
2573-
*Queue =
2574-
new _pi_queue(ZeQueue, nullptr, Context, Device, ZeCommandListBatchSize);
2579+
*Queue = new _pi_queue(ZeQueue, nullptr, Context, Device,
2580+
ZeCommandListBatchSize, OwnNativeHandle);
25752581
return PI_SUCCESS;
25762582
}
25772583

sycl/plugins/level_zero/pi_level_zero.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,13 @@ const pi_uint32 DynamicBatchStartSize = 4;
482482
struct _pi_queue : _pi_object {
483483
_pi_queue(ze_command_queue_handle_t Queue,
484484
ze_command_queue_handle_t CopyQueue, pi_context Context,
485-
pi_device Device, pi_uint32 BatchSize,
485+
pi_device Device, pi_uint32 BatchSize, bool OwnZeCommandQueue,
486486
pi_queue_properties PiQueueProperties = 0)
487487
: ZeComputeCommandQueue{Queue},
488488
ZeCopyCommandQueue{CopyQueue}, Context{Context}, Device{Device},
489489
QueueBatchSize{BatchSize > 0 ? BatchSize : DynamicBatchStartSize},
490-
UseDynamicBatching{BatchSize == 0},
490+
OwnZeCommandQueue{OwnZeCommandQueue}, UseDynamicBatching{BatchSize ==
491+
0},
491492
PiQueueProperties(PiQueueProperties) {}
492493

493494
// Level Zero compute command queue handle.
@@ -540,6 +541,10 @@ struct _pi_queue : _pi_object {
540541
// is thread safe because of the locking of the queue that occurs.
541542
pi_uint32 QueueBatchSize = {0};
542543

544+
// Indicates if we own the ZeCommandQueue or it came from interop that
545+
// asked to not transfer the ownership to SYCL RT.
546+
bool OwnZeCommandQueue;
547+
543548
// specifies whether this queue will be using dynamic batch size adjustment
544549
// or not. This is set only at queue creation time, and is therefore
545550
// const for the life of the queue.

sycl/plugins/opencl/pi_opencl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,9 @@ pi_result piQueueCreate(pi_context context, pi_device device,
354354
}
355355

356356
pi_result piextQueueCreateWithNativeHandle(pi_native_handle nativeHandle,
357-
pi_context, pi_queue *piQueue) {
357+
pi_context, pi_queue *piQueue,
358+
bool ownNativeHandle) {
359+
(void)ownNativeHandle;
358360
assert(piQueue != nullptr);
359361
*piQueue = reinterpret_cast<pi_queue>(nativeHandle);
360362
return PI_SUCCESS;

sycl/source/backend.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,18 @@ __SYCL_EXPORT context make_context(pi_native_handle NativeHandle,
8080
__SYCL_EXPORT queue make_queue(pi_native_handle NativeHandle,
8181
const context &Context,
8282
const async_handler &Handler, backend Backend) {
83+
return make_queue(NativeHandle, Context, false, Handler, Backend);
84+
}
85+
86+
__SYCL_EXPORT queue make_queue(pi_native_handle NativeHandle,
87+
const context &Context, bool KeepOwnership,
88+
const async_handler &Handler, backend Backend) {
8389
const auto &Plugin = getPlugin(Backend);
8490
const auto &ContextImpl = getSyclObjImpl(Context);
8591
// Create PI queue first.
8692
pi::PiQueue PiQueue = nullptr;
8793
Plugin.call<PiApiKind::piextQueueCreateWithNativeHandle>(
88-
NativeHandle, ContextImpl->getHandleRef(), &PiQueue);
94+
NativeHandle, ContextImpl->getHandleRef(), &PiQueue, !KeepOwnership);
8995
// Construct the SYCL queue from PI queue.
9096
return detail::createSyclObjFromImpl<queue>(
9197
std::make_shared<queue_impl>(PiQueue, ContextImpl, Handler));

sycl/source/backend/level_zero.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,20 @@ __SYCL_EXPORT program make_program(const context &Context,
7979
//----------------------------------------------------------------------------
8080
// Implementation of level_zero::make<queue>
8181
__SYCL_EXPORT queue make_queue(const context &Context,
82-
pi_native_handle NativeHandle) {
82+
pi_native_handle NativeHandle,
83+
bool KeepOwnership) {
8384
const auto &ContextImpl = getSyclObjImpl(Context);
84-
return detail::make_queue(NativeHandle, Context,
85+
return detail::make_queue(NativeHandle, Context, KeepOwnership,
8586
ContextImpl->get_async_handler(),
8687
backend::level_zero);
8788
}
8889

90+
// TODO: remove this version (without ownership) when allowed to break ABI.
91+
__SYCL_EXPORT queue make_queue(const context &Context,
92+
pi_native_handle NativeHandle) {
93+
return make_queue(Context, NativeHandle, false);
94+
}
95+
8996
} // namespace level_zero
9097
} // namespace sycl
9198
} // __SYCL_INLINE_NAMESPACE(cl)

sycl/source/backend/opencl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ __SYCL_EXPORT program make_program(const context &Context,
5252
__SYCL_EXPORT queue make_queue(const context &Context,
5353
pi_native_handle NativeHandle) {
5454
const auto &ContextImpl = getSyclObjImpl(Context);
55-
return detail::make_queue(NativeHandle, Context,
55+
return detail::make_queue(NativeHandle, Context, false,
5656
ContextImpl->get_async_handler(), backend::opencl);
5757
}
5858
} // namespace opencl

sycl/source/detail/queue_impl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class queue_impl {
115115
DeviceImplPtr(new device_impl(Device, Context->getPlatformImpl()));
116116

117117
// TODO catch an exception and put it to list of asynchronous exceptions
118-
Plugin.call<PiApiKind::piQueueRetain>(MQueues[0]);
118+
getPlugin().call<PiApiKind::piQueueRetain>(MQueues[0]);
119119
}
120120

121121
~queue_impl() {

sycl/test/abi/sycl_symbols_linux.dump

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3591,6 +3591,7 @@ _ZN2cl10__host_std9u_sub_satEjj
35913591
_ZN2cl10__host_std9u_sub_satEmm
35923592
_ZN2cl10__host_std9u_sub_satEtt
35933593
_ZN2cl4sycl10level_zero10make_queueERKNS0_7contextEm
3594+
_ZN2cl4sycl10level_zero10make_queueERKNS0_7contextEmb
35943595
_ZN2cl4sycl10level_zero11make_deviceERKNS0_8platformEm
35953596
_ZN2cl4sycl10level_zero12make_contextERKSt6vectorINS0_6deviceESaIS3_EEm
35963597
_ZN2cl4sycl10level_zero12make_contextERKSt6vectorINS0_6deviceESaIS3_EEmb
@@ -3744,6 +3745,7 @@ _ZN2cl4sycl6detail10image_implILi3EED1Ev
37443745
_ZN2cl4sycl6detail10image_implILi3EED2Ev
37453746
_ZN2cl4sycl6detail10make_eventEmRKNS0_7contextENS0_7backendE
37463747
_ZN2cl4sycl6detail10make_queueEmRKNS0_7contextERKSt8functionIFvNS0_14exception_listEEENS0_7backendE
3748+
_ZN2cl4sycl6detail10make_queueEmRKNS0_7contextEbRKSt8functionIFvNS0_14exception_listEEENS0_7backendE
37473749
_ZN2cl4sycl6detail10waitEventsESt6vectorINS0_5eventESaIS3_EE
37483750
_ZN2cl4sycl6detail11SYCLMemObjT10releaseMemESt10shared_ptrINS1_12context_implEEPv
37493751
_ZN2cl4sycl6detail11SYCLMemObjT16determineHostPtrERKSt10shared_ptrINS1_12context_implEEbRPvRb

0 commit comments

Comments
 (0)