Skip to content

Commit 5e9d07b

Browse files
authored
[SYCL][HIP] Implemented supported make_* interop functions. (#10526)
This PR adds missing functions in the hip backend to allow for interoperability in programs that create sycl objects from native hip objects. The new function implementations are: - `make_device` - `make_queue` - `make_event` Note that it would really make sense for #10491 to be merged first because this PR makes the same code change in pi2ur, for a fix that is attributed to #10491. --------- Signed-off-by: Jack Kirk <[email protected]>
1 parent 77b794b commit 5e9d07b

File tree

10 files changed

+132
-34
lines changed

10 files changed

+132
-34
lines changed

sycl/include/sycl/backend.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,11 @@ std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeQueue == true,
298298
make_queue(const typename backend_traits<Backend>::template input_type<queue>
299299
&BackendObject,
300300
const context &TargetContext, const async_handler Handler = {}) {
301+
auto KeepOwnership =
302+
Backend == backend::ext_oneapi_cuda || Backend == backend::ext_oneapi_hip;
301303
return detail::make_queue(detail::pi::cast<pi_native_handle>(BackendObject),
302-
false, TargetContext, nullptr, false, {}, Handler,
303-
Backend);
304+
false, TargetContext, nullptr, KeepOwnership, {},
305+
Handler, Backend);
304306
}
305307

306308
template <backend Backend>

sycl/include/sycl/detail/backend_traits_hip.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ template <> struct BackendReturn<backend::ext_oneapi_hip, queue> {
9595
using type = HIPstream;
9696
};
9797

98+
template <> struct InteropFeatureSupportMap<backend::ext_oneapi_hip> {
99+
static constexpr bool MakePlatform = false;
100+
static constexpr bool MakeDevice = true;
101+
static constexpr bool MakeContext = false;
102+
static constexpr bool MakeQueue = true;
103+
static constexpr bool MakeEvent = true;
104+
static constexpr bool MakeBuffer = false;
105+
static constexpr bool MakeKernel = false;
106+
static constexpr bool MakeKernelBundle = false;
107+
static constexpr bool MakeImage = false;
108+
};
109+
98110
} // namespace detail
99111
} // namespace _V1
100112
} // namespace sycl

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ inline namespace _V1 {
1616
template <>
1717
inline backend_return_t<backend::ext_oneapi_hip, device>
1818
get_native<backend::ext_oneapi_hip, device>(const device &Obj) {
19-
// TODO use SYCL 2020 exception when implemented
19+
// TODO swap with SYCL 2020 exception when in ABI-break window
2020
if (Obj.get_backend() != backend::ext_oneapi_hip) {
2121
throw sycl::runtime_error(errc::backend_mismatch, "Backends mismatch",
2222
PI_ERROR_INVALID_OPERATION);
@@ -27,5 +27,23 @@ get_native<backend::ext_oneapi_hip, device>(const device &Obj) {
2727
Obj.getNative());
2828
}
2929

30+
template <>
31+
inline device make_device<backend::ext_oneapi_hip>(
32+
const backend_input_t<backend::ext_oneapi_hip, device> &BackendObject) {
33+
auto devs = device::get_devices(info::device_type::gpu);
34+
for (auto &dev : devs) {
35+
if (dev.get_backend() == backend::ext_oneapi_hip &&
36+
BackendObject == get_native<backend::ext_oneapi_hip>(dev)) {
37+
return dev;
38+
}
39+
}
40+
// The ext_oneapi_hip platform(s) adds all n available devices where n
41+
// is returned from call to `hipGetDeviceCount`.
42+
// Hence if this code is reached then the requested device ordinal must
43+
// not be visible to the driver.
44+
throw sycl::exception(make_error_code(errc::invalid),
45+
"Native device has an invalid ordinal.");
46+
}
47+
3048
} // namespace _V1
3149
} // namespace sycl

sycl/plugins/unified_runtime/ur/adapters/cuda/queue.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ UR_APIEXPORT ur_result_t UR_APICALL urQueueCreateWithNativeHandle(
242242
ur_native_handle_t hNativeQueue, ur_context_handle_t hContext,
243243
ur_device_handle_t hDevice, const ur_queue_native_properties_t *pProperties,
244244
ur_queue_handle_t *phQueue) {
245-
(void)pProperties;
246245
(void)hDevice;
247246

248247
unsigned int CuFlags;
@@ -263,13 +262,14 @@ UR_APIEXPORT ur_result_t UR_APICALL urQueueCreateWithNativeHandle(
263262

264263
// Create queue and set num_compute_streams to 1, as computeCuStreams has
265264
// valid stream
266-
*phQueue = new ur_queue_handle_t_{std::move(ComputeCuStreams),
267-
std::move(TransferCuStreams),
268-
hContext,
269-
hContext->getDevice(),
270-
CuFlags,
271-
Flags,
272-
/*backend_owns*/ false};
265+
*phQueue =
266+
new ur_queue_handle_t_{std::move(ComputeCuStreams),
267+
std::move(TransferCuStreams),
268+
hContext,
269+
hContext->getDevice(),
270+
CuFlags,
271+
Flags,
272+
/*backend_owns*/ pProperties->isNativeHandleOwned};
273273
(*phQueue)->NumComputeStreams = 1;
274274

275275
return Return;

sycl/plugins/unified_runtime/ur/adapters/hip/event.cpp

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ ur_event_handle_t_::ur_event_handle_t_(ur_command_t Type,
1515
ur_context_handle_t Context,
1616
ur_queue_handle_t Queue,
1717
hipStream_t Stream, uint32_t StreamToken)
18-
: CommandType{Type}, RefCount{1}, HasBeenWaitedOn{false}, IsRecorded{false},
19-
IsStarted{false}, StreamToken{StreamToken}, EvEnd{nullptr},
20-
EvStart{nullptr}, EvQueued{nullptr}, Queue{Queue}, Stream{Stream},
21-
Context{Context} {
18+
: CommandType{Type}, RefCount{1}, HasOwnership{true},
19+
HasBeenWaitedOn{false}, IsRecorded{false}, IsStarted{false},
20+
StreamToken{StreamToken}, EvEnd{nullptr}, EvStart{nullptr},
21+
EvQueued{nullptr}, Queue{Queue}, Stream{Stream}, Context{Context} {
2222

2323
bool ProfilingEnabled = Queue->URFlags & UR_QUEUE_FLAG_PROFILING_ENABLE;
2424

@@ -36,6 +36,15 @@ ur_event_handle_t_::ur_event_handle_t_(ur_command_t Type,
3636
urContextRetain(Context);
3737
}
3838

39+
ur_event_handle_t_::ur_event_handle_t_(ur_context_handle_t Context,
40+
hipEvent_t EventNative)
41+
: CommandType{UR_COMMAND_EVENTS_WAIT}, RefCount{1}, HasOwnership{false},
42+
HasBeenWaitedOn{false}, IsRecorded{false}, IsStarted{false},
43+
StreamToken{std::numeric_limits<uint32_t>::max()}, EvEnd{EventNative},
44+
EvStart{nullptr}, EvQueued{nullptr}, Queue{nullptr}, Context{Context} {
45+
urContextRetain(Context);
46+
}
47+
3948
ur_event_handle_t_::~ur_event_handle_t_() {
4049
if (Queue != nullptr) {
4150
urQueueRelease(Queue);
@@ -160,6 +169,9 @@ ur_result_t ur_event_handle_t_::wait() {
160169
}
161170

162171
ur_result_t ur_event_handle_t_::release() {
172+
if (!backendHasOwnership())
173+
return UR_RESULT_SUCCESS;
174+
163175
assert(Queue != nullptr);
164176
UR_CHECK_ERROR(hipEventDestroy(EvEnd));
165177

@@ -302,15 +314,18 @@ UR_APIEXPORT ur_result_t UR_APICALL urEventGetNativeHandle(
302314
}
303315

304316
/// Created a UR event object from a HIP event handle.
305-
/// TODO: Implement this.
306-
/// NOTE: The created UR object takes ownership of the native handle.
317+
/// NOTE: The created UR object doesn't take ownership of the native handle.
307318
///
308319
/// \param[in] hNativeEvent The native handle to create UR event object from.
309320
/// \param[out] phEvent Set to the UR event object created from native handle.
310-
///
311-
/// \return UR_RESULT_ERROR_UNSUPPORTED_FEATURE
312321
UR_APIEXPORT ur_result_t UR_APICALL urEventCreateWithNativeHandle(
313-
ur_native_handle_t, ur_context_handle_t,
314-
const ur_event_native_properties_t *, ur_event_handle_t *) {
315-
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
322+
ur_native_handle_t hNativeEvent, ur_context_handle_t hContext,
323+
const ur_event_native_properties_t *pProperties,
324+
ur_event_handle_t *phEvent) {
325+
std::ignore = pProperties;
326+
327+
*phEvent = ur_event_handle_t_::makeWithNative(
328+
hContext, reinterpret_cast<hipEvent_t>(hNativeEvent));
329+
330+
return UR_RESULT_SUCCESS;
316331
}

sycl/plugins/unified_runtime/ur/adapters/hip/event.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ struct ur_event_handle_t_ {
6060

6161
uint32_t getEventId() const noexcept { return EventId; }
6262

63+
bool backendHasOwnership() const noexcept { return HasOwnership; }
64+
6365
// Returns the counter time when the associated command(s) were enqueued
6466
uint64_t getQueuedTime() const;
6567

@@ -77,6 +79,11 @@ struct ur_event_handle_t_ {
7779
StreamToken);
7880
}
7981

82+
static ur_event_handle_t makeWithNative(ur_context_handle_t context,
83+
hipEvent_t eventNative) {
84+
return new ur_event_handle_t_(context, eventNative);
85+
}
86+
8087
ur_result_t release();
8188

8289
~ur_event_handle_t_();
@@ -88,10 +95,16 @@ struct ur_event_handle_t_ {
8895
ur_queue_handle_t Queue, hipStream_t Stream,
8996
uint32_t StreamToken);
9097

98+
// This constructor is private to force programmers to use the
99+
// makeWithNative for event interop
100+
ur_event_handle_t_(ur_context_handle_t Context, hipEvent_t EventNative);
101+
91102
ur_command_t CommandType; // The type of command associated with event.
92103

93104
std::atomic_uint32_t RefCount; // Event reference count.
94105

106+
bool HasOwnership; // Signifies if event owns the native type.
107+
95108
bool HasBeenWaitedOn; // Signifies whether the event has been waited
96109
// on through a call to wait(), which implies
97110
// that it has completed.

sycl/plugins/unified_runtime/ur/adapters/hip/queue.cpp

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ UR_APIEXPORT ur_result_t UR_APICALL urQueueRelease(ur_queue_handle_t hQueue) {
193193
try {
194194
std::unique_ptr<ur_queue_handle_t_> QueueImpl(hQueue);
195195

196+
if (!hQueue->backendHasOwnership())
197+
return UR_RESULT_SUCCESS;
198+
196199
ScopedContext Active(hQueue->getContext()->getDevice());
197200

198201
hQueue->forEachStream([](hipStream_t S) {
@@ -252,19 +255,44 @@ urQueueGetNativeHandle(ur_queue_handle_t hQueue, ur_queue_native_desc_t *,
252255
}
253256

254257
/// Created a UR queue object from a HIP queue handle.
255-
/// TODO: Implement this.
256-
/// NOTE: The created UR object takes ownership of the native handle.
258+
/// NOTE: The created UR object doesn't takes ownership of the native handle.
257259
///
258260
/// \param[in] hNativeQueue The native handle to create UR queue object from.
259261
/// \param[in] hContext is the UR context of the queue.
260262
/// \param[out] phQueue Set to the UR queue object created from native handle.
261-
/// \param pProperties->isNativeHandleOwned tells if SYCL RT should assume the
262-
/// ownership of
263-
/// the native handle, if it can.
264-
///
265-
/// \return UR_RESULT_ERROR_UNSUPPORTED_FEATURE
266263
UR_APIEXPORT ur_result_t UR_APICALL urQueueCreateWithNativeHandle(
267-
ur_native_handle_t, ur_context_handle_t, ur_device_handle_t,
268-
const ur_queue_native_properties_t *, ur_queue_handle_t *) {
269-
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
264+
ur_native_handle_t hNativeQueue, ur_context_handle_t hContext,
265+
ur_device_handle_t hDevice, const ur_queue_native_properties_t *pProperties,
266+
ur_queue_handle_t *phQueue) {
267+
(void)hDevice;
268+
269+
unsigned int HIPFlags;
270+
hipStream_t HIPStream = reinterpret_cast<hipStream_t>(hNativeQueue);
271+
272+
auto Return = UR_CHECK_ERROR(hipStreamGetFlags(HIPStream, &HIPFlags));
273+
274+
ur_queue_flags_t Flags = 0;
275+
if (HIPFlags == hipStreamDefault)
276+
Flags = UR_QUEUE_FLAG_USE_DEFAULT_STREAM;
277+
else if (HIPFlags == hipStreamNonBlocking)
278+
Flags = UR_QUEUE_FLAG_SYNC_WITH_DEFAULT_STREAM;
279+
else
280+
detail::ur::die("Unknown hip stream");
281+
282+
std::vector<hipStream_t> ComputeHIPStreams(1, HIPStream);
283+
std::vector<hipStream_t> TransferHIPStreams(0);
284+
285+
// Create queue and set num_compute_streams to 1, as computeHIPStreams has
286+
// valid stream
287+
*phQueue =
288+
new ur_queue_handle_t_{std::move(ComputeHIPStreams),
289+
std::move(TransferHIPStreams),
290+
hContext,
291+
hContext->getDevice(),
292+
HIPFlags,
293+
Flags,
294+
/*backend_owns*/ pProperties->isNativeHandleOwned};
295+
(*phQueue)->NumComputeStreams = 1;
296+
297+
return Return;
270298
}

sycl/plugins/unified_runtime/ur/adapters/hip/queue.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,13 @@ struct ur_queue_handle_t_ {
4949
std::mutex ComputeStreamMutex;
5050
std::mutex TransferStreamMutex;
5151
std::mutex BarrierMutex;
52+
bool HasOwnership;
5253

5354
ur_queue_handle_t_(std::vector<native_type> &&ComputeStreams,
5455
std::vector<native_type> &&TransferStreams,
5556
ur_context_handle_t Context, ur_device_handle_t Device,
56-
unsigned int Flags, ur_queue_flags_t URFlags)
57+
unsigned int Flags, ur_queue_flags_t URFlags,
58+
bool BackendOwns = true)
5759
: ComputeStreams{std::move(ComputeStreams)},
5860
TransferStreams{std::move(TransferStreams)},
5961
DelayCompute(this->ComputeStreams.size(), false),
@@ -62,7 +64,7 @@ struct ur_queue_handle_t_ {
6264
Device{Device}, RefCount{1}, EventCount{0}, ComputeStreamIdx{0},
6365
TransferStreamIdx{0}, NumComputeStreams{0}, NumTransferStreams{0},
6466
LastSyncComputeStreams{0}, LastSyncTransferStreams{0}, Flags(Flags),
65-
URFlags(URFlags) {
67+
URFlags(URFlags), HasOwnership{BackendOwns} {
6668
urContextRetain(Context);
6769
urDeviceRetain(Device);
6870
}
@@ -235,4 +237,6 @@ struct ur_queue_handle_t_ {
235237
uint32_t getReferenceCount() const noexcept { return RefCount; }
236238

237239
uint32_t getNextEventId() noexcept { return ++EventCount; }
240+
241+
bool backendHasOwnership() const noexcept { return HasOwnership; }
238242
};

sycl/source/backend.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ static const PluginPtr &getPlugin(backend Backend) {
3737
return pi::getPlugin<backend::ext_oneapi_level_zero>();
3838
case backend::ext_oneapi_cuda:
3939
return pi::getPlugin<backend::ext_oneapi_cuda>();
40+
case backend::ext_oneapi_hip:
41+
return pi::getPlugin<backend::ext_oneapi_hip>();
4042
default:
4143
throw sycl::exception(sycl::make_error_code(sycl::errc::runtime),
4244
"getPlugin: Unsupported backend " +

sycl/test/basic_tests/interop-hip.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,9 @@ int main() {
5656
hip_event = get_native<backend::ext_oneapi_hip>(Event);
5757
hip_queue = get_native<backend::ext_oneapi_hip>(Queue);
5858

59+
device InteropDevice = make_device<backend::ext_oneapi_hip>(hip_device);
60+
event InteropEvent = make_event<backend::ext_oneapi_hip>(hip_event, Context);
61+
queue InteropQueue = make_queue<backend::ext_oneapi_hip>(hip_queue, Context);
62+
5963
return 0;
6064
}

0 commit comments

Comments
 (0)