oneAPI Deep Neural Network Library (oneDNN)
Performance library for Deep Learning
1.96.0
dnnl_sycl.hpp
1 /*******************************************************************************
2 * Copyright 2020 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16 
17 #ifndef ONEAPI_DNNL_DNNL_SYCL_HPP
18 #define ONEAPI_DNNL_DNNL_SYCL_HPP
19 
21 #include <algorithm>
22 #include <cstdlib>
23 #include <iterator>
24 #include <memory>
25 #include <string>
26 #include <vector>
27 #include <unordered_map>
28 
29 #include <CL/sycl.hpp>
30 
31 #include "oneapi/dnnl/dnnl.hpp"
32 #include "oneapi/dnnl/dnnl_sycl.h"
34 
37 
38 namespace dnnl {
39 
42 
46 
48 namespace sycl_interop {
49 
51 enum class memory_kind {
56 };
57 
63  return static_cast<dnnl_sycl_interop_memory_kind_t>(akind);
64 }
65 
73  const cl::sycl::device &adevice, const cl::sycl::context &acontext) {
74  dnnl_engine_t aengine;
76  static_cast<const void *>(&adevice),
77  static_cast<const void *>(&acontext)),
78  "could not create an engine");
79  return engine(aengine);
80 }
81 
87 inline cl::sycl::context get_context(const engine &aengine) {
88  void *ctx_ptr;
90  dnnl_sycl_interop_engine_get_context(aengine.get(), &ctx_ptr),
91  "could not get a context handle");
92  auto ctx = *static_cast<cl::sycl::context *>(ctx_ptr);
93  return ctx;
94 }
95 
101 inline cl::sycl::device get_device(const engine &aengine) {
102  void *dev_ptr;
104  dnnl_sycl_interop_engine_get_device(aengine.get(), &dev_ptr),
105  "could not get a device handle");
106  auto dev = *static_cast<cl::sycl::device *>(dev_ptr);
107  return dev;
108 }
109 
117 inline stream make_stream(const engine &aengine, cl::sycl::queue &aqueue) {
118  dnnl_stream_t astream;
120  dnnl_sycl_interop_stream_create(&astream, aengine.get(), &aqueue),
121  "could not create a stream");
122  return stream(astream);
123 }
124 
130 inline cl::sycl::queue get_queue(const stream &astream) {
131  void *queue_ptr;
133  dnnl_sycl_interop_stream_get_queue(astream.get(), &queue_ptr),
134  "could not get a stream handle");
135  auto queue = *static_cast<cl::sycl::queue *>(queue_ptr);
136  return queue;
137 }
138 
149 template <typename T, int ndims = 1>
150 cl::sycl::buffer<T, ndims> get_buffer(const memory &amemory) {
151  static_assert(ndims == 1, "only 1D buffers supported");
152 
153  void *handle_ptr;
154  error::wrap_c_api(dnnl_memory_get_data_handle(amemory.get(), &handle_ptr),
155  "could not get SYCL buffer object");
156 
157  // XXX: workaround for ComputeCpp
158  // ComputeCpp fails to construct zero-range buffer
159  if (!handle_ptr) return cl::sycl::buffer<T, ndims>(cl::sycl::range<1>(1));
160 
161  auto &buf_u8 = *static_cast<cl::sycl::buffer<uint8_t, 1> *>(handle_ptr);
162  auto range = cl::sycl::range<1>(buf_u8.get_size() / sizeof(T));
163  return buf_u8.reinterpret<T, 1>(range);
164 }
165 
172 template <typename T, int ndims>
173 void set_buffer(memory &amemory, cl::sycl::buffer<T, ndims> &abuffer) {
174  auto range = cl::sycl::range<1>(abuffer.get_size());
175  auto buf_u8 = abuffer.template reinterpret<uint8_t, 1>(range);
177  static_cast<void *>(&buf_u8), nullptr),
178  "could not set SYCL buffer object");
179 }
180 
188 template <typename T, int ndims>
189 void set_buffer(memory &amemory, cl::sycl::buffer<T, ndims> &abuffer,
190  const stream &astream) {
191  auto range = cl::sycl::range<1>(abuffer.get_size());
192  auto buf_u8 = abuffer.template reinterpret<uint8_t, 1>(range);
194  static_cast<void *>(&buf_u8), astream.get(true)),
195  "could not set SYCL buffer object");
196 }
197 
203 inline memory_kind get_memory_kind(const memory &amemory) {
207  "could not get memory kind");
208  return static_cast<memory_kind>(ckind);
209 }
210 
239 inline memory make_memory(const memory::desc &memory_desc,
240  const engine &aengine, memory_kind kind,
241  void *handle = DNNL_MEMORY_ALLOCATE) {
242  dnnl_memory_t c_memory;
244  dnnl_sycl_interop_memory_create(&c_memory, &memory_desc.data,
245  aengine.get(), convert_to_c(kind), handle),
246  "could not create a memory");
247  return memory(c_memory);
248 }
249 
257 template <typename T, int ndims = 1>
258 memory make_memory(const memory::desc &memory_desc, const engine &aengine,
259  cl::sycl::buffer<T, ndims> &abuffer) {
260  memory amemory(memory_desc, aengine, DNNL_MEMORY_NONE);
261  set_buffer(amemory, abuffer);
262  return amemory;
263 }
264 
282 inline cl::sycl::event execute(const dnnl::primitive &aprimitive,
283  const stream &astream, const std::unordered_map<int, memory> &args,
284  const std::vector<cl::sycl::event> &deps = {}) {
285  std::vector<dnnl_exec_arg_t> c_args;
286  c_args.reserve(args.size());
287  for (const auto &a : args)
288  c_args.push_back({a.first, a.second.get()});
289 
290  cl::sycl::event return_event;
292  dnnl_sycl_interop_primitive_execute(aprimitive.get(), astream.get(),
293  (int)c_args.size(), c_args.data(), &deps, &return_event),
294  "could not execute a primitive");
295  return return_event;
296 }
297 
298 } // namespace sycl_interop
299 
301 
303 
304 } // namespace dnnl
305 
307 
308 #endif // DNNL_SYCL_HPP
dnnl.hpp
C++ API.
dnnl::stream
An execution stream.
Definition: dnnl.hpp:975
dnnl_memory
An opaque structure to describe a memory.
dnnl::engine
An execution engine.
Definition: dnnl.hpp:859
dnnl::memory::desc::data
dnnl_memory_desc_t data
The underlying C API data structure.
Definition: dnnl.hpp:1721
dnnl_engine
An opaque structure to describe an engine.
dnnl_sycl_interop_engine_get_context
dnnl_status_t DNNL_API dnnl_sycl_interop_engine_get_context(dnnl_engine_t engine, void **context)
Returns the SYCL context associated with an engine.
dnnl::sycl_interop::execute
cl::sycl::event execute(const dnnl::primitive &aprimitive, const stream &astream, const std::unordered_map< int, memory > &args, const std::vector< cl::sycl::event > &deps={})
Executes computations specified by the primitive in a specified stream and returns a SYCL event.
Definition: dnnl_sycl.hpp:282
dnnl_sycl_interop_usm
@ dnnl_sycl_interop_usm
USM (device, shared, host, or unknown) memory allocation kind.
Definition: dnnl_sycl_types.h:36
dnnl_sycl_interop_engine_create
dnnl_status_t DNNL_API dnnl_sycl_interop_engine_create(dnnl_engine_t *engine, const void *device, const void *context)
Creates an engine associated with a SYCL device and a SYCL context.
dnnl::sycl_interop::get_buffer
cl::sycl::buffer< T, ndims > get_buffer(const memory &amemory)
Returns the SYCL buffer associated with a memory object.
Definition: dnnl_sycl.hpp:150
dnnl_sycl_interop_buffer
@ dnnl_sycl_interop_buffer
Buffer memory allocation kind.
Definition: dnnl_sycl_types.h:38
dnnl::sycl_interop::get_context
cl::sycl::context get_context(const engine &aengine)
Returns the SYCL context associated with an engine.
Definition: dnnl_sycl.hpp:87
dnnl_sycl_interop_engine_get_device
dnnl_status_t DNNL_API dnnl_sycl_interop_engine_get_device(dnnl_engine_t engine, void **device)
Returns the SYCL device associated with an engine.
dnnl::sycl_interop::make_stream
stream make_stream(const engine &aengine, cl::sycl::queue &aqueue)
Creates an execution stream for a given engine associated with a SYCL queue.
Definition: dnnl_sycl.hpp:117
dnnl::sycl_interop::get_memory_kind
memory_kind get_memory_kind(const memory &amemory)
Returns the memory allocation kind associated with a memory object.
Definition: dnnl_sycl.hpp:203
dnnl_memory_get_data_handle
dnnl_status_t DNNL_API dnnl_memory_get_data_handle(const_dnnl_memory_t memory, void **handle)
Returns memory object's data handle.
DNNL_MEMORY_ALLOCATE
#define DNNL_MEMORY_ALLOCATE
Special pointer value that indicates that the library needs to allocate an underlying buffer for a me...
Definition: dnnl_types.h:1253
dnnl::sycl_interop::get_queue
cl::sycl::queue get_queue(const stream &astream)
Returns the SYCL queue associated with an execution stream.
Definition: dnnl_sycl.hpp:130
dnnl_sycl_interop_memory_get_memory_kind
dnnl_status_t DNNL_API dnnl_sycl_interop_memory_get_memory_kind(const_dnnl_memory_t memory, dnnl_sycl_interop_memory_kind_t *memory_kind)
Returns the memory allocation kind associated with a memory object.
dnnl_sycl_interop_memory_create
dnnl_status_t DNNL_API dnnl_sycl_interop_memory_create(dnnl_memory_t *memory, const dnnl_memory_desc_t *memory_desc, dnnl_engine_t engine, dnnl_sycl_interop_memory_kind_t memory_kind, void *handle)
Creates a memory object.
dnnl::handle::get
T get(bool allow_empty=false) const
Returns the underlying C API handle.
Definition: dnnl.hpp:185
DNNL_MEMORY_NONE
#define DNNL_MEMORY_NONE
Special pointer value that indicates that a memory object should not have an underlying buffer.
Definition: dnnl_types.h:1249
dnnl::sycl_interop::make_engine
engine make_engine(const cl::sycl::device &adevice, const cl::sycl::context &acontext)
Constructs an engine from SYCL device and context objects.
Definition: dnnl_sycl.hpp:72
dnnl::memory
Memory object.
Definition: dnnl.hpp:1098
dnnl::error::wrap_c_api
static void wrap_c_api(dnnl_status_t status, const char *message)
A convenience function for wrapping calls to C API functions.
Definition: dnnl.hpp:103
dnnl::handle
oneDNN C API handle wrapper class.
Definition: dnnl.hpp:136
dnnl_sycl_interop_primitive_execute
dnnl_status_t DNNL_API dnnl_sycl_interop_primitive_execute(const_dnnl_primitive_t primitive, dnnl_stream_t stream, int nargs, const dnnl_exec_arg_t *args, const void *deps, void *return_event)
Executes computations specified by the primitive in a specified stream and returns a SYCL event.
dnnl::memory::desc
A memory descriptor.
Definition: dnnl.hpp:1718
dnnl_sycl_interop_memory_set_buffer
dnnl_status_t DNNL_API dnnl_sycl_interop_memory_set_buffer(dnnl_memory_t memory, void *buffer, dnnl_stream_t stream)
Sets a SYCL buffer for a memory object.
dnnl::primitive
Base class for all computational primitives.
Definition: dnnl.hpp:269
dnnl
oneDNN namespace
Definition: dnnl.hpp:74
dnnl_stream
An opaque structure to describe an execution stream.
dnnl_sycl_interop_stream_get_queue
dnnl_status_t DNNL_API dnnl_sycl_interop_stream_get_queue(dnnl_stream_t stream, void **queue)
Returns the SYCL queue associated with an execution stream.
dnnl::sycl_interop::make_memory
memory make_memory(const memory::desc &memory_desc, const engine &aengine, memory_kind kind, void *handle=DNNL_MEMORY_ALLOCATE)
Creates a memory object.
Definition: dnnl_sycl.hpp:239
dnnl_sycl_interop_memory_kind_t
dnnl_sycl_interop_memory_kind_t
Memory allocation kind.
Definition: dnnl_sycl_types.h:34
dnnl::sycl_interop::set_buffer
void set_buffer(memory &amemory, cl::sycl::buffer< T, ndims > &abuffer)
Sets SYCL buffer associated with a memory object.
Definition: dnnl_sycl.hpp:173
dnnl::sycl_interop::get_device
cl::sycl::device get_device(const engine &aengine)
Returns the SYCL device associated with an engine.
Definition: dnnl_sycl.hpp:101
dnnl::sycl_interop::convert_to_c
dnnl_sycl_interop_memory_kind_t convert_to_c(memory_kind akind)
Converts a memory allocation kind enum value from C++ API to C API type.
Definition: dnnl_sycl.hpp:62
dnnl::sycl_interop::memory_kind::usm
@ usm
USM (device, shared, host, or unknown) memory allocation kind.
dnnl::sycl_interop::memory_kind
memory_kind
Memory allocation kind.
Definition: dnnl_sycl.hpp:51
dnnl_sycl_interop_stream_create
dnnl_status_t DNNL_API dnnl_sycl_interop_stream_create(dnnl_stream_t *stream, dnnl_engine_t engine, void *queue)
Creates an execution stream for a given engine associated with a SYCL queue.