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 ext::oneapi::experimental classes
43 template <graph_state State> class command_graph;
44 class raw_kernel_arg;
45 
46 namespace detail {
47 // List of sycl features and extensions which are not supported by graphs. Used
48 // for throwing errors when these features are used with graphs.
50  sycl_reductions = 0,
60 };
61 
62 inline const char *
64  using UGF = UnsupportedGraphFeatures;
65  switch (Feature) {
66  case UGF::sycl_reductions:
67  return "Reductions";
68  case UGF::sycl_specialization_constants:
69  return "Specialization Constants";
70  case UGF::sycl_kernel_bundle:
71  return "Kernel Bundles";
72  case UGF::sycl_ext_oneapi_kernel_properties:
73  return "sycl_ext_oneapi_kernel_properties";
74  case UGF::sycl_ext_oneapi_enqueue_barrier:
75  return "sycl_ext_oneapi_enqueue_barrier";
76  case UGF::sycl_ext_oneapi_memcpy2d:
77  return "sycl_ext_oneapi_memcpy2d";
78  case UGF::sycl_ext_oneapi_device_global:
79  return "sycl_ext_oneapi_device_global";
80  case UGF::sycl_ext_oneapi_bindless_images:
81  return "sycl_ext_oneapi_bindless_images";
82  case UGF::sycl_ext_oneapi_experimental_cuda_cluster_launch:
83  return "sycl_ext_oneapi_experimental_cuda_cluster_launch";
84  case UGF::sycl_ext_codeplay_enqueue_native_command:
85  return "sycl_ext_codeplay_enqueue_native_command";
86  }
87 
88  assert(false && "Unhandled graphs feature");
89  return {};
90 }
91 
92 class node_impl;
93 class graph_impl;
94 class exec_graph_impl;
95 class dynamic_parameter_impl;
96 } // namespace detail
97 
98 enum class node_type {
99  empty = 0,
100  subgraph = 1,
101  kernel = 2,
102  memcpy = 3,
103  memset = 4,
104  memfill = 5,
105  prefetch = 6,
106  memadvise = 7,
107  ext_oneapi_barrier = 8,
108  host_task = 9
109 };
110 
112 class __SYCL_EXPORT node {
113 public:
114  node() = delete;
115 
117  node_type get_type() const;
118 
120  std::vector<node> get_predecessors() const;
121 
123  std::vector<node> get_successors() const;
124 
127  static node get_node_from_event(event nodeEvent);
128 
130  template <int Dimensions>
131  void update_nd_range(nd_range<Dimensions> executionRange);
132 
134  template <int Dimensions> void update_range(range<Dimensions> executionRange);
135 
136 private:
137  node(const std::shared_ptr<detail::node_impl> &Impl) : impl(Impl) {}
138 
139  template <class Obj>
140  friend const decltype(Obj::impl) &
141  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
142  template <class T>
143  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
144 
145  std::shared_ptr<detail::node_impl> impl;
146 };
147 
148 namespace property {
149 namespace graph {
150 
153 class no_cycle_check : public ::sycl::detail::DataLessProperty<
154  ::sycl::detail::GraphNoCycleCheck> {
155 public:
156  no_cycle_check() = default;
157 };
158 
164  : public ::sycl::detail::DataLessProperty<
165  ::sycl::detail::GraphAssumeBufferOutlivesGraph> {
166 public:
168 };
169 
173  : public ::sycl::detail::DataLessProperty<::sycl::detail::GraphUpdatable> {
174 public:
175  updatable() = default;
176 };
177 
180 class enable_profiling : public ::sycl::detail::DataLessProperty<
181  ::sycl::detail::GraphEnableProfiling> {
182 public:
183  enable_profiling() = default;
184 };
185 } // namespace graph
186 
187 namespace node {
188 
191 class depends_on : public ::sycl::detail::PropertyWithData<
192  ::sycl::detail::GraphNodeDependencies> {
193 public:
194  template <typename... NodeTN> depends_on(NodeTN... nodes) : MDeps{nodes...} {}
195 
196  const std::vector<::sycl::ext::oneapi::experimental::node> &
198  return MDeps;
199  }
200 
201 private:
202  const std::vector<::sycl::ext::oneapi::experimental::node> MDeps;
203 };
204 
207 class depends_on_all_leaves : public ::sycl::detail::DataLessProperty<
208  ::sycl::detail::GraphDependOnAllLeaves> {
209 public:
211 };
212 
213 } // namespace node
214 } // namespace property
215 
216 namespace detail {
217 // Templateless modifiable command-graph base class.
218 class __SYCL_EXPORT modifiable_command_graph {
219 public:
224  modifiable_command_graph(const context &SyclContext, const device &SyclDevice,
225  const property_list &PropList = {});
226 
230  modifiable_command_graph(const queue &SyclQueue,
231  const property_list &PropList = {});
232 
236  node add(const property_list &PropList = {}) {
237  if (PropList.has_property<property::node::depends_on>()) {
238  auto Deps = PropList.get_property<property::node::depends_on>();
239  node Node = addImpl(Deps.get_dependencies());
240  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
241  addGraphLeafDependencies(Node);
242  }
243  return Node;
244  }
245  node Node = addImpl({});
246  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
247  addGraphLeafDependencies(Node);
248  }
249  return Node;
250  }
251 
256  template <typename T> node add(T CGF, const property_list &PropList = {}) {
257  if (PropList.has_property<property::node::depends_on>()) {
258  auto Deps = PropList.get_property<property::node::depends_on>();
259  node Node = addImpl(CGF, Deps.get_dependencies());
260  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
261  addGraphLeafDependencies(Node);
262  }
263  return Node;
264  }
265  node Node = addImpl(CGF, {});
266  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
267  addGraphLeafDependencies(Node);
268  }
269  return Node;
270  }
271 
275  void make_edge(node &Src, node &Dest);
276 
280  command_graph<graph_state::executable>
281  finalize(const property_list &PropList = {}) const;
282 
288  void begin_recording(queue &RecordingQueue,
289  const property_list &PropList = {});
290 
296  void begin_recording(const std::vector<queue> &RecordingQueues,
297  const property_list &PropList = {});
298 
300  void end_recording();
301 
304  void end_recording(queue &RecordingQueue);
305 
309  void end_recording(const std::vector<queue> &RecordingQueues);
310 
317  void print_graph(const std::string path, bool verbose = false) const;
318 
320  std::vector<node> get_nodes() const;
321 
323  std::vector<node> get_root_nodes() const;
324 
325 protected:
328  modifiable_command_graph(const std::shared_ptr<detail::graph_impl> &Impl)
329  : impl(Impl) {}
330 
335  node addImpl(std::function<void(handler &)> CGF,
336  const std::vector<node> &Dep);
337 
341  node addImpl(const std::vector<node> &Dep);
342 
346  void addGraphLeafDependencies(node Node);
347 
348  template <class Obj>
349  friend const decltype(Obj::impl) &
350  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
351  template <class T>
352  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
353 
354  std::shared_ptr<detail::graph_impl> impl;
355 };
356 
357 // Templateless executable command-graph base class.
358 class __SYCL_EXPORT executable_command_graph {
359 public:
362 
365  void update(const command_graph<graph_state::modifiable> &Graph);
366 
370  void update(const node &Node);
371 
375  void update(const std::vector<node> &Nodes);
376 
377 protected:
382  executable_command_graph(const std::shared_ptr<detail::graph_impl> &Graph,
383  const sycl::context &Ctx,
384  const property_list &PropList = {});
385 
386  template <class Obj>
387  friend const decltype(Obj::impl) &
388  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
389 
391  void finalizeImpl();
392 
393  std::shared_ptr<detail::exec_graph_impl> impl;
394 };
395 } // namespace detail
396 
398 template <graph_state State = graph_state::modifiable>
400 public:
405  command_graph(const context &SyclContext, const device &SyclDevice,
406  const property_list &PropList = {})
407  : modifiable_command_graph(SyclContext, SyclDevice, PropList) {}
408 
412  command_graph(const queue &SyclQueue, const property_list &PropList = {})
413  : modifiable_command_graph(SyclQueue, PropList) {}
414 
415 private:
418  command_graph(const std::shared_ptr<detail::graph_impl> &Impl)
419  : modifiable_command_graph(Impl) {}
420 
421  template <class T>
422  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
423 };
424 
425 template <>
428 protected:
432 };
433 
434 namespace detail {
435 class __SYCL_EXPORT dynamic_parameter_base {
436 public:
439  Graph,
440  size_t ParamSize, const void *Data);
441 
442 protected:
443  void updateValue(const void *NewValue, size_t Size);
444 
445  // Update a sycl_ext_oneapi_raw_kernel_arg parameter. Size parameter is
446  // ignored as it represents sizeof(raw_kernel_arg), which doesn't represent
447  // the number of underlying bytes.
448  void updateValue(const raw_kernel_arg *NewRawValue, size_t Size);
449 
450  void updateAccessor(const sycl::detail::AccessorBaseHost *Acc);
451  std::shared_ptr<dynamic_parameter_impl> impl;
452 
453  template <class Obj>
454  friend const decltype(Obj::impl) &
455  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
456 };
457 } // namespace detail
458 
459 template <typename ValueT>
461  static constexpr bool IsAccessor =
462  std::is_base_of_v<sycl::detail::AccessorBaseHost, ValueT>;
463  static constexpr sycl::detail::kernel_param_kind_t ParamType =
464  IsAccessor ? sycl::detail::kernel_param_kind_t::kind_accessor
465  : std::is_pointer_v<ValueT>
466  ? sycl::detail::kernel_param_kind_t::kind_pointer
467  : sycl::detail::kernel_param_kind_t::kind_std_layout;
468 
469 public:
474  const ValueT &Param)
475  : detail::dynamic_parameter_base(Graph, sizeof(ValueT), &Param) {}
476 
479  void update(const ValueT &NewValue) {
480  if constexpr (IsAccessor) {
482  } else {
483  detail::dynamic_parameter_base::updateValue(&NewValue, sizeof(ValueT));
484  }
485  }
486 };
487 
489 template <typename ValueT>
491  const ValueT &Param) -> dynamic_parameter<ValueT>;
492 template <graph_state State = graph_state::modifiable>
493 command_graph(const context &SyclContext, const device &SyclDevice,
494  const property_list &PropList) -> command_graph<State>;
495 
496 } // namespace experimental
497 } // namespace oneapi
498 } // namespace ext
499 
500 template <>
501 struct is_property<ext::oneapi::experimental::property::graph::no_cycle_check>
502  : std::true_type {};
503 
504 template <>
505 struct is_property<ext::oneapi::experimental::property::node::depends_on>
506  : std::true_type {};
507 
508 template <>
510  ext::oneapi::experimental::property::graph::no_cycle_check,
512  ext::oneapi::experimental::graph_state::modifiable>> : std::true_type {
513 };
514 
515 template <>
516 struct is_property_of<ext::oneapi::experimental::property::node::depends_on,
517  ext::oneapi::experimental::node> : std::true_type {};
518 
519 } // namespace _V1
520 } // 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:412
command_graph(const context &SyclContext, const device &SyclDevice, const property_list &PropList={})
Constructor.
Definition: graph.hpp:405
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:451
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:328
node add(const property_list &PropList={})
Add an empty node to the graph.
Definition: graph.hpp:236
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:256
void update(const ValueT &NewValue)
Updates this dynamic parameter and all registered nodes with a new value.
Definition: graph.hpp:479
dynamic_parameter(experimental::command_graph< graph_state::modifiable > Graph, const ValueT &Param)
Constructs a new dynamic parameter.
Definition: graph.hpp:473
Class representing a node in the graph, returned by command_graph::add().
Definition: graph.hpp:112
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:165
Property used to enable executable graph profiling.
Definition: graph.hpp:181
Property passed to command_graph constructor to disable checking for cycles.
Definition: graph.hpp:154
Property passed to command_graph<graph_state::modifiable>::finalize() to mark the resulting executabl...
Definition: graph.hpp:173
Property used to to add all previous graph leaves as dependencies when creating a new node with comma...
Definition: graph.hpp:208
Property used to define dependent nodes when creating a new node with command_graph::add().
Definition: graph.hpp:192
const std::vector<::sycl::ext::oneapi::experimental::node > & get_dependencies() const
Definition: graph.hpp:197
Command group handler class.
Definition: handler.hpp:478
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:63
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