Deep Neural Network Library (DNNL)  1.3.0
Performance library for Deep Learning
example_utils.hpp
1 /*******************************************************************************
2 * Copyright 2019-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 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 // Exception class to indicate that the example uses a feature that is not
33 // available on the current systems. It is not treated as an error then, but
34 // just notifies a user.
35 struct example_allows_unimplemented : public std::exception {
36  example_allows_unimplemented(const char *message) noexcept
37  : message(message) {}
38  virtual const char *what() const noexcept override { return message; }
39  const char *message;
40 };
41 
42 inline const char *engine_kind2str_upper(dnnl::engine::kind kind);
43 
44 // Runs example function with signature void() and catches errors.
45 // Returns `0` on success, `1` or DNNL error, and `2` on example error.
46 inline int handle_example_errors(
47  std::initializer_list<dnnl::engine::kind> engine_kinds,
48  std::function<void()> example) {
49  int exit_code = 0;
50 
51  try {
52  example();
53  } catch (example_allows_unimplemented &e) {
54  std::cout << e.message << std::endl;
55  exit_code = 0;
56  } catch (dnnl::error &e) {
57  std::cout << "DNNL error caught: " << std::endl
58  << "\tStatus: " << dnnl_status2str(e.status) << std::endl
59  << "\tMessage: " << e.what() << std::endl;
60  exit_code = 1;
61  } catch (std::exception &e) {
62  std::cout << "Error in the example: " << e.what() << "." << std::endl;
63  exit_code = 2;
64  }
65 
66  std::string engine_kind_str;
67  for (auto it = engine_kinds.begin(); it != engine_kinds.end(); ++it) {
68  if (it != engine_kinds.begin()) engine_kind_str += "/";
69  engine_kind_str += engine_kind2str_upper(*it);
70  }
71 
72  std::cout << "Example " << (exit_code ? "failed" : "passed") << " on "
73  << engine_kind_str << "." << std::endl;
74  return exit_code;
75 }
76 
77 // Same as above, but for functions with signature
78 // void(dnnl::engine::kind engine_kind, int argc, char **argv).
79 inline int handle_example_errors(
80  std::function<void(dnnl::engine::kind, int, char **)> example,
81  dnnl::engine::kind engine_kind, int argc, char **argv) {
82  return handle_example_errors(
83  {engine_kind}, [&]() { example(engine_kind, argc, argv); });
84 }
85 
86 // Same as above, but for functions with signature void(dnnl::engine::kind).
87 inline int handle_example_errors(
88  std::function<void(dnnl::engine::kind)> example,
89  dnnl::engine::kind engine_kind) {
90  return handle_example_errors(
91  {engine_kind}, [&]() { example(engine_kind); });
92 }
93 
94 inline dnnl::engine::kind parse_engine_kind(
95  int argc, char **argv, int extra_args = 0) {
96  // Returns default engine kind, i.e. CPU, if none given
97  if (argc == 1) {
99  } else if (argc <= extra_args + 2) {
100  std::string engine_kind_str = argv[1];
101  // Checking the engine type, i.e. CPU or GPU
102  if (engine_kind_str == "cpu") {
104  } else if (engine_kind_str == "gpu") {
105  // Checking if a GPU exists on the machine
107  std::cout << "Could not find compatible GPU" << std::endl
108  << "Please run the example with CPU instead"
109  << std::endl;
110  exit(1);
111  }
113  }
114  }
115 
116  // If all above fails, the example should be ran properly
117  std::cout << "Inappropriate engine kind." << std::endl
118  << "Please run the example like this: " << argv[0] << " [cpu|gpu]"
119  << (extra_args ? " [extra arguments]" : "") << "." << std::endl;
120  exit(1);
121 }
122 
123 inline const char *engine_kind2str_upper(dnnl::engine::kind kind) {
124  if (kind == dnnl::engine::kind::cpu) return "CPU";
125  if (kind == dnnl::engine::kind::gpu) return "GPU";
126  assert(!"not expected");
127  return "<Unknown engine>";
128 }
129 
130 // Read from memory, write to handle
131 inline void read_from_dnnl_memory(void *handle, dnnl::memory &mem) {
132  dnnl::engine eng = mem.get_engine();
133  size_t bytes = mem.get_desc().get_size();
134 
135  if (eng.get_kind() == dnnl::engine::kind::cpu) {
136  uint8_t *src = static_cast<uint8_t *>(mem.get_data_handle());
137  for (size_t i = 0; i < bytes; ++i)
138  ((uint8_t *)handle)[i] = src[i];
139  }
140 #if DNNL_GPU_RUNTIME == DNNL_RUNTIME_OCL
141  else if (eng.get_kind() == dnnl::engine::kind::gpu) {
142  dnnl::stream s(eng);
143  cl_command_queue q = s.get_ocl_command_queue();
144  cl_mem m = mem.get_ocl_mem_object();
145 
146  cl_int ret = clEnqueueReadBuffer(
147  q, m, CL_TRUE, 0, bytes, handle, 0, NULL, NULL);
148  if (ret != CL_SUCCESS)
149  throw std::runtime_error("clEnqueueReadBuffer failed.");
150  }
151 #endif
152 }
153 
154 // Read from handle, write to memory
155 inline void write_to_dnnl_memory(void *handle, dnnl::memory &mem) {
156  dnnl::engine eng = mem.get_engine();
157  size_t bytes = mem.get_desc().get_size();
158 
159  if (eng.get_kind() == dnnl::engine::kind::cpu) {
160  uint8_t *dst = static_cast<uint8_t *>(mem.get_data_handle());
161  for (size_t i = 0; i < bytes; ++i)
162  dst[i] = ((uint8_t *)handle)[i];
163  }
164 #if DNNL_GPU_RUNTIME == DNNL_RUNTIME_OCL
165  else if (eng.get_kind() == dnnl::engine::kind::gpu) {
166  dnnl::stream s(eng);
167  cl_command_queue q = s.get_ocl_command_queue();
168  cl_mem m = mem.get_ocl_mem_object();
169  size_t bytes = mem.get_desc().get_size();
170 
171  cl_int ret = clEnqueueWriteBuffer(
172  q, m, CL_TRUE, 0, bytes, handle, 0, NULL, NULL);
173  if (ret != CL_SUCCESS)
174  throw std::runtime_error("clEnqueueWriteBuffer failed.");
175  }
176 #endif
177 }
178 
179 #endif
void * get_data_handle() const
Returns the underlying memory buffer.
Definition: dnnl.hpp:1919
C++ API.
An execution engine.
Definition: dnnl.hpp:837
static size_t get_count(kind kind)
Returns the number of engines of a certain kind.
Definition: dnnl.hpp:861
DNNL exception class.
Definition: dnnl.hpp:87
const char * what() const noexcept override
Returns the explanatory string.
Definition: dnnl.hpp:99
kind
Kinds of engines.
Definition: dnnl.hpp:842
engine get_engine() const
Returns the associated engine.
Definition: dnnl.hpp:1909
Memory object.
Definition: dnnl.hpp:1119
Debug capabilities.
desc get_desc() const
Returns the associated memory descriptor.
Definition: dnnl.hpp:1901
cl_mem get_ocl_mem_object() const
Returns the OpenCL memory object associated with the memory.
Definition: dnnl.hpp:2002
size_t get_size() const
Returns size of the memory descriptor in bytes.
Definition: dnnl.hpp:1836
An execution stream.
Definition: dnnl.hpp:981