.. index:: pair: page; DPC++ Interoperability .. _doxid-dev_guide_dpcpp_interoperability: DPC++ Interoperability ====================== :ref:`API Reference ` Overview ~~~~~~~~ oneDNN may use the DPC++ runtime for CPU and GPU engines to interact with the hardware. Users may need to use oneDNN with other code that uses DPC++. For that purpose, the library provides API extensions to interoperate with underlying SYCL objects. This interoperability API is defined in the ``dnnl_sycl.hpp`` header. One of the possible scenarios is executing a SYCL kernel for a custom operation not provided by oneDNN. In this case, the library provides all the necessary API to "seamlessly" submit a kernel, sharing the execution context with oneDNN: using the same device and queue. The interoperability API is provided for two scenarios: * Construction of oneDNN objects based on existing SYCL objects * Accessing SYCL objects for existing oneDNN objects The mapping between oneDNN and SYCL objects is provided in the following table: ====================== ======================================= oneDNN object SYCL object(s) ====================== ======================================= Engine ``sycl::device`` and ``sycl::context`` Stream ``sycl::queue`` Memory (Buffer-based) ``sycl::buffer`` Memory (USM-based) Unified Shared Memory (USM) pointer ====================== ======================================= The table below summarizes how to construct oneDNN objects based on SYCL objects and how to query underlying SYCL objects for existing oneDNN objects. ====================== ================================================================================================================================================================================== ================================================================================================================================================================================================================================================================= oneDNN object API to construct oneDNN object API to access SYCL object(s) ====================== ================================================================================================================================================================================== ================================================================================================================================================================================================================================================================= Engine :ref:`dnnl::sycl_interop::make_engine(const sycl::device &, const sycl::context &) ` :ref:`dnnl::sycl_interop::get_device(const engine &) ` :ref:`dnnl::sycl_interop::get_context(const engine &) ` Stream :ref:`dnnl::sycl_interop::make_stream(const engine &, sycl::queue &) ` :ref:`dnnl::sycl_interop::get_queue(const stream &) ` Memory (Buffer-based) :ref:`dnnl::sycl_interop::make_memory(const memory::desc &, const engine &, sycl::buffer\ &) ` :ref:`dnnl::sycl_interop::get_buffer\(const memory &) ` Memory (USM-based) :ref:`dnnl::memory(const memory::desc &, const engine &, void \*) ` :ref:`dnnl::memory::get_data_handle() ` ====================== ================================================================================================================================================================================== ================================================================================================================================================================================================================================================================= .. note:: Internally, library buffer-based memory objects use 1D ``uint8_t`` SYCL buffers; however, the user may initialize and access memory using SYCL buffers. of a different type. In this case, buffers will be reinterpreted to the underlying type ``sycl::buffer``. SYCL Buffers and DPC++ USM Interfaces for Memory Objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The memory model in SYCL 1.2.1 is based on SYCL buffers. DPC++ further extends the programming model with a Unified Shared Memory (USM) alternative, which provides the ability to allocate and use memory in a uniform way on host and DPC++ devices. oneDNN supports both programming models. USM is the default and can be used with the usual oneDNN :ref:`memory API `. The buffer-based programming model requires using the interoperability API. To construct a oneDNN memory object, use one of the following interfaces: * :ref:`dnnl::sycl_interop::make_memory(const memory::desc &, const engine &, sycl_interop::memory_kind kind, void \*handle) ` Constructs a USM-based or buffer-based memory object depending on memory allocation kind ``kind``. The ``handle`` could be one of special values :ref:`DNNL_MEMORY_ALLOCATE ` or :ref:`DNNL_MEMORY_NONE `, or it could be a user-provided USM pointer. The latter works only when ``kind`` is :ref:`dnnl::sycl_interop::memory_kind::usm ` and the ``handle`` is a USM-allocated pointer. * :ref:`dnnl::memory(const memory::desc &, const engine &, void \*) ` Constructs a USM-based memory object. The call is equivalent to calling the function above with with ``kind`` equal to :ref:`dnnl::sycl_interop::memory_kind::usm `. * :ref:`dnnl::sycl_interop::make_memory(const memory::desc &, const engine &, sycl::buffer\ &) ` Constructs a buffer-based memory object based on a user-provided SYCL buffer. To identify whether a memory object is USM-based or buffer-based, :ref:`dnnl::sycl_interop::get_memory_kind() ` query can be used. Handling Dependencies with USM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SYCL queues could be in-order or out-of-order. For out-of-order queues, the order of execution is defined by the dependencies between SYCL tasks. The runtime tracks dependencies based on accessors created for SYCL buffers. USM pointers cannot be used to create accessors and users must handle dependencies on their own using SYCL events. oneDNN provides two mechanisms to handle dependencies when USM memory is used: #. :ref:`dnnl::sycl_interop::execute() ` interface This interface enables you to pass dependencies between primitives using SYCL events. In this case, the user is responsible for passing proper dependencies for every primitive execution. #. In-order oneDNN stream oneDNN enables you to create in-order streams when submitted primitives are executed in the order they were submitted. Using in-order streams prevents possible read-before-write or concurrent read/write issues.