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/context.hpp> // for context
12 #include <sycl/detail/export.hpp> // for __SYCL_EXPORT
13 #include <sycl/detail/property_helper.hpp> // for DataLessPropKind, PropWith...
14 #include <sycl/device.hpp> // for device
15 #include <sycl/properties/property_traits.hpp> // for is_property, is_property_of
16 #include <sycl/property_list.hpp> // for property_list
17 
18 #include <functional> // for function
19 #include <memory> // for shared_ptr
20 #include <type_traits> // for true_type
21 #include <vector> // for vector
22 
23 namespace sycl {
24 inline namespace _V1 {
25 
26 class handler;
27 class queue;
28 class device;
29 namespace ext {
30 namespace oneapi {
31 namespace experimental {
32 
33 namespace detail {
34 // List of sycl features and extensions which are not supported by graphs. Used
35 // for throwing errors when these features are used with graphs.
37  sycl_reductions = 0,
45 };
46 
47 inline const char *
49  using UGF = UnsupportedGraphFeatures;
50  switch (Feature) {
51  case UGF::sycl_reductions:
52  return "Reductions";
53  case UGF::sycl_specialization_constants:
54  return "Specialization Constants";
55  case UGF::sycl_kernel_bundle:
56  return "Kernel Bundles";
57  case UGF::sycl_ext_oneapi_kernel_properties:
58  return "sycl_ext_oneapi_kernel_properties";
59  case UGF::sycl_ext_oneapi_enqueue_barrier:
60  return "sycl_ext_oneapi_enqueue_barrier";
61  case UGF::sycl_ext_oneapi_memcpy2d:
62  return "sycl_ext_oneapi_memcpy2d";
63  case UGF::sycl_ext_oneapi_device_global:
64  return "sycl_ext_oneapi_device_global";
65  case UGF::sycl_ext_oneapi_bindless_images:
66  return "sycl_ext_oneapi_bindless_images";
67  }
68 
69  assert(false && "Unhandled graphs feature");
70  return {};
71 }
72 
73 class node_impl;
74 class graph_impl;
75 class exec_graph_impl;
76 
77 } // namespace detail
78 
80 enum class graph_state {
81  modifiable,
82  executable,
83 };
84 
85 enum class node_type {
86  empty = 0,
87  subgraph = 1,
88  kernel = 2,
89  memcpy = 3,
90  memset = 4,
91  memfill = 5,
92  prefetch = 6,
93  memadvise = 7,
95  host_task = 9
96 };
97 
99 class __SYCL_EXPORT node {
100 public:
101  node() = delete;
102 
104  node_type get_type() const;
105 
107  std::vector<node> get_predecessors() const;
108 
110  std::vector<node> get_successors() const;
111 
114  static node get_node_from_event(event nodeEvent);
115 
116 private:
117  node(const std::shared_ptr<detail::node_impl> &Impl) : impl(Impl) {}
118 
119  template <class Obj>
120  friend decltype(Obj::impl)
121  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
122  template <class T>
123  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
124 
125  std::shared_ptr<detail::node_impl> impl;
126 };
127 
128 namespace property {
129 namespace graph {
130 
133 class no_cycle_check : public ::sycl::detail::DataLessProperty<
134  ::sycl::detail::GraphNoCycleCheck> {
135 public:
136  no_cycle_check() = default;
137 };
138 
144  : public ::sycl::detail::DataLessProperty<
145  ::sycl::detail::GraphAssumeBufferOutlivesGraph> {
146 public:
148 };
149 } // namespace graph
150 
151 namespace node {
152 
155 class depends_on : public ::sycl::detail::PropertyWithData<
156  ::sycl::detail::GraphNodeDependencies> {
157 public:
158  template <typename... NodeTN> depends_on(NodeTN... nodes) : MDeps{nodes...} {}
159 
160  const std::vector<::sycl::ext::oneapi::experimental::node> &
162  return MDeps;
163  }
164 
165 private:
166  const std::vector<::sycl::ext::oneapi::experimental::node> MDeps;
167 };
168 
171 class depends_on_all_leaves : public ::sycl::detail::DataLessProperty<
172  ::sycl::detail::GraphDependOnAllLeaves> {
173 public:
175 };
176 
177 } // namespace node
178 } // namespace property
179 
180 template <graph_state State> class command_graph;
181 
182 namespace detail {
183 // Templateless modifiable command-graph base class.
184 class __SYCL_EXPORT modifiable_command_graph {
185 public:
190  modifiable_command_graph(const context &SyclContext, const device &SyclDevice,
191  const property_list &PropList = {});
192 
196  modifiable_command_graph(const queue &SyclQueue,
197  const property_list &PropList = {});
198 
202  node add(const property_list &PropList = {}) {
203  if (PropList.has_property<property::node::depends_on>()) {
204  auto Deps = PropList.get_property<property::node::depends_on>();
205  node Node = addImpl(Deps.get_dependencies());
206  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
207  addGraphLeafDependencies(Node);
208  }
209  return Node;
210  }
211  node Node = addImpl({});
212  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
213  addGraphLeafDependencies(Node);
214  }
215  return Node;
216  }
217 
222  template <typename T> node add(T CGF, const property_list &PropList = {}) {
223  if (PropList.has_property<property::node::depends_on>()) {
224  auto Deps = PropList.get_property<property::node::depends_on>();
225  node Node = addImpl(CGF, Deps.get_dependencies());
226  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
227  addGraphLeafDependencies(Node);
228  }
229  return Node;
230  }
231  node Node = addImpl(CGF, {});
232  if (PropList.has_property<property::node::depends_on_all_leaves>()) {
233  addGraphLeafDependencies(Node);
234  }
235  return Node;
236  }
237 
241  void make_edge(node &Src, node &Dest);
242 
246  command_graph<graph_state::executable>
247  finalize(const property_list &PropList = {}) const;
248 
255  bool begin_recording(queue &RecordingQueue);
256 
263  bool begin_recording(const std::vector<queue> &RecordingQueues);
264 
268  bool end_recording();
269 
274  bool end_recording(queue &RecordingQueue);
275 
281  bool end_recording(const std::vector<queue> &RecordingQueues);
282 
289  void print_graph(const std::string path, bool verbose = false) const;
290 
292  std::vector<node> get_nodes() const;
293 
295  std::vector<node> get_root_nodes() const;
296 
297 protected:
300  modifiable_command_graph(const std::shared_ptr<detail::graph_impl> &Impl)
301  : impl(Impl) {}
302 
307  node addImpl(std::function<void(handler &)> CGF,
308  const std::vector<node> &Dep);
309 
313  node addImpl(const std::vector<node> &Dep);
314 
318  void addGraphLeafDependencies(node Node);
319 
320  template <class Obj>
321  friend decltype(Obj::impl)
322  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
323  template <class T>
324  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
325 
326  std::shared_ptr<detail::graph_impl> impl;
327 };
328 
329 // Templateless executable command-graph base class.
330 class __SYCL_EXPORT executable_command_graph {
331 public:
334 
337  void update(const command_graph<graph_state::modifiable> &Graph);
338 
339 protected:
343  executable_command_graph(const std::shared_ptr<detail::graph_impl> &Graph,
344  const sycl::context &Ctx);
345 
346  template <class Obj>
347  friend decltype(Obj::impl)
348  sycl::detail::getSyclObjImpl(const Obj &SyclObject);
349 
351  void finalizeImpl();
352 
353  std::shared_ptr<detail::exec_graph_impl> impl;
354 };
355 } // namespace detail
356 
358 template <graph_state State = graph_state::modifiable>
359 class command_graph : public detail::modifiable_command_graph {
360 public:
365  command_graph(const context &SyclContext, const device &SyclDevice,
366  const property_list &PropList = {})
367  : modifiable_command_graph(SyclContext, SyclDevice, PropList) {}
368 
372  command_graph(const queue &SyclQueue, const property_list &PropList = {})
373  : modifiable_command_graph(SyclQueue, PropList) {}
374 
375 private:
378  command_graph(const std::shared_ptr<detail::graph_impl> &Impl)
379  : modifiable_command_graph(Impl) {}
380 
381  template <class T>
382  friend T sycl::detail::createSyclObjFromImpl(decltype(T::impl) ImplObj);
383 };
384 
385 template <>
388 
389 protected:
393 };
394 
396 template <graph_state State = graph_state::modifiable>
397 command_graph(const context &SyclContext, const device &SyclDevice,
398  const property_list &PropList) -> command_graph<State>;
399 
400 } // namespace experimental
401 } // namespace oneapi
402 } // namespace ext
403 
404 template <>
405 struct is_property<ext::oneapi::experimental::property::graph::no_cycle_check>
406  : std::true_type {};
407 
408 template <>
409 struct is_property<ext::oneapi::experimental::property::node::depends_on>
410  : std::true_type {};
411 
412 template <>
414  ext::oneapi::experimental::property::graph::no_cycle_check,
416  ext::oneapi::experimental::graph_state::modifiable>> : std::true_type {
417 };
418 
419 template <>
420 struct is_property_of<ext::oneapi::experimental::property::node::depends_on,
421  ext::oneapi::experimental::node> : std::true_type {};
422 
423 } // namespace _V1
424 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:51
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:59
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:372
command_graph(const context &SyclContext, const device &SyclDevice, const property_list &PropList={})
Constructor.
Definition: graph.hpp:365
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:565
command_graph< graph_state::executable > finalize(const property_list &PropList={}) const
Finalize modifiable graph into an executable graph.
modifiable_command_graph(const std::shared_ptr< detail::graph_impl > &Impl)
Constructor used internally by the runtime.
Definition: graph.hpp:300
node add(const property_list &PropList={})
Add an empty node to the graph.
Definition: graph.hpp:202
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:222
Class representing a node in the graph, returned by command_graph::add().
Definition: graph.hpp:99
Property passed to command_graph constructor to allow buffers to be used with graphs.
Definition: graph.hpp:145
Property passed to command_graph constructor to disable checking for cycles.
Definition: graph.hpp:134
Property used to to add all previous graph leaves as dependencies when creating a new node with comma...
Definition: graph.hpp:172
Property used to define dependent nodes when creating a new node with command_graph::add().
Definition: graph.hpp:156
const std::vector<::sycl::ext::oneapi::experimental::node > & get_dependencies() const
Definition: graph.hpp:161
Command group handler class.
Definition: handler.hpp:454
Provides an abstraction of a SYCL kernel.
Definition: kernel.hpp:74
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:119
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:48
graph_state
State to template the command_graph class on.
Definition: graph.hpp:80
@ 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 >
Additional CTAD deduction guide.
Definition: access.hpp:18