Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_Graph.hpp
1 //@HEADER
2 // ************************************************************************
3 //
4 // Kokkos v. 4.0
5 // Copyright (2022) National Technology & Engineering
6 // Solutions of Sandia, LLC (NTESS).
7 //
8 // Under the terms of Contract DE-NA0003525 with NTESS,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12 // See https://kokkos.org/LICENSE for license information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //@HEADER
16 
17 #ifndef KOKKOS_GRAPH_HPP
18 #define KOKKOS_GRAPH_HPP
19 #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
20 #define KOKKOS_IMPL_PUBLIC_INCLUDE
21 #define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_GRAPH
22 #endif
23 
24 #include <Kokkos_Macros.hpp>
25 #include <impl/Kokkos_Error.hpp> // KOKKOS_EXPECTS
26 
27 #include <Kokkos_Graph_fwd.hpp>
28 #include <impl/Kokkos_GraphImpl_fwd.hpp>
29 
30 // GraphAccess needs to be defined, not just declared
31 #include <impl/Kokkos_GraphImpl.hpp>
32 
33 #include <functional>
34 #include <memory>
35 
36 namespace Kokkos {
37 namespace Experimental {
38 
39 //==============================================================================
40 // <editor-fold desc="Graph"> {{{1
41 
42 template <class ExecutionSpace = DefaultExecutionSpace>
43 struct [[nodiscard]] Graph {
44  static_assert(Kokkos::is_execution_space_v<ExecutionSpace>);
45 
46  public:
47  //----------------------------------------------------------------------------
48  // <editor-fold desc="public member types"> {{{2
49 
50  using execution_space = ExecutionSpace;
51  using graph = Graph;
52  using root_t = GraphNodeRef<ExecutionSpace>;
53 
54  // </editor-fold> end public member types }}}2
55  //----------------------------------------------------------------------------
56 
57  private:
58  //----------------------------------------------------------------------------
59  // <editor-fold desc="friends"> {{{2
60 
61  friend struct Kokkos::Impl::GraphAccess;
62 
63  // </editor-fold> end friends }}}2
64  //----------------------------------------------------------------------------
65 
66  //----------------------------------------------------------------------------
67  // <editor-fold desc="private data members"> {{{2
68 
69  using impl_t = Kokkos::Impl::GraphImpl<ExecutionSpace>;
70  using root_impl_t = typename impl_t::root_node_impl_t;
71 
72  std::shared_ptr<impl_t> m_impl_ptr = nullptr;
73  std::shared_ptr<root_impl_t> m_root = nullptr;
74 
75  // </editor-fold> end private data members }}}2
76  //----------------------------------------------------------------------------
77 
78  public:
79  // Construct an empty graph with a root node.
80  Graph(ExecutionSpace exec = ExecutionSpace{})
81  : m_impl_ptr{std::make_shared<impl_t>(std::move(exec))},
82  m_root{m_impl_ptr->create_root_node_ptr()} {}
83 
84 #if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_HIP) || \
85  defined(KOKKOS_ENABLE_SYCL)
86  // Construct a graph from a native graph, add a root node.
87  template <typename T>
88 #if defined(KOKKOS_ENABLE_CXX20)
89  requires std::same_as<ExecutionSpace, Kokkos::DefaultExecutionSpace>
90 #endif
91  Graph(ExecutionSpace exec, T&& native_graph)
92  : m_impl_ptr{std::make_shared<impl_t>(std::move(exec),
93  std::forward<T>(native_graph))},
94  m_root{m_impl_ptr->create_root_node_ptr()} {
95  }
96 #endif
97 
98  ExecutionSpace const& get_execution_space() const {
99  return m_impl_ptr->get_execution_space();
100  }
101 
102  // Once the graph is instantiated, it is undefined behavior to add nodes.
103  // TODO Add a locking mechanism to avoid users shooting themselves
104  // in the foot.
105  void instantiate() {
106  KOKKOS_EXPECTS(bool(m_impl_ptr))
107  (*m_impl_ptr).instantiate();
108  }
109 
110  auto root_node() const { return root_t{m_impl_ptr, m_root}; }
111 
112  void submit(const execution_space& exec) const {
113  KOKKOS_EXPECTS(bool(m_impl_ptr))
114  (*m_impl_ptr).submit(exec);
115  }
116 
117  void submit() const { submit(get_execution_space()); }
118 
119  decltype(auto) native_graph();
120 
121  decltype(auto) native_graph_exec();
122 };
123 
124 // </editor-fold> end Graph }}}1
125 //==============================================================================
126 
127 //==============================================================================
128 // <editor-fold desc="when_all"> {{{1
129 
130 template <class... PredecessorRefs>
131 // constraints (not intended for subsumption, though...)
132 // ((remove_cvref_t<PredecessorRefs> is a specialization of
133 // GraphNodeRef with get_root().get_graph_impl() as its GraphImpl)
134 // && ...)
135 auto when_all(PredecessorRefs&&... arg_pred_refs) {
136  // TODO @graph @desul-integration check the constraints and preconditions
137  // once we have folded conjunctions from
138  // desul
139  static_assert(sizeof...(PredecessorRefs) > 0,
140  "when_all() needs at least one predecessor.");
141  auto graph_ptr_impl =
142  Kokkos::Impl::GraphAccess::get_graph_weak_ptr(
143  std::get<0>(std::forward_as_tuple(arg_pred_refs...)))
144  .lock();
145  auto node_ptr_impl = graph_ptr_impl->create_aggregate_ptr(arg_pred_refs...);
146  graph_ptr_impl->add_node(node_ptr_impl);
147  (graph_ptr_impl->add_predecessor(node_ptr_impl, arg_pred_refs), ...);
148  return Kokkos::Impl::GraphAccess::make_graph_node_ref(
149  std::move(graph_ptr_impl), std::move(node_ptr_impl));
150 }
151 
152 // </editor-fold> end when_all }}}1
153 //==============================================================================
154 
155 //==============================================================================
156 // <editor-fold desc="create_graph"> {{{1
157 
158 template <class ExecutionSpace, class Closure>
159 Graph<ExecutionSpace> create_graph(ExecutionSpace ex, Closure&& arg_closure) {
160  // Create a shared pointer to the graph:
161  // We need an attorney class here so we have an implementation friend to
162  // create a Graph class without graph having public constructors. We can't
163  // just make `create_graph` itself a friend because of the way that friend
164  // function template injection works.
165  Graph<ExecutionSpace> rv{std::move(ex)};
166  // Invoke the user's graph construction closure
167  ((Closure&&)arg_closure)(rv.root_node());
168  // and given them back the graph
169  // KOKKOS_ENSURES(rv.m_impl_ptr.use_count() == 1)
170  return rv;
171 }
172 
173 template <
174  class ExecutionSpace = DefaultExecutionSpace,
175  class Closure = Kokkos::Impl::DoNotExplicitlySpecifyThisTemplateParameter>
176 std::enable_if_t<
177  !Kokkos::is_execution_space_v<Kokkos::Impl::remove_cvref_t<Closure>>,
178  Graph<ExecutionSpace>>
179 create_graph(Closure&& arg_closure) {
180  return create_graph(ExecutionSpace{}, (Closure&&)arg_closure);
181 }
182 
183 // </editor-fold> end create_graph }}}1
184 //==============================================================================
185 
186 template <class ExecutionSpace>
187 decltype(auto) Graph<ExecutionSpace>::native_graph() {
188  KOKKOS_EXPECTS(bool(m_impl_ptr));
189 #if defined(KOKKOS_ENABLE_CUDA)
190  if constexpr (std::is_same_v<ExecutionSpace, Kokkos::Cuda>) {
191  return m_impl_ptr->cuda_graph();
192  }
193 #elif defined(KOKKOS_ENABLE_HIP) && defined(KOKKOS_IMPL_HIP_NATIVE_GRAPH)
194  if constexpr (std::is_same_v<ExecutionSpace, Kokkos::HIP>) {
195  return m_impl_ptr->hip_graph();
196  }
197 #elif defined(KOKKOS_ENABLE_SYCL) && defined(KOKKOS_IMPL_SYCL_GRAPH_SUPPORT)
198  if constexpr (std::is_same_v<ExecutionSpace, Kokkos::SYCL>) {
199  return m_impl_ptr->sycl_graph();
200  }
201 #endif
202 }
203 
204 template <class ExecutionSpace>
205 decltype(auto) Graph<ExecutionSpace>::native_graph_exec() {
206  KOKKOS_EXPECTS(bool(m_impl_ptr));
207 #if defined(KOKKOS_ENABLE_CUDA)
208  if constexpr (std::is_same_v<ExecutionSpace, Kokkos::Cuda>) {
209  return m_impl_ptr->cuda_graph_exec();
210  }
211 #elif defined(KOKKOS_ENABLE_HIP) && defined(KOKKOS_IMPL_HIP_NATIVE_GRAPH)
212  if constexpr (std::is_same_v<ExecutionSpace, Kokkos::HIP>) {
213  return m_impl_ptr->hip_graph_exec();
214  }
215 #elif defined(KOKKOS_ENABLE_SYCL) && defined(KOKKOS_IMPL_SYCL_GRAPH_SUPPORT)
216  if constexpr (std::is_same_v<ExecutionSpace, Kokkos::SYCL>) {
217  return m_impl_ptr->sycl_graph_exec();
218  }
219 #endif
220 }
221 
222 } // end namespace Experimental
223 } // namespace Kokkos
224 
225 // Even though these things are separable, include them here for now so that
226 // the user only needs to include Kokkos_Graph.hpp to get the whole facility.
227 #include <Kokkos_GraphNode.hpp>
228 
229 #include <impl/Kokkos_GraphNodeImpl.hpp>
230 #include <impl/Kokkos_GraphNodeThenImpl.hpp>
231 #include <impl/Kokkos_Default_Graph_Impl.hpp>
232 #include <Cuda/Kokkos_Cuda_Graph_Impl.hpp>
233 #if defined(KOKKOS_ENABLE_HIP)
234 // The implementation of hipGraph in ROCm 5.2 is bugged, so we cannot use it.
235 #if defined(KOKKOS_IMPL_HIP_NATIVE_GRAPH)
236 #include <HIP/Kokkos_HIP_Graph_Impl.hpp>
237 #endif
238 #endif
239 #ifdef KOKKOS_IMPL_SYCL_GRAPH_SUPPORT
240 #include <SYCL/Kokkos_SYCL_Graph_Impl.hpp>
241 #endif
242 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_GRAPH
243 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
244 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_GRAPH
245 #endif
246 #endif // KOKKOS_GRAPH_HPP