-
Notifications
You must be signed in to change notification settings - Fork 792
[SYCL][Docs] Add sycl_ext_oneapi_inter_process_communication #20018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: sycl
Are you sure you want to change the base?
Changes from 25 commits
eec1fe5
e4aefbf
7c85049
6debadb
d3b6c56
29cbc37
baa805f
7170da9
ce89cfe
49ce33d
c3f139b
d1ba0de
4070634
5d5dc0f
db03d7b
0075694
7a332b9
ce651ce
acf286f
fa44def
7873e13
2001baa
3555827
68ea80e
d1d9a1a
01e3a65
3bf5099
ebdc9e3
02e9613
eeb0a8a
0103ab4
0f3b66f
31aa6a3
33d34a9
a1a7945
3bc26d0
6cb2cf3
7883b93
4410d55
63315d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
= sycl_ext_oneapi_inter_process_communication | ||
|
||
:source-highlighter: coderay | ||
:coderay-linenums-mode: table | ||
|
||
// This section needs to be after the document title. | ||
:doctype: book | ||
:toc2: | ||
:toc: left | ||
:encoding: utf-8 | ||
:lang: en | ||
:dpcpp: pass:[DPC++] | ||
:endnote: —{nbsp}end{nbsp}note | ||
|
||
// Set the default source code type in this document to C++, | ||
// for syntax highlighting purposes. This is needed because | ||
// docbook uses c++ and html5 uses cpp. | ||
:language: {basebackend@docbook:c++:cpp} | ||
|
||
|
||
== Notice | ||
|
||
[%hardbreaks] | ||
Copyright (C) 2025 Intel Corporation. All rights reserved. | ||
|
||
Khronos(R) is a registered trademark and SYCL(TM) and SPIR(TM) are trademarks | ||
of The Khronos Group Inc. OpenCL(TM) is a trademark of Apple Inc. used by | ||
permission by Khronos. | ||
|
||
|
||
== Contact | ||
|
||
To report problems with this extension, please open a new issue at: | ||
|
||
https://github.com/intel/llvm/issues | ||
|
||
|
||
== Dependencies | ||
|
||
This extension is written against the SYCL 2020 revision 10 specification. All | ||
references below to the "core SYCL specification" or to section numbers in the | ||
SYCL specification refer to that revision. | ||
|
||
|
||
== Status | ||
|
||
This is an experimental extension specification, intended to provide early | ||
access to features and gather community feedback. Interfaces defined in this | ||
specification are implemented in {dpcpp}, but they are not finalized and may | ||
change incompatibly in future versions of {dpcpp} without prior notice. | ||
*Shipping software products should not rely on APIs defined in this | ||
specification.* | ||
|
||
|
||
== Overview | ||
|
||
This extension adds the ability for SYCL programs to share device USM memory | ||
allocations between processes. This is done by the allocating process creating | ||
a new IPC memory handle through the new free frunctions and transferring the | ||
steffenlarsen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
returned handle data to the other processes. The other processes can use the | ||
handle data to retrieve the corresponding device USM memory. | ||
|
||
|
||
== Specification | ||
|
||
=== Feature test macro | ||
|
||
This extension provides a feature-test macro as described in the core SYCL | ||
specification. An implementation supporting this extension must predefine the | ||
macro `SYCL_EXT_ONEAPI_INTER_PROCESS_COMMUNICATION` to one of the values defined | ||
in the table below. Applications can test for the existence of this macro to | ||
determine if the implementation supports this feature, or applications can test | ||
the macro's value to determine which of the extension's features the | ||
implementation supports. | ||
|
||
[%header,cols="1,5"] | ||
|=== | ||
|Value | ||
|Description | ||
|
||
|1 | ||
|The APIs of this experimental extension are not versioned, so the | ||
feature-test macro always has this value. | ||
|=== | ||
|
||
steffenlarsen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
=== Extension to `enum class aspect` | ||
|
||
[source] | ||
---- | ||
namespace sycl { | ||
enum class aspect { | ||
... | ||
ext_oneapi_ipc_memory | ||
} | ||
} | ||
---- | ||
|
||
If a SYCL device has this aspect, that device supports `ipc_memory::get()` free | ||
function specified in the following section. | ||
|
||
|
||
=== Inter-process communicable memory | ||
|
||
|
||
This extension adds new free functions under the `ipc_memory` experimental | ||
namespace. | ||
|
||
``` | ||
namespace sycl::ext::oneapi::experimental::ipc_memory { | ||
|
||
using handle_data_t = std::vector<char>; | ||
gmlueck marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
handle_data_t get(void *ptr, const sycl::context &ctx); | ||
|
||
void put(handle_data_t &handle_data, const sycl::context &ctx); | ||
steffenlarsen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
static void *open(handle_data_t handle_data, const sycl::context &ctx, | ||
const sycl::device &dev); | ||
gmlueck marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
static void close(void *ptr, const sycl::context &ctx); | ||
|
||
} | ||
``` | ||
|
||
|==== | ||
a| | ||
[frame=all,grid=none] | ||
!==== | ||
a! | ||
[source] | ||
---- | ||
handle_data_t get(void *ptr, const sycl::context &ctx) | ||
---- | ||
!==== | ||
|
||
_Preconditions:_ `ptr` is a pointer to USM device memory on some device _D_ in | ||
context `ctx` and device _D_ returns `true` for | ||
`device::has(aspect::ext_oneapi_ipc_memory)`. | ||
gmlueck marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
_Returns:_ An IPC "handle" to this USM memory allocation. The bytes of this | ||
handle can be transferred to another process on the same system, and the other | ||
process can use the handle to get a pointer to the same USM allocation through a | ||
call to the `open()` function. | ||
steffenlarsen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
!==== | ||
a! | ||
[source] | ||
---- | ||
void put(handle_data_t &handle_data, const sycl::context &ctx) | ||
---- | ||
!==== | ||
|
||
_Preconditions:_ `handle_data` is the IPC "handle" to USM device memory that was | ||
returned from a call to get either in this process or in some other process on | ||
steffenlarsen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
the same system. The USM device memory has not yet been freed in this process. | ||
|
||
_Effects:_ Deallocates resources associated with the handle. These resources are | ||
automatically deallocated when the USM device memory is freed, so it is not | ||
strictly necessary to call the `put` function. | ||
gmlueck marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
!==== | ||
a! | ||
[source] | ||
---- | ||
static void *open(handle_data_t &handle_data, const sycl::context &ctx, | ||
const sycl::device &dev) | ||
---- | ||
!==== | ||
|
||
_Preconditions:_ `handle_data` is the IPC "handle" to USM device memory that was | ||
returned from a call to the `get` function either in this process or in some | ||
other process on the same system. That USM device memory is accessible on device | ||
`dev`. | ||
|
||
_Returns:_ A pointer to the same USM device memory represented by `handle_data`. | ||
This pointer can be used in any API taking a USM device memory pointer, except | ||
it cannot be passed to `sycl::free`. Instead, use the `close` function to free | ||
this memory pointer. | ||
gmlueck marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
_Throws:_ | ||
* An exception with the `errc::feature_not_supported` error code if device | ||
`dev` does not have `aspect::ext_oneapi_ipc_memory`. | ||
steffenlarsen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* An exception with the `errc::invalid` error code if the handle data | ||
`handle_data` has an unexpected number of bytes. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the number of bytes is correct, but the content is garbage? Can we broaden this exception like this:
That would also cover the case when the handle had the wrong number of bytes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am reluctant to promise an error code if handle data is corrupt. The byte size is something we can check at a SYCL/UR level, but the validity of the data is up to UMF to decide and the API documentation doesn't specify which error is returned if the data is off. Maybe a precondition? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should push this requirement down to the UMF and down to Level Zero if necessary. They should be able to define an error code for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will open an issue against UMF, but I think it might be tricky. What happens if the data looks correct to UMF, but using it causes UB or invalid access in the implementation? I suppose that's something they can look into though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UMF shouldn't look at the handle content at all. It should just pass it to the underlying driver API, and that API should return an error code if the handle content is invalid. This assumes that each driver is able to diagnose an error in such a case, but that seems quite reasonable to me. For example, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There may be some wrapper information in the UMF IPC handle, but I don't know the exact details. Maybe @vinser52 has some insight into this? |
||
|
||
!==== | ||
a! | ||
[source] | ||
---- | ||
static void close(void *ptr, const sycl::context &ctx) | ||
---- | ||
!==== | ||
|
||
steffenlarsen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_Effects:_ Closes a device USM pointer previously returned by a call to | ||
`open()`. | ||
|
||
|==== | ||
|
||
|
||
== Issues | ||
|
||
=== Level Zero file descriptor duplication dependency | ||
|
||
The IPC memory APIs in Level Zero on Linux currently requires the ability to | ||
duplicate file descriptors between processes. For security this is not allowed | ||
by default on Linux-based systems, so in order for the IPC memory APIs to work | ||
with Level Zero on Linux the user must either call `prctl(PR_SET_PTRACER, ...)` | ||
in the IPC handle owner process or enable the functionality globally using | ||
|
||
```bash | ||
sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" | ||
``` | ||
|
||
See also https://github.com/oneapi-src/unified-memory-framework/tree/main?tab=readme-ov-file#level-zero-memory-provider. | ||
|
||
|
||
=== Level Zero IPC memory Windows support | ||
|
||
The new IPC memory APIs are not currently supported on the Level Zero backend on | ||
Windows systems. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
//==------- ipc_memory.hpp --- SYCL inter-process communicable memory ------==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#pragma once | ||
|
||
#include <sycl/detail/defines_elementary.hpp> | ||
#include <sycl/detail/export.hpp> | ||
#include <sycl/detail/owner_less_base.hpp> | ||
#include <sycl/sycl_span.hpp> | ||
|
||
#include <memory> | ||
|
||
namespace sycl { | ||
inline namespace _V1 { | ||
|
||
class context; | ||
class device; | ||
|
||
namespace ext::oneapi::experimental::ipc_memory { | ||
|
||
using handle_data_t = std::vector<char>; | ||
|
||
__SYCL_EXPORT handle_data_t get(void *Ptr, const sycl::context &Ctx); | ||
|
||
__SYCL_EXPORT void put(handle_data_t &HandleData, const sycl::context &Ctx); | ||
|
||
__SYCL_EXPORT void *open(handle_data_t &HandleData, const sycl::context &Ctx, | ||
const sycl::device &Dev); | ||
|
||
__SYCL_EXPORT void close(void *Ptr, const sycl::context &Ctx); | ||
|
||
} // namespace ext::oneapi::experimental::ipc_memory | ||
} // namespace _V1 | ||
} // namespace sycl |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
//==------- ipc_memory.cpp --- SYCL inter-process communicable memory ------==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include <detail/adapter_impl.hpp> | ||
#include <detail/context_impl.hpp> | ||
#include <sycl/context.hpp> | ||
#include <sycl/ext/oneapi/experimental/ipc_memory.hpp> | ||
|
||
namespace sycl { | ||
inline namespace _V1 { | ||
namespace ext::oneapi::experimental::ipc_memory { | ||
|
||
__SYCL_EXPORT handle_data_t get(void *Ptr, const sycl::context &Ctx) { | ||
auto CtxImpl = sycl::detail::getSyclObjImpl(Ctx); | ||
sycl::detail::adapter_impl &Adapter = CtxImpl->getAdapter(); | ||
|
||
size_t HandleSize = 0; | ||
Adapter.call<sycl::detail::UrApiKind::urIPCGetMemHandleExp>( | ||
CtxImpl->getHandleRef(), Ptr, nullptr, &HandleSize); | ||
|
||
handle_data_t Res(HandleSize); | ||
Adapter.call<sycl::detail::UrApiKind::urIPCGetMemHandleExp>( | ||
CtxImpl->getHandleRef(), Ptr, Res.data(), nullptr); | ||
return Res; | ||
} | ||
|
||
__SYCL_EXPORT void put(handle_data_t &HandleData, const sycl::context &Ctx) { | ||
auto CtxImpl = sycl::detail::getSyclObjImpl(Ctx); | ||
sycl::detail::adapter_impl &Adapter = CtxImpl->getAdapter(); | ||
Adapter.call<sycl::detail::UrApiKind::urIPCPutMemHandleExp>( | ||
CtxImpl->getHandleRef(), HandleData.data()); | ||
} | ||
|
||
__SYCL_EXPORT void *open(handle_data_t &HandleData, const sycl::context &Ctx, | ||
const sycl::device &Dev) { | ||
if (!Dev.has(aspect::ext_oneapi_ipc_memory)) | ||
throw sycl::exception( | ||
sycl::make_error_code(errc::feature_not_supported), | ||
"Device does not support aspect::ext_oneapi_ipc_memory."); | ||
|
||
auto CtxImpl = sycl::detail::getSyclObjImpl(Ctx); | ||
sycl::detail::adapter_impl &Adapter = CtxImpl->getAdapter(); | ||
|
||
void *Ptr = nullptr; | ||
ur_result_t UrRes = | ||
Adapter.call_nocheck<sycl::detail::UrApiKind::urIPCOpenMemHandleExp>( | ||
CtxImpl->getHandleRef(), getSyclObjImpl(Dev)->getHandleRef(), | ||
HandleData.data(), HandleData.size(), &Ptr); | ||
if (UrRes == UR_RESULT_ERROR_INVALID_VALUE) | ||
throw sycl::exception(sycl::make_error_code(errc::invalid), | ||
"HandleData data size does not correspond " | ||
"to the target platform's IPC memory handle size."); | ||
Adapter.checkUrResult(UrRes); | ||
return Ptr; | ||
} | ||
|
||
__SYCL_EXPORT void close(void *Ptr, const sycl::context &Ctx) { | ||
auto CtxImpl = sycl::detail::getSyclObjImpl(Ctx); | ||
sycl::detail::adapter_impl &Adapter = CtxImpl->getAdapter(); | ||
Adapter.call<sycl::detail::UrApiKind::urIPCCloseMemHandleExp>( | ||
CtxImpl->getHandleRef(), Ptr); | ||
} | ||
|
||
} // namespace ext::oneapi::experimental::ipc_memory | ||
} // namespace _V1 | ||
} // namespace sycl |
Uh oh!
There was an error while loading. Please reload this page.