Skip to content

Commit e6dc83b

Browse files
author
iclsrc
committed
Merge from 'sycl' to 'sycl-web' (2 commits)
2 parents e76f74d + 7c49984 commit e6dc83b

26 files changed

+428
-126
lines changed

sycl/doc/extensions/supported/sycl_ext_oneapi_backend_level_zero.md

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This extension provides a feature-test macro as described in the core SYCL speci
1313
|Value|Description|
1414
|---|:---|
1515
|1|Initial extension version.
16+
|2|Added support for the make_buffer() API.
1617

1718
NOTE: This extension is following SYCL 2020 backend specification. Prior API for interoperability with Level-Zero is marked
1819
as deprecated and will be removed in the next release.
@@ -46,7 +47,6 @@ For further details see here: <https://github.com/intel/llvm/blob/sycl/sycl/doc/
4647
4748
There is an extension that introduces a filtering device selection to SYCL described in
4849
[sycl\_ext\_oneapi\_filter\_selector](../supported/sycl_ext_oneapi_filter_selector.asciidoc).
49-
5050
Similar to how SYCL_DEVICE_FILTER applies filtering to the entire process this device selector can be used to
5151
programmatically select the Level-Zero backend.
5252
@@ -170,6 +170,24 @@ struct {
170170
}
171171
```
172172
</td>
173+
</tr><tr>
174+
<td>buffer</td>
175+
<td>
176+
177+
``` C++
178+
void *
179+
```
180+
</td>
181+
<td>
182+
183+
``` C++
184+
struct {
185+
void *NativeHandle;
186+
ext::oneapi::level_zero::ownership Ownership{
187+
ext::oneapi::level_zero::ownership::transfer};
188+
}
189+
```
190+
</td>
173191
</tr>
174192
</table>
175193
@@ -183,8 +201,31 @@ auto get_native(const SyclObjectT &Obj)
183201
-> backend_return_t<BackendName, SyclObjectT>
184202
```
185203
It is currently supported for SYCL ```platform```, ```device```, ```context```, ```queue```, ```event```,
186-
```kernel_bundle```, and ```kernel``` classes.
204+
```kernel_bundle```, and ```kernel``` classes.
205+
206+
The ```sycl::get_native<backend::ext_oneapi_level_zero>```
207+
free-function is not supported for SYCL ```buffer``` class. The native backend object associated with the
208+
buffer can be obtained using interop_hande class as described in the core SYCL specification section
209+
4.10.2, "Class interop_handle".
210+
The pointer returned by ```get_native_mem<backend::ext_oneapi_level_zero>``` method of the ```interop_handle```
211+
class is the value returned from a call to <code>zeMemAllocShared()</code>, <code>zeMemAllocDevice()</code>,
212+
or <code>zeMemAllocHost()</code> and not necessarily directly accessible from the host. Users may need to copy
213+
data to the host to access the data. Users can get type of the allocation using ```type``` data member of the
214+
```ze_memory_allocation_properties_t``` struct returned by ```zeMemGetAllocProperties```.
187215

216+
``` C++
217+
Queue.submit([&](handler &CGH) {
218+
auto BufferAcc = Buffer.get_access<access::mode::write>(CGH);
219+
CGH.host_task([=](const interop_handle &IH) {
220+
void *DevicePtr =
221+
IH.get_native_mem<backend::ext_oneapi_level_zero>(BufferAcc);
222+
ze_memory_allocation_properties_t MemAllocProperties{};
223+
ze_result_t Res = zeMemGetAllocProperties(
224+
ZeContext, DevicePtr, &MemAllocProperties, nullptr);
225+
ze_memory_type_t ZeMemType = MemAllocProperties.type;
226+
});
227+
}).wait();
228+
```
188229
### 4.3 Construct a SYCL object from a Level-Zero handle
189230
190231
The following free functions defined in the ```sycl``` namespace are specialized for Level-Zero backend to allow
@@ -294,6 +335,37 @@ should take ownership of the passed native handle. The default behavior is to
294335
transfer the ownership to the SYCL runtime. See section 4.4 for details. If
295336
the behavior is "transfer" then the runtime is going to destroy the input
296337
Level-Zero kernel</td>
338+
</tr><tr>
339+
<td>
340+
341+
``` C++
342+
make_buffer(
343+
const backend_input_t<backend::ext_oneapi_level_zero,
344+
buffer<T, Dimensions, AllocatorT>> &,
345+
const context &Context)
346+
```
347+
</td>
348+
<td>This API is available starting with revision 2 of this specification.
349+
350+
Construct a SYCL buffer instance from a pointer to a Level Zero memory allocation. The pointer must be the value returned from a previous call to <code>zeMemAllocShared()</code>, <code>zeMemAllocDevice()</code>, or <code>zeMemAllocHost()</code>. The input SYCL context <code>Context</code> must be associated with a single device, matching the device used at the prior allocation.
351+
The <code>Context</code> argument must be a valid SYCL context encapsulating a Level-Zero context, and the Level-Zero memory must be allocated on the same context. Created SYCL buffer can be accessed in another contexts, not only in the provided input context.
352+
The <code>Ownership</code> input structure member 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. If the behavior is "transfer" then the runtime is going to free the input Level-Zero memory allocation.
353+
Synchronization rules for a buffer that is created with this API are described in Section 4.5</td>
354+
</tr><tr>
355+
<td>
356+
357+
``` C++
358+
make_buffer(
359+
const backend_input_t<backend::ext_oneapi_level_zero,
360+
buffer<T, Dimensions, AllocatorT>> &,
361+
const context &Context, event AvailableEvent)
362+
```
363+
</td>
364+
<td>This API is available starting with revision 2 of this specification.
365+
366+
Construct a SYCL buffer instance from a pointer to a Level Zero memory allocation. Please refer to <code>make_buffer</code>
367+
description above for semantics and restrictions.
368+
The additional <code>AvailableEvent</code> argument must be a valid SYCL event. The instance of the SYCL buffer class template being constructed must wait for the SYCL event parameter to signal that the memory native handle is ready to be used.
297369
</tr>
298370
</table>
299371

@@ -349,6 +421,15 @@ Applications must make sure that the Level-Zero handles themselves aren't used s
349421
Practically speaking, and taking into account that SYCL runtime takes ownership of the Level-Zero handles,
350422
the application should not attempt further direct use of those handles.
351423
424+
### 4.5 Interoperability buffer synchronization rules
425+
426+
A SYCL buffer that is constructed with this interop API uses the Level Zero memory allocation for its full lifetime, and the contents of the Level Zero memory allocation are unspecified for the lifetime of the SYCL buffer. If the application modifies the contents of that Level Zero memory allocation during the lifetime of the SYCL buffer, the behavior is undefined. The initial contents of the SYCL buffer will be the initial contents of the Level Zero memory allocation at the time of the SYCL buffer's construction.
427+
428+
The behavior of the SYCL buffer destructor depends on the Ownership flag. As with other SYCL buffers, this behavior is triggered only when the last reference count to the buffer is dropped, as described in the core SYCL specification section 4.7.2.3, "Buffer synchronization rules".
429+
430+
* If the ownership is keep (i.e. the application retains ownership of the Level Zero memory allocation), then the SYCL buffer destructor blocks until all work in queues on the buffer have completed. The buffer's contents is not copied back to the Level Zero memory allocation.
431+
* If the ownership is transfer (i.e. the SYCL runtime has ownership of the Level Zero memory allocation), then the SYCL buffer destructor does not need to block even if work on the buffer has not completed. The SYCL runtime frees the Level Zero memory allocation asynchronously when it is no longer in use in queues.
432+
352433
## 5 Level-Zero additional functionality
353434
354435
### 5.1 Device Information Descriptors
@@ -403,3 +484,4 @@ struct free_memory {
403484
|5|2021-07-25|Sergey Maslov|Introduced SYCL interop for events
404485
|6|2021-08-30|Dmitry Vodopyanov|Updated according to SYCL 2020 reqs for extensions
405486
|7|2021-09-13|Sergey Maslov|Updated according to SYCL 2020 standard
487+
|8|2022-01-06|Artur Gainullin|Introduced make_buffer() API

sycl/include/CL/sycl/backend.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ typename std::enable_if<
242242
template <backend Backend, typename T, int Dimensions = 1,
243243
typename AllocatorT = buffer_allocator>
244244
typename std::enable_if<detail::InteropFeatureSupportMap<Backend>::MakeBuffer ==
245-
true,
245+
true &&
246+
Backend != backend::ext_oneapi_level_zero,
246247
buffer<T, Dimensions, AllocatorT>>::type
247248
make_buffer(const typename backend_traits<Backend>::template input_type<
248249
buffer<T, Dimensions, AllocatorT>> &BackendObject,

sycl/include/CL/sycl/buffer.hpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ template <int dimensions> class range;
2626
namespace detail {
2727
template <typename T, int Dimensions, typename AllocatorT>
2828
buffer<T, Dimensions, AllocatorT, void>
29-
make_buffer_helper(pi_native_handle Handle, const context &Ctx, event Evt) {
30-
return buffer<T, Dimensions, AllocatorT, void>(Handle, Ctx, Evt);
29+
make_buffer_helper(pi_native_handle Handle, const context &Ctx, event Evt = {},
30+
bool OwnNativeHandle = true) {
31+
return buffer<T, Dimensions, AllocatorT, void>(Handle, Ctx, OwnNativeHandle,
32+
Evt);
3133
}
3234
} // namespace detail
3335

@@ -314,14 +316,11 @@ class buffer {
314316
const detail::code_location CodeLoc = detail::code_location::current())
315317
: Range{0} {
316318

317-
size_t BufSize = detail::SYCLMemObjT::getBufSizeForContext(
318-
detail::getSyclObjImpl(SyclContext), MemObject);
319-
320-
Range[0] = BufSize / sizeof(T);
321319
impl = std::make_shared<detail::buffer_impl>(
322-
detail::pi::cast<pi_native_handle>(MemObject), SyclContext, BufSize,
320+
detail::pi::cast<pi_native_handle>(MemObject), SyclContext,
323321
make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT>>(),
324-
AvailableEvent);
322+
/* OwnNativeHandle */ true, AvailableEvent);
323+
Range[0] = impl->getSize() / sizeof(T);
325324
impl->constructorNotification(CodeLoc, (void *)impl.get(), &MemObject,
326325
(const void *)typeid(T).name(), dimensions,
327326
sizeof(T), rangeToArray(Range).data());
@@ -531,7 +530,7 @@ class buffer {
531530
friend class accessor;
532531
template <typename HT, int HDims, typename HAllocT>
533532
friend buffer<HT, HDims, HAllocT, void>
534-
detail::make_buffer_helper(pi_native_handle, const context &, event);
533+
detail::make_buffer_helper(pi_native_handle, const context &, event, bool);
535534
range<dimensions> Range;
536535
// Offset field specifies the origin of the sub buffer inside the parent
537536
// buffer
@@ -541,18 +540,15 @@ class buffer {
541540
// Interop constructor
542541
template <int N = dimensions, typename = EnableIfOneDimension<N>>
543542
buffer(pi_native_handle MemObject, const context &SyclContext,
544-
event AvailableEvent = {},
543+
bool OwnNativeHandle, event AvailableEvent = {},
545544
const detail::code_location CodeLoc = detail::code_location::current())
546545
: Range{0} {
547546

548-
size_t BufSize = detail::SYCLMemObjT::getBufSizeForContext(
549-
detail::getSyclObjImpl(SyclContext), MemObject);
550-
551-
Range[0] = BufSize / sizeof(T);
552547
impl = std::make_shared<detail::buffer_impl>(
553-
MemObject, SyclContext, BufSize,
548+
MemObject, SyclContext,
554549
make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT>>(),
555-
AvailableEvent);
550+
OwnNativeHandle, AvailableEvent);
551+
Range[0] = impl->getSize() / sizeof(T);
556552
impl->constructorNotification(CodeLoc, (void *)impl.get(), &MemObject,
557553
(const void *)typeid(T).name(), dimensions,
558554
sizeof(T), rangeToArray(Range).data());

sycl/include/CL/sycl/detail/backend_traits_level_zero.hpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ template <> struct BackendInput<backend::ext_oneapi_level_zero, queue> {
138138
};
139139
};
140140

141+
template <typename DataT, int Dimensions, typename AllocatorT>
142+
struct BackendInput<backend::ext_oneapi_level_zero,
143+
buffer<DataT, Dimensions, AllocatorT>> {
144+
struct type {
145+
void *NativeHandle;
146+
ext::oneapi::level_zero::ownership Ownership{
147+
ext::oneapi::level_zero::ownership::transfer};
148+
};
149+
};
150+
151+
template <typename DataT, int Dimensions, typename AllocatorT>
152+
struct BackendReturn<backend::ext_oneapi_level_zero,
153+
buffer<DataT, Dimensions, AllocatorT>> {
154+
using type = void *;
155+
};
156+
141157
template <> struct BackendReturn<backend::ext_oneapi_level_zero, queue> {
142158
using type = ze_command_queue_handle_t;
143159
};
@@ -195,7 +211,7 @@ template <> struct InteropFeatureSupportMap<backend::ext_oneapi_level_zero> {
195211
static constexpr bool MakeEvent = true;
196212
static constexpr bool MakeKernelBundle = true;
197213
static constexpr bool MakeKernel = true;
198-
static constexpr bool MakeBuffer = false;
214+
static constexpr bool MakeBuffer = true;
199215
};
200216

201217
} // namespace detail

sycl/include/CL/sycl/detail/buffer_impl.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ class __SYCL_EXPORT buffer_impl final : public SYCLMemObjT {
138138
BaseT::handleHostData(First, Last, RequiredAlign);
139139
}
140140

141+
buffer_impl(cl_mem MemObject, const context &SyclContext,
142+
std::unique_ptr<SYCLMemObjAllocator> Allocator,
143+
event AvailableEvent)
144+
: buffer_impl(pi::cast<pi_native_handle>(MemObject), SyclContext,
145+
std::move(Allocator), /*OwnNativeHandle*/ true,
146+
std::move(AvailableEvent)) {}
147+
148+
buffer_impl(pi_native_handle MemObject, const context &SyclContext,
149+
std::unique_ptr<SYCLMemObjAllocator> Allocator,
150+
bool OwnNativeHandle, event AvailableEvent)
151+
: BaseT(MemObject, SyclContext, OwnNativeHandle,
152+
std::move(AvailableEvent), std::move(Allocator)) {}
153+
154+
// TODO: remove the following 2 constructors when it is allowed to break ABI.
141155
buffer_impl(cl_mem MemObject, const context &SyclContext,
142156
const size_t SizeInBytes,
143157
std::unique_ptr<SYCLMemObjAllocator> Allocator,

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

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@
4242
// piextEventCreateWithNativeHandle
4343
// 6.8 Added new ownership argument to piextProgramCreateWithNativeHandle. Added
4444
// piQueueFlush function.
45+
// 7.9 Added new context and ownership arguments to
46+
// piextMemCreateWithNativeHandle.
4547
//
4648
#include "CL/cl.h"
47-
#define _PI_H_VERSION_MAJOR 6
48-
#define _PI_H_VERSION_MINOR 8
49+
#define _PI_H_VERSION_MAJOR 7
50+
#define _PI_H_VERSION_MINOR 9
4951

5052
#define _PI_STRING_HELPER(a) #a
5153
#define _PI_CONCAT(a, b) _PI_STRING_HELPER(a.b)
@@ -941,6 +943,14 @@ typedef struct {
941943

942944
using pi_image_format = _pi_image_format;
943945
using pi_image_desc = _pi_image_desc;
946+
947+
typedef enum {
948+
PI_MEM_CONTEXT = CL_MEM_CONTEXT,
949+
PI_MEM_SIZE = CL_MEM_SIZE
950+
} _pi_mem_info;
951+
952+
using pi_mem_info = _pi_mem_info;
953+
944954
//
945955
// Following section contains SYCL RT Plugin Interface (PI) functions.
946956
// They are 3 distinct categories:
@@ -1163,10 +1173,9 @@ __SYCL_EXPORT pi_result piMemImageCreate(pi_context context, pi_mem_flags flags,
11631173
const pi_image_desc *image_desc,
11641174
void *host_ptr, pi_mem *ret_mem);
11651175

1166-
__SYCL_EXPORT pi_result piMemGetInfo(
1167-
pi_mem mem,
1168-
cl_mem_info param_name, // TODO: untie from OpenCL
1169-
size_t param_value_size, void *param_value, size_t *param_value_size_ret);
1176+
__SYCL_EXPORT pi_result piMemGetInfo(pi_mem mem, pi_mem_info param_name,
1177+
size_t param_value_size, void *param_value,
1178+
size_t *param_value_size_ret);
11701179

11711180
__SYCL_EXPORT pi_result piMemImageGetInfo(pi_mem image,
11721181
pi_image_info param_name,
@@ -1193,9 +1202,13 @@ __SYCL_EXPORT pi_result piextMemGetNativeHandle(pi_mem mem,
11931202
/// NOTE: The created PI object takes ownership of the native handle.
11941203
///
11951204
/// \param nativeHandle is the native handle to create PI mem from.
1205+
/// \param context The PI context of the memory allocation.
1206+
/// \param ownNativeHandle Indicates if we own the native memory handle or it
1207+
/// came from interop that asked to not transfer the ownership to SYCL RT.
11961208
/// \param mem is the PI mem created from the native handle.
1197-
__SYCL_EXPORT pi_result
1198-
piextMemCreateWithNativeHandle(pi_native_handle nativeHandle, pi_mem *mem);
1209+
__SYCL_EXPORT pi_result piextMemCreateWithNativeHandle(
1210+
pi_native_handle nativeHandle, pi_context context, bool ownNativeHandle,
1211+
pi_mem *mem);
11991212

12001213
//
12011214
// Program
@@ -1619,7 +1632,7 @@ typedef enum {
16191632
PI_MEM_ALLOC_BASE_PTR = CL_MEM_ALLOC_BASE_PTR_INTEL,
16201633
PI_MEM_ALLOC_SIZE = CL_MEM_ALLOC_SIZE_INTEL,
16211634
PI_MEM_ALLOC_DEVICE = CL_MEM_ALLOC_DEVICE_INTEL,
1622-
} _pi_mem_info;
1635+
} _pi_mem_alloc_info;
16231636

16241637
typedef enum {
16251638
PI_MEM_TYPE_UNKNOWN = CL_MEM_TYPE_UNKNOWN_INTEL,
@@ -1637,7 +1650,7 @@ typedef enum : pi_bitfield {
16371650

16381651
using pi_usm_capability_query = _pi_usm_capability_query;
16391652
using pi_usm_capabilities = _pi_usm_capabilities;
1640-
using pi_mem_info = _pi_mem_info;
1653+
using pi_mem_alloc_info = _pi_mem_alloc_info;
16411654
using pi_usm_type = _pi_usm_type;
16421655
using pi_usm_migration_flags = _pi_usm_migration_flags;
16431656

@@ -1766,7 +1779,7 @@ __SYCL_EXPORT pi_result piextUSMEnqueueMemAdvise(pi_queue queue,
17661779
/// \param param_value is the result
17671780
/// \param param_value_size_ret is how many bytes were written
17681781
__SYCL_EXPORT pi_result piextUSMGetMemAllocInfo(
1769-
pi_context context, const void *ptr, pi_mem_info param_name,
1782+
pi_context context, const void *ptr, pi_mem_alloc_info param_name,
17701783
size_t param_value_size, void *param_value, size_t *param_value_size_ret);
17711784

17721785
/// API to get Plugin internal data, opaque to SYCL RT. Some devices whose

sycl/include/CL/sycl/detail/sycl_mem_obj_t.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ class __SYCL_EXPORT SYCLMemObjT : public SYCLMemObjI {
9090
: SYCLMemObjT(MemObject, SyclContext, /*SizeInBytes*/ 0, AvailableEvent,
9191
std::move(Allocator)) {}
9292

93+
SYCLMemObjT(pi_native_handle MemObject, const context &SyclContext,
94+
bool OwmNativeHandle, event AvailableEvent,
95+
std::unique_ptr<SYCLMemObjAllocator> Allocator);
96+
9397
virtual ~SYCLMemObjT() = default;
9498

9599
const plugin &getPlugin() const;
@@ -336,10 +340,9 @@ class __SYCL_EXPORT SYCLMemObjT : public SYCLMemObjI {
336340
EventImplPtr MInteropEvent;
337341
// Context passed by user to interoperability constructor.
338342
ContextImplPtr MInteropContext;
339-
// OpenCL's memory object handle passed by user to interoperability
343+
// Native backend memory object handle passed by user to interoperability
340344
// constructor.
341-
// TODO update this member to support other backends.
342-
cl_mem MInteropMemObject;
345+
RT::PiMem MInteropMemObject;
343346
// Indicates whether memory object is created using interoperability
344347
// constructor or not.
345348
bool MOpenCLInterop;

sycl/include/CL/sycl/feature_test.hpp.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ namespace sycl {
6969
#define SYCL_EXT_INTEL_MEM_CHANNEL_PROPERTY 1
7070
#define SYCL_EXT_INTEL_USM_ADDRESS_SPACES 1
7171
#define SYCL_EXT_INTEL_RUNTIME_BUFFER_LOCATION 1
72-
#define SYCL_EXT_ONEAPI_BACKEND_LEVEL_ZERO 1
72+
#define SYCL_EXT_ONEAPI_BACKEND_LEVEL_ZERO 2
7373
#define SYCL_EXT_ONEAPI_USM_DEVICE_READ_ONLY 1
7474
#cmakedefine01 SYCL_BUILD_PI_CUDA
7575
#if SYCL_BUILD_PI_CUDA

0 commit comments

Comments
 (0)