4#include "exec/single_thread_context.hpp"
42using namespace Kokkos::utils::callbacks;
44class TEST_CATEGORY(WhenAllTest)
77 using then_sndr_t =
decltype(stdexec::then(std::declval<schd_sndr_t>(), std::declval<functor_t>()));
80 using when_all_sndr_t = stdexec::transform_sender_result_t<
81 decltype(stdexec::when_all(std::declval<then_sndr_t>(), std::declval<then_sndr_t>())),
94static_assert(test_sndr_traits());
97consteval bool test_sndr_nothrow_transformable() {
98 using when_all_sndr_t =
decltype(stdexec::when_all(
99 stdexec::schedule(std::declval<
typename TEST_CATEGORY(WhenAllTest)::scheduler_t>()),
100 stdexec::schedule(std::declval<
typename TEST_CATEGORY(WhenAllTest)::scheduler_t>())
103 static_assert(std::same_as<
110 Tests::Utils::Functors::NoOp<false, false, false>,
116 static_assert(stdexec::__detail::__has_nothrow_transform_sender<
118 stdexec::set_value_t,
123 using when_all_maythrow_on_move_sndr_t =
decltype(stdexec::when_all(
124 stdexec::schedule(std::declval<
typename TEST_CATEGORY(WhenAllTest)::scheduler_t>()),
125 stdexec::schedule(std::declval<
typename TEST_CATEGORY(WhenAllTest)::scheduler_t>())
128 static_assert(!stdexec::__detail::__has_nothrow_transform_sender<
129 Kokkos::Execution::GraphImpl::Domain,
130 stdexec::set_value_t,
131 when_all_maythrow_on_move_sndr_t&&,
143 static_assert(!std::is_nothrow_constructible_v<Kokkos::Experimental::Graph<TEST_EXECUTION_SPACE>>);
145 using when_all_sndr_t =
decltype(stdexec::when_all(
146 stdexec::schedule(std::declval<
typename TEST_CATEGORY(WhenAllTest)::scheduler_t>()),
147 stdexec::schedule(std::declval<
typename TEST_CATEGORY(WhenAllTest)::scheduler_t>())
148 | stdexec::then(Tests::Utils::Functors::NoOp<false, false, false>{})));
150 static_assert(!stdexec::__nothrow_connectable<when_all_sndr_t, Tests::Utils::SinkReceiver>);
161template <
typename ExecA,
typename ExecB>
163 if constexpr (std::same_as<ExecA, ExecB>)
166 using sndr_t = stdexec::transform_sender_result_t<
167 decltype(stdexec::when_all(
176 stdexec::__not_a_sender<
177 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::CANNOT_DISPATCH_THIS_ALGORITHM_TO_THE_GRAPH_SCHEDULER),
178 stdexec::_WHY_(Kokkos::Execution::GraphImpl::BECAUSE_THE_EXECUTION_SPACE_TYPE_IS_NOT_HOMOGENEOUS),
179 stdexec::_WHERE_(stdexec::_IN_ALGORITHM_, stdexec::when_all_t),
184 stdexec::_WITH_SENDERS_<
196static_assert(test_sndr_cannot_mix_execution_space_type<TEST_EXECUTION_SPACE, Kokkos::DefaultHostExecutionSpace>());
202 using when_all_t =
decltype(stdexec::when_all(
203 stdexec::schedule(std::declval<scheduler_t>()), stdexec::schedule(std::declval<scheduler_t>())));
206 using op_state_t = stdexec::connect_result_t<when_all_t, rcvr_t>;
208 static_assert(std::is_empty_v<decltype(std::declval<op_state_t>().count)>);
213static_assert(test_count_is_empty_when_as_one());
226 static_assert(std::same_as<stdexec::tag_of_t<
decltype(sndr)>, stdexec::when_all_t>);
227 static_assert(std::same_as<
228 stdexec::__completion_domain_of_t<stdexec::set_value_t,
decltype(sndr)>,
235 ASSERT_THAT(recorded_events, testing::IsEmpty());
250 experimental::execution::single_thread_context stc{};
253 auto sndr = stdexec::when_all(
255 stdexec::schedule(stc.get_scheduler()) | stdexec::continues_on(gctx.
get_scheduler()) | stdexec::then([]() { }));
264 testing::ElementsAre(
285 const view_s_t data(Kokkos::view_alloc(
exec,
"data - shared space"));
291 static_assert(std::same_as<
292 decltype(stdexec::get_completion_domain<stdexec::set_value_t>(stdexec::get_env(sndr))),
296 static_assert(std::same_as<stdexec::tag_of_t<
decltype(sndr)>, stdexec::then_t>);
301 ASSERT_EQ(data(), 0) <<
"Eager execution is not allowed.";
307 testing::ElementsAre(
314 ASSERT_EQ(data(), 1);
328 const view_s_t data(Kokkos::view_alloc(
exec,
"data - shared space"));
332 auto sndr = stdexec::when_all(
335 ASSERT_EQ(data(), 0) <<
"Eager execution is not allowed.";
343 testing::ElementsAre(
350 ASSERT_EQ(data(), 1);
364 const view_s_t data(Kokkos::view_alloc(
exec,
"data - shared space"));
371 auto sndr = stdexec::when_all(std::move(branch_a), std::move(branch_b));
373 ASSERT_EQ(data(), 0) <<
"Eager execution is not allowed.";
381 testing::ElementsAre(
388 recorded_events.at(0),
394 ASSERT_EQ(data(), 2);
410 const view_s_t data(Kokkos::view_alloc(
exec,
"data - shared space"));
418 auto sndr = stdexec::when_all(std::move(branch_a), std::move(branch_b), std::move(branch_c));
420 ASSERT_EQ(data(), 0) <<
"Eager execution is not allowed.";
428 testing::ElementsAre(
437 recorded_events.at(0),
444 ASSERT_EQ(data(), 3);
464 const Kokkos::View<value_t[3], Kokkos::SharedSpace> data_per_branch(Kokkos::view_alloc(
"data - shared space"));
466 experimental::execution::single_thread_context stc_a{}, stc_b{}, stc_c{};
473 auto branch_a = stdexec::schedule(stc_a.get_scheduler())
474 | stdexec::then(functor_h_t{.prev = 0, .value = 2, .data = &data_per_branch(0)})
476 | stdexec::then(functor_d_t{.prev = 2, .value = 3, .data = &data_per_branch(0)});
477 auto branch_b = stdexec::schedule(stc_b.get_scheduler())
478 | stdexec::then(functor_h_t{.prev = 0, .value = 3, .data = &data_per_branch(1)})
480 | stdexec::then(functor_d_t{.prev = 3, .value = 4, .data = &data_per_branch(1)});
481 auto branch_c = stdexec::schedule(stc_c.get_scheduler())
482 | stdexec::then(functor_h_t{.prev = 0, .value = 4, .data = &data_per_branch(2)})
484 | stdexec::then(functor_d_t{.prev = 4, .value = 5, .data = &data_per_branch(2)});
486 auto sndr = stdexec::when_all(
487 std::move(branch_a), std::move(branch_b), std::move(branch_c));
490 <<
"Eager execution is not " "allowed.";
499 testing::ElementsAre(
508 recorded_events.at(0),
532 const Kokkos::View<value_t[3], Kokkos::SharedSpace> data_per_branch(Kokkos::view_alloc(
"data - shared space"));
534 experimental::execution::single_thread_context stc_a{}, stc_b{};
541 auto branch_a = stdexec::schedule(stc_a.get_scheduler())
542 | stdexec::then(functor_h_t{.prev = 0, .value = 2, .data = &data_per_branch(0)})
544 | stdexec::then(functor_d_t{.prev = 2, .value = 3, .data = &data_per_branch(0)});
545 auto branch_b = stdexec::schedule(stc_b.get_scheduler())
546 | stdexec::then(functor_h_t{.prev = 0, .value = 3, .data = &data_per_branch(1)})
548 | stdexec::then(functor_d_t{.prev = 3, .value = 4, .data = &data_per_branch(1)});
550 | stdexec::then(functor_d_t{.prev = 0, .value = 4, .data = &data_per_branch(2)});
552 auto sndr = stdexec::when_all(
553 std::move(branch_a), std::move(branch_b), std::move(branch_c));
556 <<
"Eager execution is not " "allowed.";
565 testing::ElementsAre(
574 recorded_events.at(0),
594 const view_s_t data(Kokkos::view_alloc(
exec,
"data - shared space"));
596 std::atomic<size_t> count = 0;
602 stdexec::sender
auto sndr =
605 stdexec::read_env(stdexec::get_allocator)
606 | stdexec::then([&value](
auto allocator) { value = Tests::Utils::round_trip_allocate(allocator, 42); })
611 ASSERT_EQ(data(), 0) <<
"Eager execution is not allowed.";
619 testing::ElementsAre(
626 ASSERT_EQ(data(), 1);
628 ASSERT_EQ(value, 42);
642 using br_A_t =
decltype(std::declval<schd_sndr_t>() | stdexec::then(functor_t{}));
643 using br_B_t =
decltype(std::declval<schd_sndr_t>() | stdexec::then(functor_t{}));
646 using sndr_t =
decltype(stdexec::when_all(std::declval<br_A_t>(), std::declval<br_B_t>()));
648 using op_state_t = stdexec::connect_result_t<sndr_t, rcvr_t>;
654 static_assert(std::same_as<diagnose_t, stdexec::__msuccess>);
661static_assert(test_when_all_remains_on_graph_for_two_branches());
678 decltype(stdexec::schedule(std::declval<exec::single_thread_context&>().get_scheduler()) | stdexec::continues_on(std::declval<scheduler_t>()) | stdexec::then(functor_t{}));
681 using br_B_t =
decltype(std::declval<schd_sndr_t>() | stdexec::then(functor_t{}));
684 using sndr_t =
decltype(stdexec::when_all(std::declval<br_A_t>(), std::declval<br_B_t>()));
686 using op_state_t = stdexec::connect_result_t<sndr_t, rcvr_t>;
688 using op_state_br_A_t = stdexec::connect_result_t<br_A_t, typename op_state_t::WhenAllChildReceiver>;
699 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
700 stdexec::_WHY_(Kokkos::Execution::GraphImpl::BECAUSE_AT_LEAST_ONE_CHILD_DOES_NOT_REMAIN_ON_GRAPH),
702 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
704 Kokkos::Execution::GraphImpl::BECAUSE_THE_INNER_OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
706 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
708 Kokkos::Execution::GraphImpl::BECAUSE_THE_INNER_OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
710 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
712 typename op_state_br_A_t::inner_op_state_t::inner_op_state_t
729static_assert(test_when_all_does_not_remain_on_graph_for_two_branches());
746 decltype(stdexec::schedule(std::declval<exec::single_thread_context&>().get_scheduler()) | stdexec::continues_on(std::declval<scheduler_t>()) | stdexec::then(functor_t{}));
749 using br_B_t =
decltype(std::declval<schd_sndr_t>() | stdexec::then(functor_t{}));
753 decltype(stdexec::schedule(std::declval<exec::single_thread_context&>().get_scheduler()) | stdexec::continues_on(std::declval<scheduler_t>()) | stdexec::then(functor_t{}));
756 using sndr_t =
decltype(stdexec::when_all(std::declval<br_A_t>(), std::declval<br_B_t>(), std::declval<br_C_t>()));
758 using op_state_t = stdexec::connect_result_t<sndr_t, rcvr_t>;
760 using op_state_br_A_t = stdexec::connect_result_t<br_A_t, typename op_state_t::WhenAllChildReceiver>;
761 using op_state_br_C_t = stdexec::connect_result_t<br_C_t, typename op_state_t::WhenAllChildReceiver>;
772 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
773 stdexec::_WHY_(Kokkos::Execution::GraphImpl::BECAUSE_AT_LEAST_ONE_CHILD_DOES_NOT_REMAIN_ON_GRAPH),
776 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
778 Kokkos::Execution::GraphImpl::BECAUSE_THE_INNER_OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
780 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
782 Kokkos::Execution::GraphImpl::BECAUSE_THE_INNER_OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
784 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
786 typename op_state_br_A_t::inner_op_state_t::inner_op_state_t
797 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
799 Kokkos::Execution::GraphImpl::BECAUSE_THE_INNER_OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
801 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
803 Kokkos::Execution::GraphImpl::BECAUSE_THE_INNER_OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
805 stdexec::_WHAT_(Kokkos::Execution::GraphImpl::OPERATION_STATE_DOES_NOT_REMAIN_ON_GRAPH),
807 typename op_state_br_C_t::inner_op_state_t::inner_op_state_t
825static_assert(test_when_all_does_not_remain_on_graph_for_three_branches());
constexpr std::string dispatch_label(const Exec &, const std::string_view label)
Get the dispatch label from Exec and label.
#define MATCHER_FOR_BEGIN_FENCE(_exec_, _label_)
#define TEST_CATEGORY(_name_)
device_handle_t default_device_handle
RecorderListener< ConjunctionMatcher< EventDiscardMatcher< TEST_EXECUTION_SPACE >, GraphEventDiscardMatcher< TEST_EXECUTION_SPACE > >, BeginFenceEvent, BeginParallelForEvent, AllocateDataEvent, DeallocateDataEvent, Kokkos::Execution::Impl::RecordEvent, Kokkos::Execution::Impl::WaitEvent, Kokkos::Execution::GraphImpl::GraphAddAggregateNodeEvent, Kokkos::Execution::GraphImpl::GraphAddNodeEvent, Kokkos::Execution::GraphImpl::GraphCreateEvent, Kokkos::Execution::GraphImpl::GraphInstantiateEvent, Kokkos::Execution::GraphImpl::GraphSubmitEvent > recorder_listener_t
Concept for a sender whose completion scheduler is Kokkos::Execution::GraphImpl::Scheduler.
Concept that constrains the type of a sender that dispatches a functor for execution.
#define KOKKOS_EXECUTION_THREADS_THROWS_ON_SYNC_WAIT_ASSERT_AND_SKIP(_sndr_)
#define KOKKOS_EXECUTION_TEST_UTILS_GRAPH_FENCE(_exec_)
#define KOKKOS_EXECUTION_STDEXEC_PRAGMA_DIAGNOSTIC_IGNORED
Basic list of ignored diagnostics when including anything from stdexec.
#define THEN_INCREMENT(_data_)
Add a then using Tests::Utils::Functors::Increment that may throw. // NOLINTNEXTLINE(cppcoreguideline...
#define THEN_INCREMENT_ATOMIC(_scope_, _data_)
Same as THEN_INCREMENT, using Tests::Utils::atomic_fetch_add. // NOLINTNEXTLINE(cppcoreguidelines-mac...
constexpr bool mandate_or_explain() noexcept
If T::value is false, diagnose.
typename Diagnose< Ts... >::type diagnose_t
consteval bool test_sndr_nothrow_transformable()
consteval bool test_count_is_empty_when_as_one()
consteval bool test_sndr_traits()
consteval bool test_when_all_does_not_remain_on_graph_for_two_branches()
consteval bool test_when_all_does_not_remain_on_graph_for_three_branches()
consteval bool test_when_all_remains_on_graph_for_two_branches()
consteval bool test_sndr_nothrow_connectable()
consteval bool test_sndr_cannot_mix_execution_space_type()
auto record_sync_wait(Sndr &&sndr)
constexpr check_rcvr_env_queryable_with_t< true, Queries... > check_rcvr_env_queryable_with
auto span_from(const ViewType &view) noexcept
Get a std::span from a rank-one Kokkos::View.
Execution context using Kokkos::Experimental::Graph under the hood.
auto get_scheduler() const noexcept -> GraphImpl::Scheduler< execution_space >
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph aggregate node is added.
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph node is added.
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph is created.
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph is instantiated.
Event to be sent to Kokkos::utils::callbacks::dispatch when a Kokkos graph is submitted.
Event to be sent to Kokkos::utils::callbacks::dispatch when calling record.
Receiver for stdexec::sync_wait.
Tag to be used to signal children errors.
Tag to be used to signal an execution space.
Event to be sent to Kokkos::utils::callbacks::dispatch when calling wait.
Similar to EventDiscardMatcher, for graph-related events.
Kokkos::View< value_t, Kokkos::SharedSpace > view_s_t
Kokkos::Execution::GraphContext< Exec > context_t
Load the value at data and check it is equal to prev. Then, add value to it.
Kokkos::Impl::DeviceHandle< Exec > device_handle_t
device_handle_t device_handle
A receiver that can handle all completions and does nothing with them.
A minimal tracking allocator.
#define MATCHER_FOR_GRAPH_CREATE(_device_handle_)
#define MATCHER_FOR_GRAPH_ADDNODE(_graph_create_event_variant_, _device_handle_, _predecessor_,...)
#define MATCHER_FOR_GRAPH_SUBMIT(_exec_, _graph_create_event_variant_)
#define MATCHER_FOR_GRAPH_ADD_AGGREGATE_NODE(_graph_create_event_variant_,...)
#define MATCHER_FOR_GRAPH_ROOT_NODE_OF(_graph_create_event_)
#define MATCHER_FOR_GRAPH_NODE_OF(_graph_add_node_event_)