oneAPI Deep Neural Network Library (oneDNN)
Performance library for Deep Learning
2.1.1
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 
48 
50 namespace sycl_interop {
51 
53 enum class memory_kind {
58 };
59 
65  return static_cast<dnnl_sycl_interop_memory_kind_t>(akind);
66 }
67 
75  const cl::sycl::device &adevice, const cl::sycl::context &acontext) {
76  dnnl_engine_t aengine;
78  static_cast<const void *>(&adevice),
79  static_cast<const void *>(&acontext)),
80  "could not create an engine");
81  return engine(aengine);
82 }
83 
89 inline cl::sycl::context get_context(const engine &aengine) {
90  void *ctx_ptr;
92  dnnl_sycl_interop_engine_get_context(aengine.get(), &ctx_ptr),
93  "could not get a context handle");
94  auto ctx = *static_cast<cl::sycl::context *>(ctx_ptr);
95  return ctx;
96 }
97 
103 inline cl::sycl::device get_device(const engine &aengine) {
104  void *dev_ptr;
106  dnnl_sycl_interop_engine_get_device(aengine.get(), &dev_ptr),
107  "could not get a device handle");
108  auto dev = *static_cast<cl::sycl::device *>(dev_ptr);
109  return dev;
110 }
111 
119 inline stream make_stream(const engine &aengine, cl::sycl::queue &aqueue) {
120  dnnl_stream_t astream;
122  dnnl_sycl_interop_stream_create(&astream, aengine.get(), &aqueue),
123  "could not create a stream");
124  return stream(astream);
125 }
126 
132 inline cl::sycl::queue get_queue(const stream &astream) {
133  void *queue_ptr;
135  dnnl_sycl_interop_stream_get_queue(astream.get(), &queue_ptr),
136  "could not get a stream handle");
137  auto queue = *static_cast<cl::sycl::queue *>(queue_ptr);
138  return queue;
139 }
140 
151 template <typename T, int ndims = 1>
152 cl::sycl::buffer<T, ndims> get_buffer(const memory &amemory) {
153  static_assert(ndims == 1, "only 1D buffers supported");
154 
155  void *handle_ptr;
156  error::wrap_c_api(dnnl_memory_get_data_handle(amemory.get(), &handle_ptr),
157  "could not get SYCL buffer object");
158 
159  // XXX: workaround: zero-range buffer cannot be constructed.
160  if (!handle_ptr) return cl::sycl::buffer<T, ndims>(cl::sycl::range<1>(1));
161 
162  auto &buf_u8 = *static_cast<cl::sycl::buffer<uint8_t, 1> *>(handle_ptr);
163  auto range = cl::sycl::range<1>(buf_u8.get_size() / sizeof(T));
164  return buf_u8.reinterpret<T, 1>(range);
165 }
166 
173 template <typename T, int ndims>
174 void set_buffer(memory &amemory, cl::sycl::buffer<T, ndims> &abuffer) {
175  auto range = cl::sycl::range<1>(abuffer.get_size());
176  auto buf_u8 = abuffer.template reinterpret<uint8_t, 1>(range);
178  static_cast<void *>(&buf_u8), nullptr),
179  "could not set SYCL buffer object");
180 }
181 
189 template <typename T, int ndims>
190 void set_buffer(memory &amemory, cl::sycl::buffer<T, ndims> &abuffer,
191  const stream &astream) {
192  auto range = cl::sycl::range<1>(abuffer.get_size());
193  auto buf_u8 = abuffer.template reinterpret<uint8_t, 1>(range);
195  static_cast<void *>(&buf_u8), astream.get(true)),
196  "could not set SYCL buffer object");
197 }
198 
204 inline memory_kind get_memory_kind(const memory &amemory) {
208  "could not get memory kind");
209  return static_cast<memory_kind>(ckind);
210 }
211 
240 inline memory make_memory(const memory::desc &memory_desc,
241  const engine &aengine, memory_kind kind,
242  void *handle = DNNL_MEMORY_ALLOCATE) {
243  dnnl_memory_t c_memory;
245  dnnl_sycl_interop_memory_create(&c_memory, &memory_desc.data,
246  aengine.get(), convert_to_c(kind), handle),
247  "could not create a memory");
248  return memory(c_memory);
249 }
250 
258 template <typename T, int ndims = 1>
259 memory make_memory(const memory::desc &memory_desc, const engine &aengine,
260  cl::sycl::buffer<T, ndims> &abuffer) {
261  memory amemory(memory_desc, aengine, DNNL_MEMORY_NONE);
262  set_buffer(amemory, abuffer);
263  return amemory;
264 }
265 
283 inline cl::sycl::event execute(const dnnl::primitive &aprimitive,
284  const stream &astream, const std::unordered_map<int, memory> &args,
285  const std::vector<cl::sycl::event> &deps = {}) {
286  std::vector<dnnl_exec_arg_t> c_args;
287  c_args.reserve(args.size());
288  for (const auto &a : args)
289  c_args.push_back({a.first, a.second.get()});
290 
291  cl::sycl::event return_event;
293  dnnl_sycl_interop_primitive_execute(aprimitive.get(), astream.get(),
294  (int)c_args.size(), c_args.data(), &deps, &return_event),
295  "could not execute a primitive");
296  return return_event;
297 }
298 
299 } // namespace sycl_interop
300 
302 
304 
305 } // namespace dnnl
306 
308 
309 #endif // DNNL_SYCL_HPP
dnnl_status_t DNNL_API dnnl_memory_get_data_handle(const_dnnl_memory_t memory, void **handle)
Returns memory object's data handle.
#define DNNL_MEMORY_NONE
Special pointer value that indicates that a memory object should not have an underlying buffer.
Definition: dnnl_types.h:1506
#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:1510
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_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_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_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.
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_memory_kind_t
Memory allocation kind.
Definition: dnnl_sycl_types.h:34
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_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_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_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_sycl_interop_buffer
Buffer memory allocation kind.
Definition: dnnl_sycl_types.h:38
@ dnnl_sycl_interop_usm
USM (device, shared, host, or unknown) memory allocation kind.
Definition: dnnl_sycl_types.h:36
cl::sycl::queue get_queue(const stream &astream)
Returns the SYCL queue associated with an execution stream.
Definition: dnnl_sycl.hpp:132
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:119
cl::sycl::context get_context(const engine &aengine)
Returns the SYCL context associated with an engine.
Definition: dnnl_sycl.hpp:89
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:74
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:64
memory_kind get_memory_kind(const memory &amemory)
Returns the memory allocation kind associated with a memory object.
Definition: dnnl_sycl.hpp:204
memory_kind
Memory allocation kind.
Definition: dnnl_sycl.hpp:53
@ buffer
Buffer memory allocation kind.
@ usm
USM (device, shared, host, or unknown) memory allocation kind.
void set_buffer(memory &amemory, cl::sycl::buffer< T, ndims > &abuffer)
Sets SYCL buffer associated with a memory object.
Definition: dnnl_sycl.hpp:174
cl::sycl::buffer< T, ndims > get_buffer(const memory &amemory)
Returns the SYCL buffer associated with a memory object.
Definition: dnnl_sycl.hpp:152
cl::sycl::device get_device(const engine &aengine)
Returns the SYCL device associated with an engine.
Definition: dnnl_sycl.hpp:103
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:240
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:283
oneDNN namespace
Definition: dnnl.hpp:74
C++ API.
An execution engine.
Definition: dnnl.hpp:869
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
oneDNN C API handle wrapper class.
Definition: dnnl.hpp:136
T get(bool allow_empty=false) const
Returns the underlying C API handle.
Definition: dnnl.hpp:185
A memory descriptor.
Definition: dnnl.hpp:1984
dnnl_memory_desc_t data
The underlying C API data structure.
Definition: dnnl.hpp:1987
Memory object.
Definition: dnnl.hpp:1108
Base class for all computational primitives.
Definition: dnnl.hpp:269
An execution stream.
Definition: dnnl.hpp:985
An opaque structure to describe an engine.
An opaque structure to describe a memory.
An opaque structure to describe an execution stream.