17 #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
18 #include <Kokkos_Macros.hpp>
20 "Including non-public Kokkos header files is not allowed.");
22 #ifndef KOKKOS_KOKKOS_GRAPHNODE_HPP
23 #define KOKKOS_KOKKOS_GRAPHNODE_HPP
25 #include <Kokkos_Macros.hpp>
27 #include <impl/Kokkos_Error.hpp>
29 #include <Kokkos_Core_fwd.hpp>
30 #include <Kokkos_Graph_fwd.hpp>
31 #include <impl/Kokkos_GraphImpl_fwd.hpp>
32 #include <Kokkos_Parallel_Reduce.hpp>
33 #include <impl/Kokkos_GraphImpl_Utilities.hpp>
34 #include <impl/Kokkos_GraphImpl.hpp>
39 namespace Experimental {
41 template <
class ExecutionSpace,
class Kernel ,
51 std::is_same_v<Predecessor, TypeErasedTag> ||
52 Kokkos::Impl::is_specialization_of<Predecessor, GraphNodeRef>::value,
53 "Invalid predecessor template parameter given to GraphNodeRef");
56 Kokkos::is_execution_space<ExecutionSpace>::value,
57 "Invalid execution space template parameter given to GraphNodeRef");
59 static_assert(std::is_same_v<Predecessor, TypeErasedTag> ||
60 Kokkos::Impl::is_graph_kernel<Kernel>::value,
61 "Invalid kernel template parameter given to GraphNodeRef");
63 static_assert(!Kokkos::Impl::is_more_type_erased<Kernel, Predecessor>::value,
64 "The kernel of a graph node can't be more type-erased than the "
74 using execution_space = ExecutionSpace;
75 using graph_kernel = Kernel;
76 using graph_predecessor = Predecessor;
85 template <
class,
class,
class>
86 friend class GraphNodeRef;
87 friend struct Kokkos::Impl::GraphAccess;
95 using graph_impl_t = Kokkos::Impl::GraphImpl<ExecutionSpace>;
96 std::weak_ptr<graph_impl_t> m_graph_impl;
105 Kokkos::Impl::GraphNodeImpl<ExecutionSpace, Kernel, Predecessor>;
106 std::shared_ptr<node_impl_t> m_node_impl;
115 node_impl_t& get_node_impl()
const {
return *m_node_impl.get(); }
116 std::shared_ptr<node_impl_t>
const& get_node_ptr() const& {
119 std::shared_ptr<node_impl_t> get_node_ptr() && {
120 return std::move(m_node_impl);
122 std::weak_ptr<graph_impl_t> get_graph_weak_ptr()
const {
131 template <
class NextKernelDeduced>
132 auto _then_kernel(NextKernelDeduced&& arg_kernel)
const {
136 static_assert(Kokkos::Impl::is_specialization_of<
137 Kokkos::Impl::remove_cvref_t<NextKernelDeduced>,
138 Kokkos::Impl::GraphNodeKernelImpl>::value,
139 "Kokkos internal error");
141 auto graph_ptr = m_graph_impl.lock();
142 KOKKOS_EXPECTS(
bool(graph_ptr))
144 using next_kernel_t = Kokkos::Impl::remove_cvref_t<NextKernelDeduced>;
146 using return_t = GraphNodeRef<ExecutionSpace, next_kernel_t, GraphNodeRef>;
148 auto rv = Kokkos::Impl::GraphAccess::make_graph_node_ref(
150 Kokkos::Impl::GraphAccess::make_node_shared_ptr<
151 typename return_t::node_impl_t>(
152 m_node_impl->execution_space_instance(),
153 Kokkos::Impl::_graph_node_kernel_ctor_tag{},
154 (NextKernelDeduced&&)arg_kernel,
156 Kokkos::Impl::_graph_node_predecessor_ctor_tag{}, *
this));
160 graph_ptr->add_node(rv.m_node_impl);
163 graph_ptr->add_predecessor(rv.m_node_impl, *
this);
164 KOKKOS_ENSURES(
bool(rv.m_node_impl))
171 GraphNodeRef(std::weak_ptr<graph_impl_t> arg_graph_impl,
172 std::shared_ptr<node_impl_t> arg_node_impl)
173 : m_graph_impl(std::move(arg_graph_impl)),
174 m_node_impl(std::move(arg_node_impl)) {}
187 GraphNodeRef() noexcept = default;
188 GraphNodeRef(GraphNodeRef const&) = default;
189 GraphNodeRef(GraphNodeRef&&) noexcept = default;
190 GraphNodeRef& operator=(GraphNodeRef const&) = default;
191 GraphNodeRef& operator=(GraphNodeRef&&) noexcept = default;
192 ~GraphNodeRef() = default;
200 template <class OtherKernel, class OtherPredecessor,
203 !std::is_same_v<GraphNodeRef,
204 GraphNodeRef<execution_space, OtherKernel,
205 OtherPredecessor>> &&
207 Kokkos::Impl::is_compatible_type_erasure<
208 OtherKernel, graph_kernel>::value &&
210 Kokkos::Impl::is_compatible_type_erasure<
211 OtherPredecessor, graph_predecessor>::value,
215 GraphNodeRef<execution_space, OtherKernel, OtherPredecessor> const& other)
216 : m_graph_impl(other.m_graph_impl), m_node_impl(other.m_node_impl) {}
232 class Policy,
class Functor,
236 is_execution_policy<Kokkos::Impl::remove_cvref_t<Policy>>::value,
239 auto then_parallel_for(std::string arg_name, Policy&& arg_policy,
240 Functor&& functor)
const {
242 KOKKOS_EXPECTS(!m_graph_impl.expired())
243 KOKKOS_EXPECTS(
bool(m_node_impl))
251 using policy_t = Kokkos::Impl::remove_cvref_t<Policy>;
254 std::is_same<
typename policy_t::execution_space,
255 execution_space>::value,
258 "Execution Space mismatch between execution policy and graph");
260 auto policy = Experimental::require((Policy&&)arg_policy,
261 Kokkos::Impl::KernelInGraphProperty{});
263 using next_policy_t = decltype(policy);
264 using next_kernel_t =
265 Kokkos::Impl::GraphNodeKernelImpl<ExecutionSpace, next_policy_t,
266 std::decay_t<Functor>,
267 Kokkos::ParallelForTag>;
268 return this->_then_kernel(next_kernel_t{std::move(arg_name), policy.space(),
274 class Policy,
class Functor,
278 is_execution_policy<Kokkos::Impl::remove_cvref_t<Policy>>::value,
281 auto then_parallel_for(Policy&& policy, Functor&& functor)
const {
283 return this->then_parallel_for(
"", (Policy&&)policy, (Functor&&)functor);
286 template <
class Functor>
287 auto then_parallel_for(std::string name, std::size_t n,
288 Functor&& functor)
const {
290 return this->then_parallel_for(std::move(name),
295 template <
class Functor>
296 auto then_parallel_for(std::size_t n, Functor&& functor)
const {
298 return this->then_parallel_for(
"", n, (Functor&&)functor);
308 class Policy,
class Functor,
class ReturnType,
312 is_execution_policy<Kokkos::Impl::remove_cvref_t<Policy>>::value,
315 auto then_parallel_reduce(std::string arg_name, Policy&& arg_policy,
317 ReturnType&& return_value)
const {
318 auto graph_impl_ptr = m_graph_impl.lock();
319 KOKKOS_EXPECTS(
bool(graph_impl_ptr))
320 KOKKOS_EXPECTS(
bool(m_node_impl))
329 using policy_t = std::remove_cv_t<std::remove_reference_t<Policy>>;
331 std::is_same<typename policy_t::execution_space,
332 execution_space>::value,
335 "Execution Space mismatch between execution policy and graph");
343 if (Kokkos::Impl::parallel_reduce_needs_fence(
344 graph_impl_ptr->get_execution_space(), return_value)) {
345 Kokkos::Impl::throw_runtime_exception(
346 "Parallel reductions in graphs can't operate on Reducers that "
347 "reference a scalar because they can't complete synchronously. Use a "
348 "Kokkos::View instead and keep in mind the result will only be "
349 "available once the graph is submitted (or in tasks that depend on "
355 using return_type_remove_cvref =
356 std::remove_cv_t<std::remove_reference_t<ReturnType>>;
357 static_assert(Kokkos::is_view<return_type_remove_cvref>::value ||
358 Kokkos::is_reducer<return_type_remove_cvref>::value,
359 "Output argument to parallel reduce in a graph must be a "
360 "View or a Reducer");
362 if constexpr (Kokkos::is_reducer_v<return_type_remove_cvref>) {
365 ExecutionSpace,
typename return_type_remove_cvref::
366 result_view_type::memory_space>::accessible,
367 "The reduction target must be accessible by the graph execution "
373 typename return_type_remove_cvref::memory_space>::accessible,
374 "The reduction target must be accessible by the graph execution "
380 std::conditional_t<Kokkos::is_reducer<return_type_remove_cvref>::value,
381 return_type_remove_cvref,
382 const return_type_remove_cvref>;
383 using functor_type = Kokkos::Impl::remove_cvref_t<Functor>;
386 using return_value_adapter =
387 Kokkos::Impl::ParallelReduceReturnValue<void, return_type,
392 auto policy = Experimental::require((Policy&&)arg_policy,
393 Kokkos::Impl::KernelInGraphProperty{});
395 using passed_reducer_type =
typename return_value_adapter::reducer_type;
397 using reducer_selector = Kokkos::Impl::if_c<
398 std::is_same<InvalidType, passed_reducer_type>::value, functor_type,
399 passed_reducer_type>;
400 using analysis = Kokkos::Impl::FunctorAnalysis<
401 Kokkos::Impl::FunctorPatternInterface::REDUCE, Policy,
402 typename reducer_selector::type,
403 typename return_value_adapter::value_type>;
404 typename analysis::Reducer final_reducer(
405 reducer_selector::select(functor, return_value));
406 Kokkos::Impl::CombinedFunctorReducer<functor_type,
407 typename analysis::Reducer>
408 functor_reducer(functor, final_reducer);
410 using next_policy_t = decltype(policy);
411 using next_kernel_t =
412 Kokkos::Impl::GraphNodeKernelImpl<ExecutionSpace, next_policy_t,
413 decltype(functor_reducer),
414 Kokkos::ParallelReduceTag>;
416 return this->_then_kernel(next_kernel_t{
417 std::move(arg_name), graph_impl_ptr->get_execution_space(),
418 functor_reducer, (Policy&&)policy,
419 return_value_adapter::return_value(return_value, functor)});
423 class Policy,
class Functor,
class ReturnType,
427 is_execution_policy<Kokkos::Impl::remove_cvref_t<Policy>>::value,
430 auto then_parallel_reduce(Policy&& arg_policy, Functor&& functor,
431 ReturnType&& return_value)
const {
432 return this->then_parallel_reduce(
"", (Policy&&)arg_policy,
434 (ReturnType&&)return_value);
437 template <
class Functor,
class ReturnType>
438 auto then_parallel_reduce(std::string label,
439 typename execution_space::size_type idx_end,
441 ReturnType&& return_value)
const {
442 return this->then_parallel_reduce(
444 (Functor&&)functor, (ReturnType&&)return_value);
447 template <
class Functor,
class ReturnType>
448 auto then_parallel_reduce(
typename execution_space::size_type idx_end,
450 ReturnType&& return_value)
const {
451 return this->then_parallel_reduce(
"", idx_end, (Functor&&)functor,
452 (ReturnType&&)return_value);
464 #endif // KOKKOS_KOKKOS_GRAPHNODE_HPP
Can AccessSpace access MemorySpace ?
Execution policy for work over a range of an integral type.