Skip to content

Commit

Permalink
[UR] Replace some UR retains with CL retains
Browse files Browse the repository at this point in the history
At various points, OpenCL native handles need to be retained to ensure
SYCL semantics. Previously, this relied on the fact that UR handles were
typecast CL handles and shared the same reference count.

However, the SYCL RT shouldn't assume this, so instead we call the
appropriate (dynamically looked-up) CL functions on the native handles
instead.

This is in preperation for oneapi-src/unified-runtime#1176 .

This change should also have no observable effect for SYCL code; there
is no change in lifetime semantics.
  • Loading branch information
RossBrunton committed Feb 14, 2025
1 parent 254dd3b commit cd73105
Show file tree
Hide file tree
Showing 13 changed files with 47 additions and 28 deletions.
10 changes: 10 additions & 0 deletions sycl/include/sycl/detail/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#pragma once

#include <dlfcn.h>
#include <sycl/detail/defines_elementary.hpp> // for __SYCL_ALWAYS_INLINE
#include <sycl/detail/export.hpp> // for __SYCL_EXPORT

Expand Down Expand Up @@ -379,6 +380,15 @@ static constexpr std::array<T, N> RepeatValue(const T &Arg) {
// classes.
struct AllowCTADTag;

template <typename fn> fn *dynLookupFunction(const char *name) {
auto *retVal = reinterpret_cast<fn *>(dlsym(RTLD_DEFAULT, name));
assert(retVal);
return retVal;
}

#define _DYN_LOOKUP_FUNCTION(FN) \
(::sycl::_V1::detail::dynLookupFunction<decltype(FN)>(#FN))

} // namespace detail
} // namespace _V1
} // namespace sycl
6 changes: 3 additions & 3 deletions sycl/source/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ __SYCL_EXPORT event make_event(ur_native_handle_t NativeHandle,
std::make_shared<event_impl>(UrEvent, Context));

if (Backend == backend::opencl)
Adapter->call<UrApiKind::urEventRetain>(UrEvent);
_DYN_LOOKUP_FUNCTION(clRetainEvent)(ur::cast<cl_event>(NativeHandle));
return Event;
}

Expand All @@ -205,7 +205,7 @@ make_kernel_bundle(ur_native_handle_t NativeHandle,
"urProgramCreateWithNativeHandle resulted in a null program handle.");

if (ContextImpl->getBackend() == backend::opencl)
Adapter->call<UrApiKind::urProgramRetain>(UrProgram);
_DYN_LOOKUP_FUNCTION(clRetainProgram)(ur::cast<cl_program>(NativeHandle));

std::vector<ur_device_handle_t> ProgramDevices;
uint32_t NumDevices = 0;
Expand Down Expand Up @@ -352,7 +352,7 @@ kernel make_kernel(const context &TargetContext,
&UrKernel);

if (Backend == backend::opencl)
Adapter->call<UrApiKind::urKernelRetain>(UrKernel);
_DYN_LOOKUP_FUNCTION(clRetainKernel)(ur::cast<cl_kernel>(NativeHandle));

// Construct the SYCL queue from UR queue.
return detail::createSyclObjFromImpl<kernel>(
Expand Down
5 changes: 3 additions & 2 deletions sycl/source/detail/context_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,11 @@ context_impl::findMatchingDeviceImpl(ur_device_handle_t &DeviceUR) const {

ur_native_handle_t context_impl::getNative() const {
const auto &Adapter = getAdapter();
if (getBackend() == backend::opencl)
Adapter->call<UrApiKind::urContextRetain>(getHandleRef());
ur_native_handle_t Handle;
Adapter->call<UrApiKind::urContextGetNativeHandle>(getHandleRef(), &Handle);
if (getBackend() == backend::opencl) {
_DYN_LOOKUP_FUNCTION(clRetainContext)(ur::cast<cl_context>(Handle));
}
return Handle;
}

Expand Down
6 changes: 4 additions & 2 deletions sycl/source/detail/device_image_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,13 @@ class device_image_impl {
const auto &ContextImplPtr = detail::getSyclObjImpl(MContext);
const AdapterPtr &Adapter = ContextImplPtr->getAdapter();

if (ContextImplPtr->getBackend() == backend::opencl)
Adapter->call<UrApiKind::urProgramRetain>(MProgram);
ur_native_handle_t NativeProgram = 0;
Adapter->call<UrApiKind::urProgramGetNativeHandle>(MProgram,
&NativeProgram);
if (ContextImplPtr->getBackend() == backend::opencl) {
auto *RetainFun = _DYN_LOOKUP_FUNCTION(clRetainProgram);
RetainFun(ur::cast<cl_program>(NativeProgram));
}

return NativeProgram;
}
Expand Down
7 changes: 4 additions & 3 deletions sycl/source/detail/device_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ bool device_impl::is_affinity_supported(

cl_device_id device_impl::get() const {
// TODO catch an exception and put it to list of asynchronous exceptions
getAdapter()->call<UrApiKind::urDeviceRetain>(MDevice);
_DYN_LOOKUP_FUNCTION(clRetainDevice)(ur::cast<cl_device_id>(getNative()));
return ur::cast<cl_device_id>(getNative());
}

Expand Down Expand Up @@ -345,10 +345,11 @@ std::vector<device> device_impl::create_sub_devices() const {

ur_native_handle_t device_impl::getNative() const {
auto Adapter = getAdapter();
if (getBackend() == backend::opencl)
Adapter->call<UrApiKind::urDeviceRetain>(getHandleRef());
ur_native_handle_t Handle;
Adapter->call<UrApiKind::urDeviceGetNativeHandle>(getHandleRef(), &Handle);
if (getBackend() == backend::opencl) {
_DYN_LOOKUP_FUNCTION(clRetainDevice)(ur::cast<cl_device_id>(Handle));
}
return Handle;
}

Expand Down
4 changes: 2 additions & 2 deletions sycl/source/detail/event_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,10 +500,10 @@ ur_native_handle_t event_impl::getNative() {
this->setHandle(UREvent);
Handle = UREvent;
}
if (MContext->getBackend() == backend::opencl)
Adapter->call<UrApiKind::urEventRetain>(Handle);
ur_native_handle_t OutHandle;
Adapter->call<UrApiKind::urEventGetNativeHandle>(Handle, &OutHandle);
if (MContext->getBackend() == backend::opencl)
_DYN_LOOKUP_FUNCTION(clRetainEvent)(ur::cast<cl_event>(OutHandle));
return OutHandle;
}

Expand Down
9 changes: 5 additions & 4 deletions sycl/source/detail/kernel_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ class kernel_impl {
///
/// \return a valid cl_kernel instance
cl_kernel get() const {
getAdapter()->call<UrApiKind::urKernelRetain>(MKernel);
ur_native_handle_t nativeHandle = 0;
getAdapter()->call<UrApiKind::urKernelGetNativeHandle>(MKernel,
&nativeHandle);
_DYN_LOOKUP_FUNCTION(clRetainKernel)(ur::cast<cl_kernel>(nativeHandle));
return ur::cast<cl_kernel>(nativeHandle);
}

Expand Down Expand Up @@ -179,12 +179,13 @@ class kernel_impl {
ur_native_handle_t getNative() const {
const AdapterPtr &Adapter = MContext->getAdapter();

if (MContext->getBackend() == backend::opencl)
Adapter->call<UrApiKind::urKernelRetain>(MKernel);

ur_native_handle_t NativeKernel = 0;
Adapter->call<UrApiKind::urKernelGetNativeHandle>(MKernel, &NativeKernel);

if (MContext->getBackend() == backend::opencl) {
_DYN_LOOKUP_FUNCTION(clRetainKernel)(ur::cast<cl_kernel>(NativeKernel));
}

return NativeKernel;
}

Expand Down
6 changes: 4 additions & 2 deletions sycl/source/detail/queue_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,15 +731,17 @@ void queue_impl::destructorNotification() {

ur_native_handle_t queue_impl::getNative(int32_t &NativeHandleDesc) const {
const AdapterPtr &Adapter = getAdapter();
if (getContextImplPtr()->getBackend() == backend::opencl)
Adapter->call<UrApiKind::urQueueRetain>(MQueues[0]);
ur_native_handle_t Handle{};
ur_queue_native_desc_t UrNativeDesc{UR_STRUCTURE_TYPE_QUEUE_NATIVE_DESC,
nullptr, nullptr};
UrNativeDesc.pNativeData = &NativeHandleDesc;

Adapter->call<UrApiKind::urQueueGetNativeHandle>(MQueues[0], &UrNativeDesc,
&Handle);
if (getContextImplPtr()->getBackend() == backend::opencl) {
_DYN_LOOKUP_FUNCTION(clRetainCommandQueue)
(ur::cast<cl_command_queue>(Handle));
}
return Handle;
}

Expand Down
5 changes: 3 additions & 2 deletions sycl/source/detail/queue_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class queue_impl {
/// \param PropList is a list of properties to use for queue construction.
queue_impl(const DeviceImplPtr &Device, const async_handler &AsyncHandler,
const property_list &PropList)
: queue_impl(Device, getDefaultOrNew(Device), AsyncHandler, PropList) {};
: queue_impl(Device, getDefaultOrNew(Device), AsyncHandler, PropList){};

/// Constructs a SYCL queue with an async_handler and property_list provided
/// form a device and a context.
Expand Down Expand Up @@ -273,10 +273,11 @@ class queue_impl {
/// \return an OpenCL interoperability queue handle.

cl_command_queue get() {
getAdapter()->call<UrApiKind::urQueueRetain>(MQueues[0]);
ur_native_handle_t nativeHandle = 0;
getAdapter()->call<UrApiKind::urQueueGetNativeHandle>(MQueues[0], nullptr,
&nativeHandle);
_DYN_LOOKUP_FUNCTION(clRetainCommandQueue)
(ur::cast<cl_command_queue>(nativeHandle));
return ur::cast<cl_command_queue>(nativeHandle);
}

Expand Down
10 changes: 6 additions & 4 deletions sycl/source/detail/sycl_mem_obj_t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ SYCLMemObjT::SYCLMemObjT(ur_native_handle_t MemObject,
make_error_code(errc::invalid),
"Input context must be the same as the context of cl_mem");

if (MInteropContext->getBackend() == backend::opencl)
Adapter->call<UrApiKind::urMemRetain>(MInteropMemObject);
if (MInteropContext->getBackend() == backend::opencl) {
_DYN_LOOKUP_FUNCTION(clRetainMemObject)(ur::cast<cl_mem>(MemObject));
}
}

ur_mem_type_t getImageType(int Dimensions) {
Expand Down Expand Up @@ -112,8 +113,9 @@ SYCLMemObjT::SYCLMemObjT(ur_native_handle_t MemObject,
make_error_code(errc::invalid),
"Input context must be the same as the context of cl_mem");

if (MInteropContext->getBackend() == backend::opencl)
Adapter->call<UrApiKind::urMemRetain>(MInteropMemObject);
if (MInteropContext->getBackend() == backend::opencl) {
_DYN_LOOKUP_FUNCTION(clRetainMemObject)(ur::cast<cl_mem>(MemObject));
}
}

void SYCLMemObjT::releaseMem(ContextImplPtr Context, void *MemAllocation) {
Expand Down
2 changes: 1 addition & 1 deletion sycl/source/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ device::device(cl_device_id DeviceId) {
auto Platform =
detail::platform_impl::getPlatformFromUrDevice(Device, Adapter);
impl = Platform->getOrMakeDeviceImpl(Device, Platform);
Adapter->call<detail::UrApiKind::urDeviceRetain>(impl->getHandleRef());
_DYN_LOOKUP_FUNCTION(clRetainDevice)(DeviceId);
}

device::device(const device_selector &deviceSelector) {
Expand Down
3 changes: 1 addition & 2 deletions sycl/source/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ event::event(cl_event ClEvent, const context &SyclContext)
// This is a special interop constructor for OpenCL, so the event must be
// retained.
// TODO(pi2ur): Don't just cast from cl_event above
impl->getAdapter()->call<detail::UrApiKind::urEventRetain>(
detail::ur::cast<ur_event_handle_t>(ClEvent));
_DYN_LOOKUP_FUNCTION(clRetainEvent)(ClEvent);
}

bool event::operator==(const event &rhs) const { return rhs.impl == impl; }
Expand Down
2 changes: 1 addition & 1 deletion sycl/source/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ kernel::kernel(cl_kernel ClKernel, const context &SyclContext) {
// This is a special interop constructor for OpenCL, so the kernel must be
// retained.
if (get_backend() == backend::opencl) {
impl->getAdapter()->call<detail::UrApiKind::urKernelRetain>(hKernel);
_DYN_LOOKUP_FUNCTION(clRetainKernel)(ClKernel);
}
}

Expand Down

0 comments on commit cd73105

Please sign in to comment.