DPC++ Runtime
Runtime libraries for oneAPI DPC++
graph.hpp
Go to the documentation of this file.
1 //==--------- graph.hpp --- SYCL graph extension ---------------------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #pragma once
10 
11 #include <sycl/accessor.hpp> // for detail::AccessorBaseHost
12 #include <sycl/context.hpp> // for context
13 #include <sycl/detail/export.hpp> // for __SYCL_EXPORT
14 #include <sycl/detail/kernel_desc.hpp> // for kernel_param_kind_t
15 #include <sycl/detail/property_helper.hpp> // for DataLessPropKind, PropWith...
16 #include <sycl/device.hpp> // for device
17 #include <sycl/nd_range.hpp> // for range, nd_range
18 #include <sycl/properties/property_traits.hpp> // for is_property, is_property_of
19 #include <sycl/property_list.hpp> // for property_list
20 
21 #include <functional> // for function
22 #include <memory> // for shared_ptr
23 #include <type_traits> // for true_type
24 #include <vector> // for vector
25 
26 namespace sycl {
27 inline namespace _V1 {
28 
29 class handler;
30 class queue;
31 class device;
32 namespace ext {
33 namespace oneapi {
34 namespace experimental {
35 
37 enum class graph_state {
38  modifiable,
39  executable,
40 };
41 
42 // Forward declare Graph class
43 template <graph_state State> class command_graph;
44 
45 namespace detail {
46 // List of sycl features and extensions which are not supported by graphs. Used
47 // for throwing errors when these features are used with graphs.
49  sycl_reductions = 0,
57 };
58 
59 inline const char *
61  using UGF = UnsupportedGraphFeatures;
62  switch (Feature) {
63  case UGF::sycl_reductions:
64  return "Reductions";
65  case UGF::sycl_specialization_constants:
66  return "Specialization Constants";
67  case UGF::sycl_kernel_bundle:
68  return "Kernel Bundles";
69  case UGF::sycl_ext_oneapi_kernel_properties:
70  return "sycl_ext_oneapi_kernel_properties";
71  case UGF::sycl_ext_oneapi_enqueue_barrier:
72  return "sycl_ext_oneapi_enqueue_barrier";
73  case UGF::sycl_ext_oneapi_memcpy2d:
74  return "sycl_ext_oneapi_memcpy2d";
75  case UGF::sycl_ext_oneapi_device_global:
76  return "sycl_ext_oneapi_device_global";
77  case UGF::sycl_ext_oneapi_bindless_images:
78  return "sycl_ext_oneapi_bindless_images";
79  }
80 
81  assert(false && "Unhandled graphs feature");
82  return {};
83 }
84 
85 class node_impl;
86 class graph_impl;
87 class exec_graph_impl;
88 class dynamic_parameter_impl;
89 } // namespace detail
90 
91 enum class node_type {
92  empty = 0,
93  subgraph = 1,
94  kernel = 2,
95  memcpy = 3,
96  memset = 4,
97  memfill = 5,
98  prefetch = 6,
99  memadvise = 7,
100  ext_oneapi_barrier = 8,
101  host_task = 9
102 };
103 
105 class __SYCL_EXPORT node {
106 public:
107  node() = delete;
108 
110  node_type get_type() const;
111 
113  std::vector<node> get_predecessors() const;
114 
116  std::vector<node> get_successors() const;
117 
120  static node get_node_from_event(event nodeEvent);
121 
123  template <int Dimensions>
124  void update_nd_range(nd_range<Dimensions> executionRange);
125 
127  template <int Dimensions> void update_range(range<Dimensions> executionRange);
128 
129 private:
130  node(const std::shared_ptr<detail::node_impl> &Impl) : impl(Impl) {}
131 
132  template <class Obj>
133  friend decltype(Obj::impl)
134  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
135  template <class T>
136  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
137 
138  std::shared_ptr<detail::node_impl> impl;
139 };
140 
141 namespace property {
142 namespace graph {
143 
146 class no_cycle_check : public ::sycl::detail::DataLessProperty<
147  ::sycl::detail::GraphNoCycleCheck> {
148 public:
149  no_cycle_check() = default;
150 };
151 
157  : public ::sycl::detail::DataLessProperty<
158  ::sycl::detail::GraphAssumeBufferOutlivesGraph> {
159 public:
161 };
162 
166  : public ::sycl::detail::DataLessProperty<::sycl::detail::GraphUpdatable> {
167 public:
168  updatable() = default;
169 };
170 } // namespace graph
171 
172 namespace node {
173 
176 class depends_on : public ::sycl::detail::PropertyWithData<
177  ::sycl::detail::GraphNodeDependencies> {
178 public:
179  template <typename... NodeTN> depends_on(NodeTN... nodes) : MDeps{nodes...} {}
180 
181  const std::vector<::sycl::ext::oneapi::experimental::node> &
183  return MDeps;
184  }
185 
186 private:
187  const std::vector<::sycl::ext::oneapi::experimental::node> MDeps;
188 };
189 
192 class depends_on_all_leaves : public ::sycl::detail::DataLessProperty<
193  ::sycl::detail::GraphDependOnAllLeaves> {
194 public:
196 };
197 
198 } // namespace node
199 } // namespace property
200 
201 template <graph_state State> class command_graph;
202 
203 namespace detail {
204 // Templateless modifiable command-graph base class.
205 class __SYCL_EXPORT modifiable_command_graph {
206 public:
211  modifiable_command_graph(const context &SyclContext, const device &SyclDevice,
212  const property_list &PropList = {});
213 
217  modifiable_command_graph(const queue &SyclQueue,
218  const property_list &PropList = {});
219 
223  node add(const property_list &PropList = {}) {
224  if (PropList.has_property<property::node::depends_on>()) {
225  auto Deps = PropList.get_property<property::node::depends_on>();
226  node Node = addImpl(Deps.get_dependencies());
227  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
228  addGraphLeafDependencies(Node);
229  }
230  return Node;
231  }
232  node Node = addImpl({});
233  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
234  addGraphLeafDependencies(Node);
235  }
236  return Node;
237  }
238 
243  template <typename T> node add(T CGF, const property_list &PropList = {}) {
244  if (PropList.has_property<property::node::depends_on>()) {
245  auto Deps = PropList.get_property<property::node::depends_on>();
246  node Node = addImpl(CGF, Deps.get_dependencies());
247  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
248  addGraphLeafDependencies(Node);
249  }
250  return Node;
251  }
252  node Node = addImpl(CGF, {});
253  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
254  addGraphLeafDependencies(Node);
255  }
256  return Node;
257  }
258 
262  void make_edge(node &Src, node &Dest);
263 
267  command_graph<graph_state::executable>
268  finalize(const property_list &PropList = {}) const;
269 
275  void begin_recording(queue &RecordingQueue,
276  const property_list &PropList = {});
277 
283  void begin_recording(const std::vector<queue> &RecordingQueues,
284  const property_list &PropList = {});
285 
287  void end_recording();
288 
291  void end_recording(queue &RecordingQueue);
292 
296  void end_recording(const std::vector<queue> &RecordingQueues);
297 
304  void print_graph(const std::string path, bool verbose = false) const;
305 
307  std::vector<node> get_nodes() const;
308 
310  std::vector<node> get_root_nodes() const;
311 
312 protected:
315  modifiable_command_graph(const std::shared_ptr<detail::graph_impl> &Impl)
316  : impl(Impl) {}
317 
322  node addImpl(std::function<void(handler &)> CGF,
323  const std::vector<node> &Dep);
324 
328  node addImpl(const std::vector<node> &Dep);
329 
333  void addGraphLeafDependencies(node Node);
334 
335  template <class Obj>
336  friend decltype(Obj::impl)
337  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
338  template <class T>
339  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
340 
341  std::shared_ptr<detail::graph_impl> impl;
342 };
343 
344 // Templateless executable command-graph base class.
345 class __SYCL_EXPORT executable_command_graph {
346 public:
349 
352  void update(const command_graph<graph_state::modifiable> &Graph);
353 
357  void update(const node &Node);
358 
362  void update(const std::vector<node> &Nodes);
363 
364 protected:
369  executable_command_graph(const std::shared_ptr<detail::graph_impl> &Graph,
370  const sycl::context &Ctx,
371  const property_list &PropList = {});
372 
373  template <class Obj>
374  friend decltype(Obj::impl)
375  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
376 
378  void finalizeImpl();
379 
380  std::shared_ptr<detail::exec_graph_impl> impl;
381 };
382 } // namespace detail
383 
385 template <graph_state State = graph_state::modifiable>
386 class command_graph : public detail::modifiable_command_graph {
387 public:
392  command_graph(const context &SyclContext, const device &SyclDevice,
393  const property_list &PropList = {})
394  : modifiable_command_graph(SyclContext, SyclDevice, PropList) {}
395 
399  command_graph(const queue &SyclQueue, const property_list &PropList = {})
400  : modifiable_command_graph(SyclQueue, PropList) {}
401 
402 private:
405  command_graph(const std::shared_ptr<detail::graph_impl> &Impl)
406  : modifiable_command_graph(Impl) {}
407 
408  template <class T>
409  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
410 };
411 
412 template <>
415 protected:
419 };
420 
421 namespace detail {
422 class __SYCL_EXPORT dynamic_parameter_base {
423 public:
426  Graph,
427  size_t ParamSize, const void *Data);
428 
429 protected:
430  void updateValue(const void *NewValue, size_t Size);
431 
432  void updateAccessor(const sycl::detail::AccessorBaseHost *Acc);
433  std::shared_ptr<dynamic_parameter_impl> impl;
434 
435  template <class Obj>
436  friend decltype(Obj::impl)
437  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
438 };
439 } // namespace detail
440 
441 template <typename ValueT>
442 class dynamic_parameter : public detail::dynamic_parameter_base {
443  static constexpr bool IsAccessor =
444  std::is_base_of_v<sycl::detail::AccessorBaseHost, ValueT>;
445  static constexpr sycl::detail::kernel_param_kind_t ParamType =
446  IsAccessor ? sycl::detail::kernel_param_kind_t::kind_accessor
447  : std::is_pointer_v<ValueT>
448  ? sycl::detail::kernel_param_kind_t::kind_pointer
449  : sycl::detail::kernel_param_kind_t::kind_std_layout;
450 
451 public:
456  const ValueT &Param)
457  : detail::dynamic_parameter_base(Graph, sizeof(ValueT), &Param) {}
458 
461  void update(const ValueT &NewValue) {
462  if constexpr (IsAccessor) {
464  } else {
465  detail::dynamic_parameter_base::updateValue(&NewValue, sizeof(ValueT));
466  }
467  }
468 };
469 
471 template <typename ValueT>
473  const ValueT &Param) -> dynamic_parameter<ValueT>;
474 template <graph_state State = graph_state::modifiable>
475 command_graph(const context &SyclContext, const device &SyclDevice,
476  const property_list &PropList) -> command_graph<State>;
477 
478 } // namespace experimental
479 } // namespace oneapi
480 } // namespace ext
481 
482 template <>
483 struct is_property<ext::oneapi::experimental::property::graph::no_cycle_check>
484  : std::true_type {};
485 
486 template <>
487 struct is_property<ext::oneapi::experimental::property::node::depends_on>
488  : std::true_type {};
489 
490 template <>
492  ext::oneapi::experimental::property::graph::no_cycle_check,
494  ext::oneapi::experimental::graph_state::modifiable>> : std::true_type {
495 };
496 
497 template <>
498 struct is_property_of<ext::oneapi::experimental::property::node::depends_on,
499  ext::oneapi::experimental::node> : std::true_type {};
500 
501 } // namespace _V1
502 } // namespace sycl
The file contains implementations of accessor class.
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:50
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Definition: event.hpp:44
command_graph(const queue &SyclQueue, const property_list &PropList={})
Constructor.
Definition: graph.hpp:399
command_graph(const context &SyclContext, const device &SyclDevice, const property_list &PropList={})
Constructor.
Definition: graph.hpp:392
void updateAccessor(const sycl::detail::AccessorBaseHost *Acc)
std::shared_ptr< dynamic_parameter_impl > impl
Definition: graph.hpp:433
Class representing the implementation of command_graph<executable>.
executable_command_graph()=delete
An executable command-graph is not user constructable.
Implementation details of command_graph<modifiable>.
Definition: graph_impl.hpp:794
command_graph< graph_state::executable > finalize(const property_list &PropList={}) const
Finalize modifiable graph into an executable graph.
void begin_recording(queue &RecordingQueue, const property_list &PropList={})
Change the state of a queue to be recording and associate this graph with it.
void begin_recording(const std::vector< queue > &RecordingQueues, const property_list &PropList={})
Change the state of multiple queues to be recording and associate this graph with each of them.
modifiable_command_graph(const std::shared_ptr< detail::graph_impl > &Impl)
Constructor used internally by the runtime.
Definition: graph.hpp:315
node add(const property_list &PropList={})
Add an empty node to the graph.
Definition: graph.hpp:223
modifiable_command_graph(const context &SyclContext, const device &SyclDevice, const property_list &PropList={})
Constructor.
modifiable_command_graph(const queue &SyclQueue, const property_list &PropList={})
Constructor.
node add(T CGF, const property_list &PropList={})
Add a command-group node to the graph.
Definition: graph.hpp:243
void update(const ValueT &NewValue)
Updates this dynamic parameter and all registered nodes with a new value.
Definition: graph.hpp:461
dynamic_parameter(experimental::command_graph< graph_state::modifiable > Graph, const ValueT &Param)
Constructs a new dynamic parameter.
Definition: graph.hpp:455
Class representing a node in the graph, returned by command_graph::add().
Definition: graph.hpp:105
void update_nd_range(nd_range< Dimensions > executionRange)
Update the ND-Range of this node if it is a kernel execution node.
void update_range(range< Dimensions > executionRange)
Update the Range of this node if it is a kernel execution node.
Property passed to command_graph constructor to allow buffers to be used with graphs.
Definition: graph.hpp:158
Property passed to command_graph constructor to disable checking for cycles.
Definition: graph.hpp:147
Property passed to command_graph<graph_state::modifiable>::finalize() to mark the resulting executabl...
Definition: graph.hpp:166
Property used to to add all previous graph leaves as dependencies when creating a new node with comma...
Definition: graph.hpp:193
Property used to define dependent nodes when creating a new node with command_graph::add().
Definition: graph.hpp:177
const std::vector<::sycl::ext::oneapi::experimental::node > & get_dependencies() const
Definition: graph.hpp:182
Command group handler class.
Definition: handler.hpp:458
Provides an abstraction of a SYCL kernel.
Definition: kernel.hpp:77
Defines the iteration domain of both the work-groups and the overall dispatch.
Definition: nd_range.hpp:22
Objects of the property_list class are containers for the SYCL properties.
Encapsulates a single SYCL queue which schedules kernels on a SYCL device.
Definition: queue.hpp:111
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:30
T createSyclObjFromImpl(decltype(T::impl) ImplObj)
Definition: impl_utils.hpp:48
const char * UnsupportedFeatureToString(UnsupportedGraphFeatures Feature)
Definition: graph.hpp:60
graph_state
State to template the command_graph class on.
Definition: graph.hpp:37
@ modifiable
In modifiable state, commands can be added to graph.
@ executable
In executable state, the graph is ready to execute.
command_graph(const context &SyclContext, const device &SyclDevice, const property_list &PropList) -> command_graph< State >
dynamic_parameter(experimental::command_graph< graph_state::modifiable > Graph, const ValueT &Param) -> dynamic_parameter< ValueT >
Additional CTAD deduction guides.
Definition: access.hpp:18