Deep Neural Network Library (DNNL)  1.91.0
Performance library for Deep Learning
example_utils.hpp
1 /*******************************************************************************
2 * Copyright 2019 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 EXAMPLE_UTILS_HPP
18 #define EXAMPLE_UTILS_HPP
19 
20 #include <algorithm>
21 #include <cassert>
22 #include <functional>
23 #include <iostream>
24 #include <stdexcept>
25 #include <stdlib.h>
26 #include <string>
27 #include <initializer_list>
28 
29 #include "dnnl.hpp"
30 #include "dnnl_debug.h"
31 
32 dnnl::engine::kind validate_engine_kind(dnnl::engine::kind akind) {
33  // Checking if a GPU exists on the machine
34  if (akind == dnnl::engine::kind::gpu) {
36  std::cout << "Application couldn't find GPU, please run with CPU "
37  "instead.\n";
38  exit(0);
39  }
40  }
41  return akind;
42 }
43 
44 // Exception class to indicate that the example uses a feature that is not
45 // available on the current systems. It is not treated as an error then, but
46 // just notifies a user.
47 struct example_allows_unimplemented : public std::exception {
48  example_allows_unimplemented(const char *message) noexcept
49  : message(message) {}
50  virtual const char *what() const noexcept override { return message; }
51  const char *message;
52 };
53 
54 inline const char *engine_kind2str_upper(dnnl::engine::kind kind);
55 
56 // Runs example function with signature void() and catches errors.
57 // Returns `0` on success, `1` or DNNL error, and `2` on example error.
58 inline int handle_example_errors(
59  std::initializer_list<dnnl::engine::kind> engine_kinds,
60  std::function<void()> example) {
61  int exit_code = 0;
62 
63  try {
64  example();
65  } catch (example_allows_unimplemented &e) {
66  std::cout << e.message << std::endl;
67  exit_code = 0;
68  } catch (dnnl::error &e) {
69  std::cout << "DNNL error caught: " << std::endl
70  << "\tStatus: " << dnnl_status2str(e.status) << std::endl
71  << "\tMessage: " << e.what() << std::endl;
72  exit_code = 1;
73  } catch (std::exception &e) {
74  std::cout << "Error in the example: " << e.what() << "." << std::endl;
75  exit_code = 2;
76  }
77 
78  std::string engine_kind_str;
79  for (auto it = engine_kinds.begin(); it != engine_kinds.end(); ++it) {
80  if (it != engine_kinds.begin()) engine_kind_str += "/";
81  engine_kind_str += engine_kind2str_upper(*it);
82  }
83 
84  std::cout << "Example " << (exit_code ? "failed" : "passed") << " on "
85  << engine_kind_str << "." << std::endl;
86  return exit_code;
87 }
88 
89 // Same as above, but for functions with signature
90 // void(dnnl::engine::kind engine_kind, int argc, char **argv).
91 inline int handle_example_errors(
92  std::function<void(dnnl::engine::kind, int, char **)> example,
93  dnnl::engine::kind engine_kind, int argc, char **argv) {
94  return handle_example_errors(
95  {engine_kind}, [&]() { example(engine_kind, argc, argv); });
96 }
97 
98 // Same as above, but for functions with signature void(dnnl::engine::kind).
99 inline int handle_example_errors(
100  std::function<void(dnnl::engine::kind)> example,
101  dnnl::engine::kind engine_kind) {
102  return handle_example_errors(
103  {engine_kind}, [&]() { example(engine_kind); });
104 }
105 
106 inline dnnl::engine::kind parse_engine_kind(
107  int argc, char **argv, int extra_args = 0) {
108  // Returns default engine kind, i.e. CPU, if none given
109  if (argc == 1) {
110  return validate_engine_kind(dnnl::engine::kind::cpu);
111  } else if (argc <= extra_args + 2) {
112  std::string engine_kind_str = argv[1];
113  // Checking the engine type, i.e. CPU or GPU
114  if (engine_kind_str == "cpu") {
115  return validate_engine_kind(dnnl::engine::kind::cpu);
116  } else if (engine_kind_str == "gpu") {
117  return validate_engine_kind(dnnl::engine::kind::gpu);
118  }
119  }
120 
121  // If all above fails, the example should be ran properly
122  std::cout << "Inappropriate engine kind." << std::endl
123  << "Please run the example like this: " << argv[0] << " [cpu|gpu]"
124  << (extra_args ? " [extra arguments]" : "") << "." << std::endl;
125  exit(1);
126 }
127 
128 inline const char *engine_kind2str_upper(dnnl::engine::kind kind) {
129  if (kind == dnnl::engine::kind::cpu) return "CPU";
130  if (kind == dnnl::engine::kind::gpu) return "GPU";
131  assert(!"not expected");
132  return "<Unknown engine>";
133 }
134 
135 // Read from memory, write to handle
136 inline void read_from_dnnl_memory(void *handle, dnnl::memory &mem) {
137  dnnl::engine eng = mem.get_engine();
138  size_t size = mem.get_desc().get_size();
139 
140 #if DNNL_WITH_SYCL
141  bool is_cpu_sycl = (DNNL_CPU_RUNTIME == DNNL_RUNTIME_SYCL
142  && eng.get_kind() == dnnl::engine::kind::cpu);
143  bool is_gpu_sycl = (DNNL_GPU_RUNTIME == DNNL_RUNTIME_SYCL
144  && eng.get_kind() == dnnl::engine::kind::gpu);
145  if (is_cpu_sycl || is_gpu_sycl) {
146 #ifdef DNNL_USE_SYCL_BUFFERS
147  auto buffer = mem.get_sycl_buffer<uint8_t>();
148  auto src = buffer.get_access<cl::sycl::access::mode::read>();
149  uint8_t *src_ptr = src.get_pointer();
150 #elif defined(DNNL_USE_DPCPP_USM)
151  uint8_t *src_ptr = (uint8_t *)mem.get_data_handle();
152 #else
153 #error "Not expected"
154 #endif
155  for (size_t i = 0; i < size; ++i)
156  ((uint8_t *)handle)[i] = src_ptr[i];
157  return;
158  }
159 #endif
160 #if DNNL_GPU_RUNTIME == DNNL_RUNTIME_OCL
161  if (eng.get_kind() == dnnl::engine::kind::gpu) {
162  dnnl::stream s(eng);
163  cl_command_queue q = s.get_ocl_command_queue();
164  cl_mem m = mem.get_ocl_mem_object();
165 
166  cl_int ret = clEnqueueReadBuffer(
167  q, m, CL_TRUE, 0, size, handle, 0, NULL, NULL);
168  if (ret != CL_SUCCESS)
169  throw std::runtime_error("clEnqueueReadBuffer failed.");
170  return;
171  }
172 #endif
173 
174  if (eng.get_kind() == dnnl::engine::kind::cpu) {
175  uint8_t *src = static_cast<uint8_t *>(mem.get_data_handle());
176  for (size_t i = 0; i < size; ++i)
177  ((uint8_t *)handle)[i] = src[i];
178  return;
179  }
180 
181  assert(!"not expected");
182 }
183 
184 // Read from handle, write to memory
185 inline void write_to_dnnl_memory(void *handle, dnnl::memory &mem) {
186  dnnl::engine eng = mem.get_engine();
187  size_t size = mem.get_desc().get_size();
188 
189 #if DNNL_WITH_SYCL
190  bool is_cpu_sycl = (DNNL_CPU_RUNTIME == DNNL_RUNTIME_SYCL
191  && eng.get_kind() == dnnl::engine::kind::cpu);
192  bool is_gpu_sycl = (DNNL_GPU_RUNTIME == DNNL_RUNTIME_SYCL
193  && eng.get_kind() == dnnl::engine::kind::gpu);
194  if (is_cpu_sycl || is_gpu_sycl) {
195 #ifdef DNNL_USE_SYCL_BUFFERS
196  auto buffer = mem.get_sycl_buffer<uint8_t>();
197  auto dst = buffer.get_access<cl::sycl::access::mode::write>();
198  uint8_t *dst_ptr = dst.get_pointer();
199 #elif defined(DNNL_USE_DPCPP_USM)
200  uint8_t *dst_ptr = (uint8_t *)mem.get_data_handle();
201 #else
202 #error "Not expected"
203 #endif
204  for (size_t i = 0; i < size; ++i)
205  dst_ptr[i] = ((uint8_t *)handle)[i];
206  return;
207  }
208 #endif
209 #if DNNL_GPU_RUNTIME == DNNL_RUNTIME_OCL
210  if (eng.get_kind() == dnnl::engine::kind::gpu) {
211  dnnl::stream s(eng);
212  cl_command_queue q = s.get_ocl_command_queue();
213  cl_mem m = mem.get_ocl_mem_object();
214 
215  cl_int ret = clEnqueueWriteBuffer(
216  q, m, CL_TRUE, 0, size, handle, 0, NULL, NULL);
217  if (ret != CL_SUCCESS)
218  throw std::runtime_error("clEnqueueWriteBuffer failed.");
219  return;
220  }
221 #endif
222 
223  if (eng.get_kind() == dnnl::engine::kind::cpu) {
224  uint8_t *dst = static_cast<uint8_t *>(mem.get_data_handle());
225  for (size_t i = 0; i < size; ++i)
226  dst[i] = ((uint8_t *)handle)[i];
227  return;
228  }
229 
230  assert(!"not expected");
231 }
232 
233 #endif
dnnl::memory::desc::get_size
size_t get_size() const
Returns size of the memory descriptor in bytes.
Definition: dnnl.hpp:2210
dnnl::memory::get_sycl_buffer
cl::sycl::buffer< T, ndims > get_sycl_buffer(size_t *offset=nullptr) const
Returns the underlying SYCL buffer object.
Definition: dnnl.hpp:2395
dnnl::error::what
const char * what() const noexcept override
Returns the explanatory string.
Definition: dnnl.hpp:103
dnnl::stream
An execution stream.
Definition: dnnl.hpp:1433
dnnl::engine
An execution engine.
Definition: dnnl.hpp:1273
dnnl::engine::kind
kind
Kinds of engines.
Definition: dnnl.hpp:1278
dnnl.hpp
dnnl::memory::get_desc
desc get_desc() const
Returns the associated memory descriptor.
Definition: dnnl.hpp:2292
dnnl::engine::kind::gpu
GPU engine.
dnnl::error
DNNL exception class.
Definition: dnnl.hpp:91
dnnl::engine::get_count
static size_t get_count(kind kind)
Returns the number of engines of a certain kind.
Definition: dnnl.hpp:1297
dnnl_debug.h
dnnl::memory
Memory object.
Definition: dnnl.hpp:1606
dnnl::memory::get_engine
engine get_engine() const
Returns the associated engine.
Definition: dnnl.hpp:2300
dnnl::memory::get_data_handle
void * get_data_handle() const
Returns the underlying memory buffer.
Definition: dnnl.hpp:2310
dnnl::memory::get_ocl_mem_object
cl_mem get_ocl_mem_object() const
Returns the OpenCL memory object associated with the memory.
Definition: dnnl.hpp:2371
dnnl::engine::kind::cpu
CPU engine.