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,
59 };
60 
61 inline const char *
63  using UGF = UnsupportedGraphFeatures;
64  switch (Feature) {
65  case UGF::sycl_reductions:
66  return "Reductions";
67  case UGF::sycl_specialization_constants:
68  return "Specialization Constants";
69  case UGF::sycl_kernel_bundle:
70  return "Kernel Bundles";
71  case UGF::sycl_ext_oneapi_kernel_properties:
72  return "sycl_ext_oneapi_kernel_properties";
73  case UGF::sycl_ext_oneapi_enqueue_barrier:
74  return "sycl_ext_oneapi_enqueue_barrier";
75  case UGF::sycl_ext_oneapi_memcpy2d:
76  return "sycl_ext_oneapi_memcpy2d";
77  case UGF::sycl_ext_oneapi_device_global:
78  return "sycl_ext_oneapi_device_global";
79  case UGF::sycl_ext_oneapi_bindless_images:
80  return "sycl_ext_oneapi_bindless_images";
81  case UGF::sycl_ext_oneapi_experimental_cuda_cluster_launch:
82  return "sycl_ext_oneapi_experimental_cuda_cluster_launch";
83  case UGF::sycl_ext_codeplay_enqueue_native_command:
84  return "sycl_ext_codeplay_enqueue_native_command";
85  }
86 
87  assert(false && "Unhandled graphs feature");
88  return {};
89 }
90 
91 class node_impl;
92 class graph_impl;
93 class exec_graph_impl;
94 class dynamic_parameter_impl;
95 } // namespace detail
96 
97 enum class node_type {
98  empty = 0,
99  subgraph = 1,
100  kernel = 2,
101  memcpy = 3,
102  memset = 4,
103  memfill = 5,
104  prefetch = 6,
105  memadvise = 7,
106  ext_oneapi_barrier = 8,
107  host_task = 9
108 };
109 
111 class __SYCL_EXPORT node {
112 public:
113  node() = delete;
114 
116  node_type get_type() const;
117 
119  std::vector<node> get_predecessors() const;
120 
122  std::vector<node> get_successors() const;
123 
126  static node get_node_from_event(event nodeEvent);
127 
129  template <int Dimensions>
130  void update_nd_range(nd_range<Dimensions> executionRange);
131 
133  template <int Dimensions> void update_range(range<Dimensions> executionRange);
134 
135 private:
136  node(const std::shared_ptr<detail::node_impl> &Impl) : impl(Impl) {}
137 
138  template <class Obj>
139  friend const decltype(Obj::impl) &
140  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
141  template <class T>
142  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
143 
144  std::shared_ptr<detail::node_impl> impl;
145 };
146 
147 namespace property {
148 namespace graph {
149 
152 class no_cycle_check : public ::sycl::detail::DataLessProperty<
153  ::sycl::detail::GraphNoCycleCheck> {
154 public:
155  no_cycle_check() = default;
156 };
157 
163  : public ::sycl::detail::DataLessProperty<
164  ::sycl::detail::GraphAssumeBufferOutlivesGraph> {
165 public:
167 };
168 
172  : public ::sycl::detail::DataLessProperty<::sycl::detail::GraphUpdatable> {
173 public:
174  updatable() = default;
175 };
176 
179 class enable_profiling : public ::sycl::detail::DataLessProperty<
180  ::sycl::detail::GraphEnableProfiling> {
181 public:
182  enable_profiling() = default;
183 };
184 } // namespace graph
185 
186 namespace node {
187 
190 class depends_on : public ::sycl::detail::PropertyWithData<
191  ::sycl::detail::GraphNodeDependencies> {
192 public:
193  template <typename... NodeTN> depends_on(NodeTN... nodes) : MDeps{nodes...} {}
194 
195  const std::vector<::sycl::ext::oneapi::experimental::node> &
197  return MDeps;
198  }
199 
200 private:
201  const std::vector<::sycl::ext::oneapi::experimental::node> MDeps;
202 };
203 
206 class depends_on_all_leaves : public ::sycl::detail::DataLessProperty<
207  ::sycl::detail::GraphDependOnAllLeaves> {
208 public:
210 };
211 
212 } // namespace node
213 } // namespace property
214 
215 namespace detail {
216 // Templateless modifiable command-graph base class.
217 class __SYCL_EXPORT modifiable_command_graph {
218 public:
223  modifiable_command_graph(const context &SyclContext, const device &SyclDevice,
224  const property_list &PropList = {});
225 
229  modifiable_command_graph(const queue &SyclQueue,
230  const property_list &PropList = {});
231 
235  node add(const property_list &PropList = {}) {
236  if (PropList.has_property<property::node::depends_on>()) {
237  auto Deps = PropList.get_property<property::node::depends_on>();
238  node Node = addImpl(Deps.get_dependencies());
239  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
240  addGraphLeafDependencies(Node);
241  }
242  return Node;
243  }
244  node Node = addImpl({});
245  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
246  addGraphLeafDependencies(Node);
247  }
248  return Node;
249  }
250 
255  template <typename T> node add(T CGF, const property_list &PropList = {}) {
256  if (PropList.has_property<property::node::depends_on>()) {
257  auto Deps = PropList.get_property<property::node::depends_on>();
258  node Node = addImpl(CGF, Deps.get_dependencies());
259  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
260  addGraphLeafDependencies(Node);
261  }
262  return Node;
263  }
264  node Node = addImpl(CGF, {});
265  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
266  addGraphLeafDependencies(Node);
267  }
268  return Node;
269  }
270 
274  void make_edge(node &Src, node &Dest);
275 
279  command_graph<graph_state::executable>
280  finalize(const property_list &PropList = {}) const;
281 
287  void begin_recording(queue &RecordingQueue,
288  const property_list &PropList = {});
289 
295  void begin_recording(const std::vector<queue> &RecordingQueues,
296  const property_list &PropList = {});
297 
299  void end_recording();
300 
303  void end_recording(queue &RecordingQueue);
304 
308  void end_recording(const std::vector<queue> &RecordingQueues);
309 
316  void print_graph(const std::string path, bool verbose = false) const;
317 
319  std::vector<node> get_nodes() const;
320 
322  std::vector<node> get_root_nodes() const;
323 
324 protected:
327  modifiable_command_graph(const std::shared_ptr<detail::graph_impl> &Impl)
328  : impl(Impl) {}
329 
334  node addImpl(std::function<void(handler &)> CGF,
335  const std::vector<node> &Dep);
336 
340  node addImpl(const std::vector<node> &Dep);
341 
345  void addGraphLeafDependencies(node Node);
346 
347  template <class Obj>
348  friend const decltype(Obj::impl) &
349  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
350  template <class T>
351  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
352 
353  std::shared_ptr<detail::graph_impl> impl;
354 };
355 
356 // Templateless executable command-graph base class.
357 class __SYCL_EXPORT executable_command_graph {
358 public:
361 
364  void update(const command_graph<graph_state::modifiable> &Graph);
365 
369  void update(const node &Node);
370 
374  void update(const std::vector<node> &Nodes);
375 
376 protected:
381  executable_command_graph(const std::shared_ptr<detail::graph_impl> &Graph,
382  const sycl::context &Ctx,
383  const property_list &PropList = {});
384 
385  template <class Obj>
386  friend const decltype(Obj::impl) &
387  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
388 
390  void finalizeImpl();
391 
392  std::shared_ptr<detail::exec_graph_impl> impl;
393 };
394 } // namespace detail
395 
397 template <graph_state State = graph_state::modifiable>
399 public:
404  command_graph(const context &SyclContext, const device &SyclDevice,
405  const property_list &PropList = {})
406  : modifiable_command_graph(SyclContext, SyclDevice, PropList) {}
407 
411  command_graph(const queue &SyclQueue, const property_list &PropList = {})
412  : modifiable_command_graph(SyclQueue, PropList) {}
413 
414 private:
417  command_graph(const std::shared_ptr<detail::graph_impl> &Impl)
418  : modifiable_command_graph(Impl) {}
419 
420  template <class T>
421  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
422 };
423 
424 template <>
427 protected:
431 };
432 
433 namespace detail {
434 class __SYCL_EXPORT dynamic_parameter_base {
435 public:
438  Graph,
439  size_t ParamSize, const void *Data);
440 
441 protected:
442  void updateValue(const void *NewValue, size_t Size);
443 
444  void updateAccessor(const sycl::detail::AccessorBaseHost *Acc);
445  std::shared_ptr<dynamic_parameter_impl> impl;
446 
447  template <class Obj>
448  friend const decltype(Obj::impl) &
449  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
450 };
451 } // namespace detail
452 
453 template <typename ValueT>
455  static constexpr bool IsAccessor =
456  std::is_base_of_v<sycl::detail::AccessorBaseHost, ValueT>;
457  static constexpr sycl::detail::kernel_param_kind_t ParamType =
458  IsAccessor ? sycl::detail::kernel_param_kind_t::kind_accessor
459  : std::is_pointer_v<ValueT>
460  ? sycl::detail::kernel_param_kind_t::kind_pointer
461  : sycl::detail::kernel_param_kind_t::kind_std_layout;
462 
463 public:
468  const ValueT &Param)
469  : detail::dynamic_parameter_base(Graph, sizeof(ValueT), &Param) {}
470 
473  void update(const ValueT &NewValue) {
474  if constexpr (IsAccessor) {
476  } else {
477  detail::dynamic_parameter_base::updateValue(&NewValue, sizeof(ValueT));
478  }
479  }
480 };
481 
483 template <typename ValueT>
485  const ValueT &Param) -> dynamic_parameter<ValueT>;
486 template <graph_state State = graph_state::modifiable>
487 command_graph(const context &SyclContext, const device &SyclDevice,
488  const property_list &PropList) -> command_graph<State>;
489 
490 } // namespace experimental
491 } // namespace oneapi
492 } // namespace ext
493 
494 template <>
495 struct is_property<ext::oneapi::experimental::property::graph::no_cycle_check>
496  : std::true_type {};
497 
498 template <>
499 struct is_property<ext::oneapi::experimental::property::node::depends_on>
500  : std::true_type {};
501 
502 template <>
504  ext::oneapi::experimental::property::graph::no_cycle_check,
506  ext::oneapi::experimental::graph_state::modifiable>> : std::true_type {
507 };
508 
509 template <>
510 struct is_property_of<ext::oneapi::experimental::property::node::depends_on,
511  ext::oneapi::experimental::node> : std::true_type {};
512 
513 } // namespace _V1
514 } // 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:411
command_graph(const context &SyclContext, const device &SyclDevice, const property_list &PropList={})
Constructor.
Definition: graph.hpp:404
void updateAccessor(const sycl::detail::AccessorBaseHost *Acc)
dynamic_parameter_base(sycl::ext::oneapi::experimental::command_graph< graph_state::modifiable > Graph, size_t ParamSize, const void *Data)
std::shared_ptr< dynamic_parameter_impl > impl
Definition: graph.hpp:445
executable_command_graph()=delete
An executable command-graph is not user constructable.
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:327
node add(const property_list &PropList={})
Add an empty node to the graph.
Definition: graph.hpp:235
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:255
void update(const ValueT &NewValue)
Updates this dynamic parameter and all registered nodes with a new value.
Definition: graph.hpp:473
dynamic_parameter(experimental::command_graph< graph_state::modifiable > Graph, const ValueT &Param)
Constructs a new dynamic parameter.
Definition: graph.hpp:467
Class representing a node in the graph, returned by command_graph::add().
Definition: graph.hpp:111
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:164
Property used to enable executable graph profiling.
Definition: graph.hpp:180
Property passed to command_graph constructor to disable checking for cycles.
Definition: graph.hpp:153
Property passed to command_graph<graph_state::modifiable>::finalize() to mark the resulting executabl...
Definition: graph.hpp:172
Property used to to add all previous graph leaves as dependencies when creating a new node with comma...
Definition: graph.hpp:207
Property used to define dependent nodes when creating a new node with command_graph::add().
Definition: graph.hpp:191
const std::vector<::sycl::ext::oneapi::experimental::node > & get_dependencies() const
Definition: graph.hpp:196
Command group handler class.
Definition: handler.hpp:467
Provides an abstraction of a SYCL kernel.
Definition: kernel.hpp:71
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:110
decltype(Obj::impl) const & getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:31
T createSyclObjFromImpl(decltype(T::impl) ImplObj)
Definition: impl_utils.hpp:40
const char * UnsupportedFeatureToString(UnsupportedGraphFeatures Feature)
Definition: graph.hpp:62
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