1#ifndef KOKKOS_EXECUTION_GRAPH_WHEN_ALL_HPP
2#define KOKKOS_EXECUTION_GRAPH_WHEN_ALL_HPP
6#if defined(KOKKOS_EXECUTION_ENABLE_DEBUG_LOGGING)
10#include "Kokkos_Macros.hpp"
11#ifdef KOKKOS_ENABLE_EXPERIMENTAL_CXX20_MODULES
15# include "Kokkos_Core.hpp"
16# include "Kokkos_Graph.hpp"
43template <Kokkos::ExecutionSpace Exec, stdexec::receiver Rcvr, stdexec::sender... Sndrs>
63 return this->
parent_op->get_predecessor();
75 stdexec::__many_of<stdexec::__q<Impl::queryable_for<get_node_t>::type>>,
84 stdexec::__mcount_if<stdexec::__mbind_back_q<RemainsOnGraphFor, Exec>>,
99 template <
typename OpState>
101 if constexpr (stdexec::__queryable_with<OpState, get_node_t>) {
102 using query_t = stdexec::__query_result_t<OpState, get_node_t>;
103 static_assert(std::is_lvalue_reference_v<query_t>);
104 return std::tuple<query_t>{opstate.query(
get_node)};
106 return std::tuple<>{};
110 static constexpr auto join() noexcept {
114 template <
typename Node>
115 static constexpr const Node&
join(
const Node&
node)
noexcept {
119 template <
typename... Nodes>
120 requires(
sizeof...(Nodes) >= 2)
121 static constexpr auto join(
const Nodes&... nodes) {
122 auto agg = Kokkos::Experimental::when_all(nodes...);
127 template <
typename ChildrenOpStates>
128 constexpr decltype(
auto)
operator()(
const ChildrenOpStates& children)
const {
129 return stdexec::__apply(
130 [](
const auto&... opstates) ->
decltype(
auto) {
132 [](
const auto&... nodes) ->
decltype(
auto) {
return join(nodes...); },
133 std::tuple_cat(
node_of(opstates)...));
139 using node_t = std::invoke_result_t<JoinOpStateNodes, const children_op_states_t&>;
147 [[no_unique_address]]
150 PRAGMA_DIAGNOSTIC_PUSH
151 KOKKOS_EXECUTION_PRAGMA_DIAGNOSTIC_IGNORED_DANGLING_REFERENCE
152 [[no_unique_address]]
154 PRAGMA_DIAGNOSTIC_POP
155 [[no_unique_address]]
160 :
base_t(std::move(rcvr_))
171 static_assert((std::same_as<decltype(children), Sndrs&&> && ...));
172 PRAGMA_DIAGNOSTIC_PUSH
173 PRAGMA_DIAGNOSTIC_IGNORED(
"-Wmissing-braces")
176 PRAGMA_DIAGNOSTIC_POP
179 , node(JoinOpStateNodes{}(children_op_states)) {
183 if constexpr (std::same_as<graph_composition_policy_t, GraphComposition::Create>) {
184 return state.get_root_node();
198 typename state_t::graph_t&
requires std::same_as<graph_composition_policy_t, GraphComposition::Create>
226 if (
count.value.fetch_sub(1) == 1) {
240 template <
typename Tag,
typename... Args>
241 requires(!std::same_as<Tag, stdexec::set_value_t>)
248#if defined(KOKKOS_EXECUTION_ENABLE_DEBUG_LOGGING)
249 PLOG_INFO <<
"Starting all branches before submission.";
251#if defined(__cpp_expansion_statements) && __cpp_expansion_statements >= 202506L
258 []<
typename... ChildOpStates>([[maybe_unused]] ChildOpStates&... ops)
noexcept {
273#if defined(KOKKOS_EXECUTION_ENABLE_DEBUG_LOGGING)
274 PLOG_INFO <<
"Submit the graph directly without starting the branches.";
286#if defined(KOKKOS_EXECUTION_ENABLE_DEBUG_LOGGING)
288 << Kokkos::Tools::Experimental::device_id(
state.get_device_handle().m_exec) <<
'.';
293 stdexec::set_error(std::move(this->
completion_signal.rcvr), std::current_exception());
303template <stdexec::operation_state OpState, Kokkos::ExecutionSpace Exec>
305 stdexec::__is_instance_of<OpState, Kokkos::Execution::GraphImpl::WhenAllOpState>
306 && std::same_as<typename OpState::execution_space, Exec>)
310template <stdexec::operation_state OpState, Kokkos::ExecutionSpace Exec>
313 && stdexec::__is_instance_of<OpState, Kokkos::Execution::GraphImpl::WhenAllOpState>)
315 template <stdexec::operation_state ChildOpState>
318 static constexpr bool value = stdexec::__mapply<
319 stdexec::__mall_of<stdexec::__q<RemainsOnGraphForChild>>,
320 typename OpState::children_op_states_t
324 using children_t = stdexec::__mapply<
325 stdexec::__mtransform<stdexec::__q<RemainsOnGraphForChild>, stdexec::__q<Impl::diagnose_t>>,
326 typename OpState::children_op_states_t
329 if constexpr (stdexec::__ok<Impl::first_error_t<children_t>>) {
330 return stdexec::__msuccess{};
332 return stdexec::__mexception<
333 stdexec::_WHAT_(OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
334 stdexec::_WHY_(BECAUSE_AT_LEAST_ONE_CHILD_DOES_NOT_REMAIN_ON_GRAPH),
343template <Kokkos::ExecutionSpace Exec, stdexec::sender... Sndrs>
350 template <
typename... Env>
353 query(stdexec::get_completion_domain_t<stdexec::set_value_t>,
const Env&...)
const noexcept ->
Domain {
359 template <
typename Self,
typename... Env>
361 return stdexec::completion_signatures<stdexec::set_value_t(), stdexec::set_error_t(std::exception_ptr)>{};
364 template <stdexec::receiver Rcvr>
368 constexpr auto get_env() const noexcept -> attrs {
375struct BECAUSE_THE_EXECUTION_SPACE_TYPE_IS_NOT_HOMOGENEOUS;
377template <
size_t Index,
typename Sndr>
382 template <
typename Env,
typename... Sndrs>
385 template <
typename Env,
typename... Sndrs>
386 auto operator()(
const Env&, stdexec::when_all_t, stdexec::__ignore, Sndrs&&... sndrs)
const
387 noexcept(std::is_nothrow_constructible_v<
typename trnsfrmd_sndr_t<Env, Sndrs...>::sndrs_t, Sndrs&&...>) {
392 if constexpr ((std::same_as<Impl::exec_of_t<Sndrs, Env>,
execution_space> && ...)) {
393 PRAGMA_DIAGNOSTIC_PUSH
394 PRAGMA_DIAGNOSTIC_IGNORED(
"-Wmissing-braces")
395 return trnsfrmd_sndr_t<Env, Sndrs...>{.sndrs = {std::forward<Sndrs>(sndrs)...}};
396 PRAGMA_DIAGNOSTIC_POP
399 STDEXEC_CONSTEXPR_LOCAL
bool map[] = {
400 !std::same_as<Impl::exec_of_t<stdexec::__m_at_c<0, Sndrs>, Env>,
execution_space>...};
401 STDEXEC_CONSTEXPR_LOCAL std::size_t index = stdexec::__pos_of(map, map +
sizeof...(Sndrs));
402 using invalid_sndr_t = stdexec::__m_at_c<index, Sndrs...>;
403 return stdexec::__not_a_sender<
404 stdexec::_WHAT_(CANNOT_DISPATCH_THIS_ALGORITHM_TO_THE_GRAPH_SCHEDULER),
405 stdexec::_WHY_(BECAUSE_THE_EXECUTION_SPACE_TYPE_IS_NOT_HOMOGENEOUS),
406 stdexec::_WHERE_(stdexec::_IN_ALGORITHM_, stdexec::when_all_t),
408 stdexec::_WITH_SENDERS_<Sndrs...>,
409 stdexec::_WITH_ENVIRONMENT_(Env)
415 STDEXEC_CONSTEXPR_LOCAL std::size_t index = stdexec::__pos_of(map, map +
sizeof...(Sndrs));
416 using invalid_sndr_t = stdexec::__m_at_c<index, Sndrs...>;
Concept for a sender whose completion scheduler is Kokkos::Execution::GraphImpl::Scheduler.
#define KOKKOS_EXECUTION_GET_ENV(_type_, _obj_)
Retrieve the environment of _obj_. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage).
#define KOKKOS_EXECUTION_RETURNS_BRACED(_type_,...)
Define a function by returning a list-initialized object of an explicit type.
void graph_add_aggregate_node_event(const NodeType &aggregate, const Predecessors &... predecessors)
Record an event for an aggregate node added after predecessors.
constexpr get_node_t get_node
auto * get_graph_impl_ptr(const NodeType &node) noexcept
Retrieve the raw graph pointer from a node.
void submit_graph(const Kokkos::Experimental::Graph< Exec > &graph, const Exec &exec)
Submit a graph and record the associated event with graph_submit_event.
auto no_graph_scheduler_in_env() noexcept
Show a better compile diagnostic when there is no Kokkos::Execution::GraphImpl::Scheduler found.
decltype(rebind< To >(static_cast< From * >(nullptr))) rebind_t
typename ExecOf< Args... >::type exec_of_t
Attach to the existing graph of the predecessor.
typename node_helper_t< Exec, Queryables... >::type node_t
void complete(stdexec::set_error_t, Error &&error) noexcept
completion_signal_t completion_signal
constexpr OpStateBase(Rcvr rcvr) noexcept(std::is_nothrow_constructible_v< completion_signal_t, Rcvr && >)
Operation state that adds all closures as a sequence of nodes.
static constexpr auto diagnose() noexcept
static constexpr bool value
RemainsOnGraphFor< ChildOpState, Exec > RemainsOnGraphForChild
Join the nodes of all operation states into one aggregate node.
static constexpr auto join(const Nodes &... nodes)
static constexpr const Node & join(const Node &node) noexcept
static constexpr auto join() noexcept
static constexpr auto node_of(const OpState &opstate) noexcept
Receiver for a child of stdexec::when_all.
auto query(get_node_t) const &noexcept -> const predecessor_t &
Operation state for stdexec::when_all.
PRAGMA_DIAGNOSTIC_PUSH KOKKOS_EXECUTION_PRAGMA_DIAGNOSTIC_IGNORED_DANGLING_REFERENCE node_t node
State< graph_composition_policy_t, execution_space > state_t
static constexpr std::size_t num_branches_not_remaining_on_graph
WhenAllOpState(stdexec::__tuple< Sndrs... > &&sndrs_, Rcvr &&rcvr_)
static constexpr std::size_t num_branches_remaining_on_graph
Determine how many branches remain on graph (and how many don't).
children_op_states_t children_op_states
stdexec::operation_state_tag operation_state_concept
static constexpr bool as_one
Determine if all branches remain fully on the graph, if connected to WhenAllChildReceiver.
void submit_graph() &noexcept
void start() &noexcept
If as_one is true, there is no need to start the branches.
auto query(get_graph_t) const &noexcept -> const typename state_t::graph_t &
std::conditional_t< at_least_one_child_adds_a_node, GraphComposition::policy_t< Rcvr >, GraphComposition::Attach > graph_composition_policy_t
stdexec::__tuple< stdexec::connect_result_t< Sndrs, WhenAllChildReceiver >... > children_op_states_t
static constexpr bool at_least_one_child_adds_a_node
Determine if at least one child operation state will add a node.
auto query(get_node_t) const &noexcept -> const node_t &requires(!Impl::empty< node_t >)
GraphComposition::node_t< Exec, Rcvr > predecessor_t
void complete(Tag, Args &&... args) &noexcept
void complete(stdexec::set_value_t) &noexcept
PRAGMA_DIAGNOSTIC_POP Impl::CompileTimeOptional<!as_one, std::atomic< size_t > > count
std::invoke_result_t< JoinOpStateNodes, const children_op_states_t & > node_t
OpStateBase< Exec, Rcvr > base_t
static constexpr std::size_t num_branches
Number of branches.
void submit_graph() &noexcept
const predecessor_t & get_predecessor() const noexcept
constexpr auto query(stdexec::get_completion_domain_t< stdexec::set_value_t >, const Env &...) const noexcept -> Domain
Sender for stdexec::when_all.
auto connect(Rcvr rcvr) &&noexcept(noexcept(WhenAllOpState< Exec, Rcvr, Sndrs... >{std::move(sndrs), std::move(rcvr)})) -> WhenAllOpState< Exec, Rcvr, Sndrs... >
stdexec::sender_tag sender_concept
constexpr auto get_env() const noexcept -> attrs
static consteval auto get_completion_signatures()
stdexec::__tuple< Sndrs... > sndrs_t
Compile-time optional value that holds a T when Enabled, is an empty type otherwise.
Receiver for an object parent_op that implements complete.
WhenAllOpState * parent_op
Kokkos::DefaultExecutionSpace execution_space