Intel clGPU
engine.hpp
1 // Copyright (c) 2017-2018 Intel Corporation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 #include <memory>
17 #include <exception>
18 #include <typeinfo>
19 #include <vector>
20 #include <type_traits>
21 #include <chrono>
22 #include <map>
23 #include <cassert>
24 
25 namespace iclgpu
26 {
27 class primitive_db;
28 
29 template <class T, class U>
30 auto down_pointer_cast(const std::shared_ptr<U>& r)
31 -> typename std::enable_if<std::is_base_of<U, T>::value && !std::is_same<U, T>::value, std::shared_ptr<T>>::type
32 {
33  auto res = std::dynamic_pointer_cast<T>(r);
34  if (!res)
35  throw std::bad_cast();
36  return res;
37 }
38 
39 template <class T, class U>
40 auto down_pointer_cast(const std::shared_ptr<U>& r)
41 -> typename std::enable_if<std::is_same<T, U>::value, std::shared_ptr<T>>::type
42 {
43  return r;
44 }
45 
46 struct engine;
47 
50 
52 struct engine_object : std::enable_shared_from_this<engine_object>
53 {
54  explicit engine_object(const std::shared_ptr<engine>& engine)
55  : _engine(engine) {}
56 
57  virtual ~engine_object() = default;
58 
60  template <class EngTy = engine>
61  auto get_engine() const
62  -> typename std::enable_if<std::is_base_of<engine, EngTy>::value, std::shared_ptr<EngTy>>::type
63  {
64  return down_pointer_cast<EngTy>(_engine);
65  }
66 
67 private:
68  std::shared_ptr<engine> _engine;
69 };
70 
73 {
74  using engine_object::engine_object;
77  virtual std::chrono::nanoseconds wait() = 0;
78 };
79 
82 {
83  typedef size_t id_t;
84 
85  command_queue(id_t id)
86  : _id(id) {}
87 
89  : _id(0) {}
90 
91  id_t id() const { return _id; }
92 private:
93  id_t _id;
94 };
95 
97 static const command_queue default_queue;
98 
101 {
102  using engine_object::engine_object;
103 
108  virtual std::shared_ptr<event> submit(const std::vector<std::shared_ptr<event>>& dependencies = {},
109  const command_queue& queue = default_queue) = 0;
110 };
111 
114 {
115  using engine_object::engine_object;
117  virtual size_t size() const = 0;
119  virtual void* get_host_ptr() = 0;
120 };
121 
123 enum direction { none = 0x0, input = 0x1, output = 0x2, inout = input | output };
124 
127 {
128 public:
129 
134  buffer_binding(void* ptr, size_t size = 0, direction dir = inout)
135  : _direction(dir)
136  , _host_ptr(ptr)
137  , _capacity(size)
138  , _size(size)
139  , _owning_engine(nullptr)
140  , _buffers({})
141  {
142  assert(_host_ptr);
143  }
144 
149  buffer_binding(const std::shared_ptr<buffer>& buffer, direction dir = inout, size_t size = 0)
150  : _direction(dir)
151  , _host_ptr(nullptr)
152  , _capacity(buffer->size())
153  , _size(size != 0 ? size : buffer->size())
154  , _owning_engine(buffer->get_engine())
155  , _buffers({{buffer->get_engine(), buffer}})
156  {
157  assert(_capacity >= _size);
158  }
159 
161  direction get_direction() const { return _direction; }
162 
165  direction set_direction(direction dir);
166 
168  const std::shared_ptr<engine>& get_owning_engine() const { return _owning_engine; }
169 
172  void* get_host_ptr() const;
173 
175  void reset_host_ptr() const;
176 
178  size_t size() const { return _size; }
179 
181  size_t capacity() const { return _capacity; }
182 
185  void size(size_t size);
186 
189  std::shared_ptr<buffer> get_buffer(const std::shared_ptr<engine>& engine) const;
190 
191  bool is_output() const { return (_direction & output) != 0; }
192  bool is_input() const { return (_direction & input) != 0; }
193 
195  bool is_defined() const
196  {
197  return _size != 0 && (_host_ptr || _owning_engine);
198  }
199 
200 protected:
201  direction _direction;
202  mutable void* _host_ptr;
203  size_t _capacity;
204  size_t _size;
205  std::shared_ptr<engine> _owning_engine;
206  mutable std::map<std::shared_ptr<engine>, std::shared_ptr<buffer>> _buffers;
207 };
208 
209 template <typename ElemTy> size_t sizeof_t() { return sizeof(ElemTy); }
210 template <> inline size_t sizeof_t<void>() { return 1; }
211 
214 {
215  using command::command;
216 };
217 
220 {
221  using command::command;
222 
224  void push_back(const std::shared_ptr<command>& command);
225 
226  std::shared_ptr<event> submit(const std::vector<std::shared_ptr<event>>& dependencies = {},
227  const command_queue& queue = default_queue) override;
228 protected:
229  std::vector<std::shared_ptr<command>> _commands;
230 };
231 
234 {
235  using command::command;
236 
238  void add(const std::shared_ptr<command>& command);
239 
240  std::shared_ptr<event> submit(const std::vector<std::shared_ptr<event>>& dependencies = {},
241  const command_queue& queue = default_queue) override;
242 private:
243  std::vector<std::shared_ptr<command>> _commands;
244 };
245 
247 struct nd_range
248 {
249  nd_range()
250  : _size(0)
251  , _values{0, 0, 0} {}
252 
253  nd_range(size_t x)
254  : _size(1)
255  , _values{x, 0, 0} {}
256 
257  nd_range(size_t x, size_t y)
258  : _size(2)
259  , _values{x, y, 0} {}
260 
261  nd_range(size_t x, size_t y, size_t z)
262  : _size(3)
263  , _values{x, y, z} {}
264 
265  size_t dimensions() const { return _size; }
266  const size_t* values() const { return _values; }
267 
268  const size_t& operator[](size_t idx) const
269  {
270  assert(idx < _size);
271  return _values[idx];
272  }
273 
274  size_t& operator[](size_t idx)
275  {
276  assert(idx < _size);
277  return _values[idx];
278  }
279 
280 private:
281  size_t _size;
282  size_t _values[3];
283 };
284 
286 static const nd_range null_range;
287 
290 {
292  kernel_options(const nd_range& work_size, const nd_range& parallel_size = null_range);
293 
294  virtual ~kernel_options() = default;
295 
297  const nd_range& work_size() const { return _work_size; }
298 
300  const nd_range& parallel_size() const { return _parallel_size; }
301 private:
302  nd_range _work_size;
303  nd_range _parallel_size;
304 };
305 
308 {
309  using command::command;
310 
314  template <typename T>
315  auto set_arg(unsigned idx, const T& value)
316  -> typename std::enable_if<!std::is_pointer<T>::value>::type
317  {
318  set_scalar_arg(idx, &value, sizeof(T));
319  }
320 
324  void set_arg(unsigned idx, const std::shared_ptr<buffer_binding>& value)
325  {
326  assert(value->is_defined());
327  set_buffer_arg(idx, value);
328  }
329 
332  virtual void set_options(const kernel_options& params) = 0;
333 
334 protected:
340  virtual void set_scalar_arg(unsigned idx, const void* ptr, size_t size) = 0;
341 
346  virtual void set_buffer_arg(unsigned idx, const std::shared_ptr<buffer_binding>& binding) = 0;
347 };
348 
349 template <typename ElemTy, direction Dir> class blob;
350 
352 struct engine
353 {
354  virtual ~engine() = default;
355 
357  virtual primitive_db* get_primitive_db() = 0;
358 
362  virtual std::shared_ptr<kernel_command> get_kernel(const std::string& name,
363  const std::string& module = std::string()) = 0;
364 
368  virtual std::shared_ptr<buffer> create_buffer(size_t size, void* ptr = nullptr) = 0;
369 
371  virtual std::shared_ptr<raise_event_command> get_raise_event_command() = 0;
372 
375  virtual std::shared_ptr<commands_sequence> get_commands_sequence(const std::vector<std::shared_ptr<command>>& commands = {}) = 0;
376 
379  virtual std::shared_ptr<commands_parallel> get_commands_parallel(const std::vector<std::shared_ptr<command>>& commands = {}) = 0;
380 
382  template <typename T = char>
383  std::shared_ptr<buffer_binding> get_temp_buffer(size_t num)
384  {
385  if (num == 0) throw std::invalid_argument("size should not be zero.");
386  return std::make_shared<buffer_binding>(create_buffer(num * sizeof_t<T>(), nullptr), none);
387  }
388 
390  template <typename T, direction Dir>
391  static auto get_input_buffer(const blob<T, Dir>& blob, size_t num)
392  -> typename std::enable_if<(Dir & input) != 0, std::shared_ptr<buffer_binding>>::type
393  {
394  return set_binding_options<T>(blob.get(), num, input);
395  }
396 
398  template <typename T, direction Dir>
399  static auto get_output_buffer(const blob<T, Dir>& blob, size_t num)
400  -> typename std::enable_if<(Dir & output) != 0, std::shared_ptr<buffer_binding>>::type
401  {
402  return set_binding_options<T>(blob.get(), num, output);
403  }
404 
406  template <typename T, direction Dir>
407  static auto get_inout_buffer(const blob<T, Dir>& blob, size_t num)
408  -> typename std::enable_if<Dir == inout, std::shared_ptr<buffer_binding>>::type
409  {
410  return set_binding_options<T>(blob.get(), num, Dir);
411  }
412 
413 private:
414  template <typename T>
415  static std::shared_ptr<buffer_binding> set_binding_options(std::shared_ptr<buffer_binding>&& binding,
416  size_t num,
417  direction dir)
418  {
419  binding->set_direction(dir);
420  binding->size(num * sizeof_t<T>());
421  return binding;
422  }
423 };
424 
425 
427 }
static auto get_inout_buffer(const blob< T, Dir > &blob, size_t num) -> typename std::enable_if< Dir==inout, std::shared_ptr< buffer_binding >>::type
Get in-out buffer binding from Blob object.
Definition: engine.hpp:407
Base class for a command.
Definition: engine.hpp:100
direction
Represents data direction for kernel command.
Definition: engine.hpp:123
bool is_defined() const
Check if binding is fully defined: size is set and constructed from correct host-allocated pointer of...
Definition: engine.hpp:195
const nd_range & work_size() const
Range for kernel instances (global worksize)
Definition: engine.hpp:297
auto get_engine() const -> typename std::enable_if< std::is_base_of< engine, EngTy >::value, std::shared_ptr< EngTy >>::type
Returns associated Engine object.
Definition: engine.hpp:61
Binds host data and memory buffers per engine describing data direction (in/out) for kernel...
Definition: engine.hpp:126
direction get_direction() const
Get direction of the binding.
Definition: engine.hpp:161
Represents a command queue within an Engine.
Definition: engine.hpp:81
Represents an event object assotiated with a executed Command.
Definition: engine.hpp:72
The base class for all Engine connected objects.
Definition: engine.hpp:52
Represents kernel command.
Definition: engine.hpp:307
Represents data Blob object passed to a Function.
Definition: engine.hpp:349
Base class for execution engines.
Definition: engine.hpp:352
buffer_binding(const std::shared_ptr< buffer > &buffer, direction dir=inout, size_t size=0)
Constructs binding from engine-allocated memory buffer.
Definition: engine.hpp:149
size_t capacity() const
Returns maximum possible size value.
Definition: engine.hpp:181
void set_arg(unsigned idx, const std::shared_ptr< buffer_binding > &value)
Set kernel argument (specialized for data buffers)
Definition: engine.hpp:324
auto set_arg(unsigned idx, const T &value) -> typename std::enable_if<!std::is_pointer< T >::value >::type
Set kernel argument.
Definition: engine.hpp:315
buffer_binding(void *ptr, size_t size=0, direction dir=inout)
Constructs binding from host-allocated buffer.
Definition: engine.hpp:134
Kernel execution options.
Definition: engine.hpp:289
size_t size() const
Returns size of data.
Definition: engine.hpp:178
const std::shared_ptr< engine > & get_owning_engine() const
Returns engine of the buffer passed to constructor or NULL if consrtucted from host-allocated data...
Definition: engine.hpp:168
const nd_range & parallel_size() const
Range of kernel instances to be executed in paralled (local worksize)
Definition: engine.hpp:300
std::shared_ptr< buffer_binding > get_temp_buffer(size_t num)
Create temporary buffer with num elements of T.
Definition: engine.hpp:383
Helper class to store kernel sources.
Represents set of command can be executed in parallel.
Definition: engine.hpp:233
Represents ND (1D, 2D, 3D) ranges for kernels executions.
Definition: engine.hpp:247
Represents set of command to be executed sequentially.
Definition: engine.hpp:219
Represents a command which just raises an event.
Definition: engine.hpp:213
Represents memory buffer.
Definition: engine.hpp:113