Skip to content

Commit e3c9c92

Browse files
[SYCL][L0] Add ownership control for LeveL-Zero kernel_bundle interop. (#4576)
Signed-off-by: Sergey V Maslov <sergey.v.maslov@intel.com>
1 parent c2221f0 commit e3c9c92

File tree

15 files changed

+128
-65
lines changed

15 files changed

+128
-65
lines changed

sycl/doc/extensions/LevelZeroBackend/LevelZeroBackend.md

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ backend_input_t<backend::ext_oneapi_level_zero,
101101
struct {
102102
ze_context_handle_t NativeHandle;
103103
std::vector<device> DeviceList;
104-
ext::oneapi::level_zero::ownership Ownership;
104+
ext::oneapi::level_zero::ownership Ownership{
105+
ext::oneapi::level_zero::ownership::transfer};
105106
}
106107
```
107108
</td>
@@ -113,7 +114,8 @@ struct {
113114
``` C++
114115
struct {
115116
ze_command_queue_handle_t NativeHandle;
116-
ext::oneapi::level_zero::ownership Ownership;
117+
ext::oneapi::level_zero::ownership Ownership{
118+
ext::oneapi::level_zero::ownership::transfer};
117119
}
118120
```
119121
</td>
@@ -125,7 +127,8 @@ struct {
125127
``` C++
126128
struct {
127129
ze_event_handle_t NativeHandle;
128-
ext::oneapi::level_zero::ownership Ownership;
130+
ext::oneapi::level_zero::ownership Ownership{
131+
ext::oneapi::level_zero::ownership::transfer};
129132
}
130133
```
131134
</td>
@@ -137,7 +140,16 @@ struct {
137140
std::vector<ze_module_handle_t>
138141
```
139142
</td>
140-
<td><pre>ze_module_handle_t</pre></td>
143+
<td>
144+
145+
``` C++
146+
struct {
147+
ze_module_handle_t NativeHandle;
148+
ext::oneapi::level_zero::ownership Ownership{
149+
ext::oneapi::level_zero::ownership::transfer};
150+
}
151+
```
152+
</td>
141153
</tr>
142154
</table>
143155
@@ -226,7 +238,20 @@ make_kernel_bundle<backend::ext_oneapi_level_zero,
226238
const context &Context)
227239
```
228240
</td>
229-
<td>Constructs a SYCL kernel_bundle instance from a Level-Zero <code>ze_module_handle_t</code>. The <code>Context</code> 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 <a href="https://spec.oneapi.com/level-zero/latest/core/api.html?highlight=zemoduledynamiclink#_CPPv419zeModuleDynamicLink8uint32_tP18ze_module_handle_tP28ze_module_build_log_handle_t"><code>zeModuleDynamicLink</code></a>), and thus the SYCL kernel_bundle is created in the "executable" state.</td>
241+
<td>Constructs a SYCL kernel_bundle instance from a Level-Zero
242+
<code>ze_module_handle_t</code>. The <code>Context</code> argument must be a
243+
valid SYCL context encapsulating a Level-Zero context, and the Level-Zero
244+
module must be created on the same context. The Level-Zero module must be
245+
fully linked (i.e. not require further linking through <a href="https://spec.oneapi.com/level-zero/latest/core/api.html?highlight=zemoduledynamiclink#_CPPv419zeModuleDynamicLink8uint32_tP18ze_module_handle_tP28ze_module_build_log_handle_t">
246+
<code>zeModuleDynamicLink</code></a>), and thus the SYCL kernel_bundle is
247+
created in the "executable" state. The <code>Ownership</code> input structure
248+
member specifies if the SYCL runtime should take ownership of the passed
249+
native handle. The default behavior is to transfer the ownership to the SYCL
250+
runtime. See section 4.4 for details. If the behavior is "transfer" then the
251+
runtime is going to destroy the input Level-Zero module, and hence the
252+
application must not to have any outstanding <code>ze_kernel_handle_t</code>
253+
handles to the underlying <code>ze_module_handle_t</code> by the time this
254+
interoperability <code>kernel_bundle</code> destructor is called.</td>
230255
</tr>
231256
</table>
232257

sycl/include/CL/sycl/backend.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,13 @@ __SYCL_EXPORT event make_event(pi_native_handle NativeHandle,
108108
backend Backend);
109109
__SYCL_EXPORT kernel make_kernel(pi_native_handle NativeHandle,
110110
const context &TargetContext, backend Backend);
111+
// TODO: Unused. Remove when allowed.
111112
__SYCL_EXPORT std::shared_ptr<detail::kernel_bundle_impl>
112113
make_kernel_bundle(pi_native_handle NativeHandle, const context &TargetContext,
113114
bundle_state State, backend Backend);
115+
__SYCL_EXPORT std::shared_ptr<detail::kernel_bundle_impl>
116+
make_kernel_bundle(pi_native_handle NativeHandle, const context &TargetContext,
117+
bool KeepOwnership, bundle_state State, backend Backend);
114118
} // namespace detail
115119

116120
template <backend Backend>
@@ -221,7 +225,7 @@ make_kernel_bundle(const typename backend_traits<Backend>::template input_type<
221225
std::shared_ptr<detail::kernel_bundle_impl> KBImpl =
222226
detail::make_kernel_bundle(
223227
detail::pi::cast<pi_native_handle>(BackendObject), TargetContext,
224-
State, Backend);
228+
false, State, Backend);
225229
return detail::createSyclObjFromImpl<kernel_bundle<State>>(KBImpl);
226230
}
227231
} // namespace sycl

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

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
// changes the API version from 3.5 to 4.6.
4141
// 5.7 Added new context and ownership arguments to
4242
// piextEventCreateWithNativeHandle
43+
// 6.8 Added new ownership argument to piextProgramCreateWithNativeHandle.
4344
//
4445
#include "CL/cl.h"
4546
#define _PI_H_VERSION_MAJOR 5
@@ -1033,8 +1034,8 @@ piextContextGetNativeHandle(pi_context context, pi_native_handle *nativeHandle);
10331034
/// \param devices is the list of devices in the context. Parameter is ignored
10341035
/// if devices can be queried from the context native handle for a
10351036
/// backend.
1036-
/// \param ownNativeHandle tells if SYCL RT should assume the ownership of
1037-
/// the native handle, if it can.
1037+
/// \param pluginOwnsNativeHandle Indicates whether the created PI object
1038+
/// should take ownership of the native handle.
10381039
/// \param context is the PI context created from the native handle.
10391040
/// \return PI_SUCCESS if successfully created pi_context from the handle.
10401041
/// PI_OUT_OF_HOST_MEMORY if can't allocate memory for the pi_context
@@ -1043,7 +1044,7 @@ piextContextGetNativeHandle(pi_context context, pi_native_handle *nativeHandle);
10431044
/// native handle. PI_UNKNOWN_ERROR in case of another error.
10441045
__SYCL_EXPORT pi_result piextContextCreateWithNativeHandle(
10451046
pi_native_handle nativeHandle, pi_uint32 numDevices,
1046-
const pi_device *devices, bool ownNativeHandle, pi_context *context);
1047+
const pi_device *devices, bool pluginOwnsNativeHandle, pi_context *context);
10471048

10481049
//
10491050
// Queue
@@ -1077,11 +1078,11 @@ piextQueueGetNativeHandle(pi_queue queue, pi_native_handle *nativeHandle);
10771078
/// \param nativeHandle is the native handle to create PI queue from.
10781079
/// \param context is the PI context of the queue.
10791080
/// \param queue is the PI queue created from the native handle.
1080-
/// \param ownNativeHandle tells if SYCL RT should assume the ownership of
1081-
/// the native handle, if it can.
1081+
/// \param pluginOwnsNativeHandle Indicates whether the created PI object
1082+
/// should take ownership of the native handle.
10821083
__SYCL_EXPORT pi_result piextQueueCreateWithNativeHandle(
10831084
pi_native_handle nativeHandle, pi_context context, pi_queue *queue,
1084-
bool ownNativeHandle);
1085+
bool pluginOwnsNativeHandle);
10851086

10861087
//
10871088
// Memory
@@ -1219,9 +1220,12 @@ piextProgramGetNativeHandle(pi_program program, pi_native_handle *nativeHandle);
12191220
///
12201221
/// \param nativeHandle is the native handle to create PI program from.
12211222
/// \param context is the PI context of the program.
1223+
/// \param pluginOwnsNativeHandle Indicates whether the created PI object
1224+
/// should take ownership of the native handle.
12221225
/// \param program is the PI program created from the native handle.
12231226
__SYCL_EXPORT pi_result piextProgramCreateWithNativeHandle(
1224-
pi_native_handle nativeHandle, pi_context context, pi_program *program);
1227+
pi_native_handle nativeHandle, pi_context context,
1228+
bool pluginOwnsNativeHandle, pi_program *program);
12251229

12261230
//
12271231
// Kernel
@@ -1315,12 +1319,12 @@ __SYCL_EXPORT pi_result piKernelSetExecInfo(pi_kernel kernel,
13151319
///
13161320
/// \param nativeHandle is the native handle to create PI kernel from.
13171321
/// \param context is the PI context of the kernel.
1318-
/// \param ownNativeHandle tells if SYCL RT should assume the ownership of
1319-
/// the native handle, if it can.
1322+
/// \param pluginOwnsNativeHandle Indicates whether the created PI object
1323+
/// should take ownership of the native handle.
13201324
/// \param kernel is the PI kernel created from the native handle.
13211325
__SYCL_EXPORT pi_result piextKernelCreateWithNativeHandle(
1322-
pi_native_handle nativeHandle, pi_context context, bool ownNativeHandle,
1323-
pi_kernel *kernel);
1326+
pi_native_handle nativeHandle, pi_context context,
1327+
bool pluginOwnsNativeHandle, pi_kernel *kernel);
13241328

13251329
/// Gets the native handle of a PI kernel object.
13261330
///
@@ -1373,8 +1377,8 @@ piextEventGetNativeHandle(pi_event event, pi_native_handle *nativeHandle);
13731377
///
13741378
/// \param nativeHandle is the native handle to create PI event from.
13751379
/// \param context is the corresponding PI context
1376-
/// \param ownNativeHandle tells if SYCL RT should assume the ownership of
1377-
/// the native handle, if it can.
1380+
/// \param pluginOwnsNativeHandle Indicates whether the created PI object
1381+
/// should take ownership of the native handle.
13781382
/// \param event is the PI event created from the native handle.
13791383
__SYCL_EXPORT pi_result piextEventCreateWithNativeHandle(
13801384
pi_native_handle nativeHandle, pi_context context, bool ownNativeHandle,

sycl/include/sycl/ext/oneapi/backend/level_zero.hpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ template <> struct BackendInput<backend::level_zero, event> {
101101

102102
template <bundle_state State>
103103
struct BackendInput<backend::level_zero, kernel_bundle<State>> {
104-
using type = ze_module_handle_t;
104+
using type = struct {
105+
ze_module_handle_t NativeHandle;
106+
ext::oneapi::level_zero::ownership Ownership{
107+
ext::oneapi::level_zero::ownership::transfer};
108+
};
105109
};
106110

107111
template <bundle_state State>
@@ -249,6 +253,24 @@ event make_event<backend::level_zero>(
249253
BackendObject.Ownership == ext::oneapi::level_zero::ownership::keep);
250254
}
251255

256+
// Specialization of sycl::make_kernel_bundle for Level-Zero backend.
257+
template <>
258+
kernel_bundle<bundle_state::executable>
259+
make_kernel_bundle<backend::ext_oneapi_level_zero, bundle_state::executable>(
260+
const backend_input_t<backend::ext_oneapi_level_zero,
261+
kernel_bundle<bundle_state::executable>>
262+
&BackendObject,
263+
const context &TargetContext) {
264+
std::shared_ptr<detail::kernel_bundle_impl> KBImpl =
265+
detail::make_kernel_bundle(
266+
detail::pi::cast<pi_native_handle>(BackendObject.NativeHandle),
267+
TargetContext,
268+
BackendObject.Ownership == ext::oneapi::level_zero::ownership::keep,
269+
bundle_state::executable, backend::ext_oneapi_level_zero);
270+
return detail::createSyclObjFromImpl<kernel_bundle<bundle_state::executable>>(
271+
KBImpl);
272+
}
273+
252274
// TODO: remove this specialization when generic is changed to call
253275
// .GetNative() instead of .get_native() member of kernel_bundle.
254276
template <>

sycl/plugins/cuda/pi_cuda.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3174,7 +3174,7 @@ pi_result cuda_piextProgramGetNativeHandle(pi_program program,
31743174
///
31753175
/// \return TBD
31763176
pi_result cuda_piextProgramCreateWithNativeHandle(pi_native_handle, pi_context,
3177-
pi_program *) {
3177+
bool, pi_program *) {
31783178
cl::sycl::detail::pi::die(
31793179
"Creation of PI program from native handle not implemented");
31803180
return {};

sycl/plugins/esimd_cpu/pi_esimd_cpu.cpp

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,19 +1019,15 @@ pi_result piProgramGetBuildInfo(pi_program, pi_device, cl_program_build_info,
10191019
DIE_NO_IMPLEMENTATION;
10201020
}
10211021

1022-
pi_result piProgramRetain(pi_program) {
1023-
DIE_NO_IMPLEMENTATION;
1024-
}
1022+
pi_result piProgramRetain(pi_program) { DIE_NO_IMPLEMENTATION; }
10251023

1026-
pi_result piProgramRelease(pi_program) {
1027-
DIE_NO_IMPLEMENTATION;
1028-
}
1024+
pi_result piProgramRelease(pi_program) { DIE_NO_IMPLEMENTATION; }
10291025

10301026
pi_result piextProgramGetNativeHandle(pi_program, pi_native_handle *) {
10311027
DIE_NO_IMPLEMENTATION;
10321028
}
10331029

1034-
pi_result piextProgramCreateWithNativeHandle(pi_native_handle, pi_context,
1030+
pi_result piextProgramCreateWithNativeHandle(pi_native_handle, pi_context, bool,
10351031
pi_program *) {
10361032
DIE_NO_IMPLEMENTATION;
10371033
}
@@ -1068,17 +1064,11 @@ pi_result piKernelGetSubGroupInfo(pi_kernel, pi_device,
10681064
DIE_NO_IMPLEMENTATION;
10691065
}
10701066

1071-
pi_result piKernelRetain(pi_kernel) {
1072-
DIE_NO_IMPLEMENTATION;
1073-
}
1067+
pi_result piKernelRetain(pi_kernel) { DIE_NO_IMPLEMENTATION; }
10741068

1075-
pi_result piKernelRelease(pi_kernel) {
1076-
DIE_NO_IMPLEMENTATION;
1077-
}
1069+
pi_result piKernelRelease(pi_kernel) { DIE_NO_IMPLEMENTATION; }
10781070

1079-
pi_result piEventCreate(pi_context, pi_event *) {
1080-
DIE_NO_IMPLEMENTATION;
1081-
}
1071+
pi_result piEventCreate(pi_context, pi_event *) { DIE_NO_IMPLEMENTATION; }
10821072

10831073
pi_result piEventGetInfo(pi_event, pi_event_info, size_t, void *, size_t *) {
10841074
DIE_NO_IMPLEMENTATION;
@@ -1117,9 +1107,7 @@ pi_result piEventSetCallback(pi_event, pi_int32,
11171107
DIE_NO_IMPLEMENTATION;
11181108
}
11191109

1120-
pi_result piEventSetStatus(pi_event, pi_int32) {
1121-
DIE_NO_IMPLEMENTATION;
1122-
}
1110+
pi_result piEventSetStatus(pi_event, pi_int32) { DIE_NO_IMPLEMENTATION; }
11231111

11241112
pi_result piEventRetain(pi_event Event) {
11251113
if (Event == nullptr) {
@@ -1170,13 +1158,9 @@ pi_result piSamplerGetInfo(pi_sampler, pi_sampler_info, size_t, void *,
11701158
DIE_NO_IMPLEMENTATION;
11711159
}
11721160

1173-
pi_result piSamplerRetain(pi_sampler) {
1174-
DIE_NO_IMPLEMENTATION;
1175-
}
1161+
pi_result piSamplerRetain(pi_sampler) { DIE_NO_IMPLEMENTATION; }
11761162

1177-
pi_result piSamplerRelease(pi_sampler) {
1178-
DIE_NO_IMPLEMENTATION;
1179-
}
1163+
pi_result piSamplerRelease(pi_sampler) { DIE_NO_IMPLEMENTATION; }
11801164

11811165
pi_result piEnqueueEventsWait(pi_queue, pi_uint32, const pi_event *,
11821166
pi_event *) {

sycl/plugins/hip/pi_hip.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3018,11 +3018,14 @@ pi_result hip_piextProgramGetNativeHandle(pi_program program,
30183018
///
30193019
/// \param[in] nativeHandle The native handle to create PI program object from.
30203020
/// \param[in] context The PI context of the program.
3021+
/// \param[in] ownNativeHandle tells if should assume the ownership of
3022+
/// the native handle.
30213023
/// \param[out] program Set to the PI program object created from native handle.
30223024
///
30233025
/// \return TBD
30243026
pi_result hip_piextProgramCreateWithNativeHandle(pi_native_handle nativeHandle,
30253027
pi_context context,
3028+
bool ownNativeHandle,
30263029
pi_program *program) {
30273030
(void)nativeHandle;
30283031
(void)context;

sycl/plugins/level_zero/pi_level_zero.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3657,8 +3657,9 @@ pi_result piProgramLink(pi_context Context, pi_uint32 NumDevices,
36573657
if (res != PI_SUCCESS) {
36583658
return res;
36593659
}
3660-
Input = new _pi_program(Input->Context, ZeModule, _pi_program::Object,
3661-
Input->HasImports);
3660+
Input =
3661+
new _pi_program(Input->Context, ZeModule, true /*own ZeModule*/,
3662+
_pi_program::Object, Input->HasImports);
36623663
Input->HasImportsAndIsLinked = true;
36633664
}
36643665
} else {
@@ -3913,6 +3914,7 @@ pi_result piextProgramGetNativeHandle(pi_program Program,
39133914

39143915
pi_result piextProgramCreateWithNativeHandle(pi_native_handle NativeHandle,
39153916
pi_context Context,
3917+
bool ownNativeHandle,
39163918
pi_program *Program) {
39173919
PI_ASSERT(Program, PI_INVALID_PROGRAM);
39183920
PI_ASSERT(NativeHandle, PI_INVALID_VALUE);
@@ -3925,7 +3927,8 @@ pi_result piextProgramCreateWithNativeHandle(pi_native_handle NativeHandle,
39253927
// executable (state Object).
39263928

39273929
try {
3928-
*Program = new _pi_program(Context, ZeModule, _pi_program::Exe);
3930+
*Program =
3931+
new _pi_program(Context, ZeModule, ownNativeHandle, _pi_program::Exe);
39293932
} catch (const std::bad_alloc &) {
39303933
return PI_OUT_OF_HOST_MEMORY;
39313934
} catch (...) {
@@ -3942,7 +3945,7 @@ _pi_program::~_pi_program() {
39423945
ZE_CALL_NOCHECK(zeModuleBuildLogDestroy, (ZeBuildLog));
39433946
}
39443947

3945-
if (ZeModule) {
3948+
if (ZeModule && OwnZeModule) {
39463949
ZE_CALL_NOCHECK(zeModuleDestroy, (ZeModule));
39473950
}
39483951
}

sycl/plugins/level_zero/pi_level_zero.hpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,23 +1068,24 @@ struct _pi_program : _pi_object {
10681068
// Construct a program in IL or Native state.
10691069
_pi_program(pi_context Context, const void *Input, size_t Length, state St)
10701070
: State(St), Context(Context), Code(new uint8_t[Length]),
1071-
CodeLength(Length), ZeModule(nullptr), HasImports(false),
1072-
HasImportsAndIsLinked(false), ZeBuildLog(nullptr) {
1071+
CodeLength(Length), ZeModule(nullptr), OwnZeModule{true},
1072+
HasImports(false), HasImportsAndIsLinked(false), ZeBuildLog(nullptr) {
10731073

10741074
std::memcpy(Code.get(), Input, Length);
10751075
}
10761076

10771077
// Construct a program in either Object or Exe state.
1078-
_pi_program(pi_context Context, ze_module_handle_t ZeModule, state St,
1079-
bool HasImports = false)
1080-
: State(St), Context(Context), ZeModule(ZeModule), HasImports(HasImports),
1078+
_pi_program(pi_context Context, ze_module_handle_t ZeModule, bool OwnZeModule,
1079+
state St, bool HasImports = false)
1080+
: State(St), Context(Context),
1081+
ZeModule(ZeModule), OwnZeModule{OwnZeModule}, HasImports(HasImports),
10811082
HasImportsAndIsLinked(false), ZeBuildLog(nullptr) {}
10821083

10831084
// Construct a program in LinkedExe state.
10841085
_pi_program(pi_context Context, std::vector<LinkedReleaser> &&Inputs,
10851086
ze_module_build_log_handle_t ZeLog)
10861087
: State(LinkedExe), Context(Context), ZeModule(nullptr),
1087-
HasImports(false), HasImportsAndIsLinked(false),
1088+
OwnZeModule(true), HasImports(false), HasImportsAndIsLinked(false),
10881089
LinkedPrograms(std::move(Inputs)), ZeBuildLog(ZeLog) {}
10891090

10901091
~_pi_program();
@@ -1103,7 +1104,13 @@ struct _pi_program : _pi_object {
11031104

11041105
// Used for programs in Object or Exe state.
11051106
ze_module_handle_t ZeModule; // Level Zero module handle.
1106-
bool HasImports; // Tells if module imports any symbols.
1107+
1108+
// Indicates if we own the ZeModule or it came from interop that
1109+
// asked to not transfer the ownership to SYCL RT.
1110+
bool OwnZeModule;
1111+
1112+
// Tells if module imports any symbols.
1113+
bool HasImports;
11071114

11081115
// Used for programs in Object state. Tells if this module imports any
11091116
// symbols AND it is linked into some other program that has state LinkedExe.

0 commit comments

Comments
 (0)