From ca5e2d0bb4e0546007dd2d21acbe302fd5d6a2cd Mon Sep 17 00:00:00 2001 From: Hartmut Kaiser Date: Tue, 25 Jul 2023 15:15:44 -0500 Subject: [PATCH 1/2] Making sure changed number of counts is propagated to executor --- .../container_algorithms/is_sorted.hpp | 2 +- .../hpx/parallel/util/detail/chunk_size.hpp | 56 +++- .../hpx/parallel/util/foreach_partitioner.hpp | 10 +- .../include/hpx/parallel/util/partitioner.hpp | 21 +- .../tests/regressions/CMakeLists.txt | 1 + .../tests/regressions/num_cores.cpp | 41 +++ .../tests/unit/algorithms/rotate_sender.cpp | 8 +- .../is_sorted_until_range.cpp | 43 +-- .../executors/execution_parameters_fwd.hpp | 23 +- .../hpx/execution/executors/num_cores.hpp | 9 + .../tests/regressions/is_executor_1691.cpp | 1 + .../unit/executor_parameters_dispatching.cpp | 280 ++++++++---------- .../disable_thread_stealing_executor.cpp | 32 ++ .../examples/executor_with_thread_hooks.cpp | 6 + .../hpx/executors/annotating_executor.hpp | 10 +- .../executors/datapar/execution_policy.hpp | 114 ++++++- .../datapar/execution_policy_fwd.hpp | 8 +- .../hpx/executors/execution_policy.hpp | 241 ++++++++++++++- .../hpx/executors/execution_policy_fwd.hpp | 16 +- .../executors/execution_policy_mappings.hpp | 2 +- .../executors/explicit_scheduler_executor.hpp | 18 +- .../hpx/executors/parallel_executor.hpp | 62 +++- .../restricted_thread_pool_executor.hpp | 15 +- .../hpx/executors/scheduler_executor.hpp | 18 +- .../hpx/executors/sequenced_executor.hpp | 29 +- .../hpx/executors/thread_pool_scheduler.hpp | 53 +++- .../executors/thread_pool_scheduler_bulk.hpp | 8 +- .../tests/regressions/pu_count_6184.cpp | 2 +- .../hpx/resiliency/replay_executor.hpp | 56 +++- .../hpx/resiliency/replicate_executor.hpp | 63 +++- .../functional/detail/tag_fallback_invoke.hpp | 4 +- .../functional/detail/tag_priority_invoke.hpp | 6 +- .../include/hpx/functional/tag_invoke.hpp | 2 +- .../examples/1d_stencil_4_checkpoint.cpp | 88 +++--- 34 files changed, 984 insertions(+), 364 deletions(-) create mode 100644 libs/core/algorithms/tests/regressions/num_cores.cpp diff --git a/libs/core/algorithms/include/hpx/parallel/container_algorithms/is_sorted.hpp b/libs/core/algorithms/include/hpx/parallel/container_algorithms/is_sorted.hpp index beed8d6b620f..f72353ebd092 100644 --- a/libs/core/algorithms/include/hpx/parallel/container_algorithms/is_sorted.hpp +++ b/libs/core/algorithms/include/hpx/parallel/container_algorithms/is_sorted.hpp @@ -508,7 +508,7 @@ namespace hpx { namespace ranges { namespace hpx::ranges { - inline constexpr struct is_sorted_t final + inline constexpr struct is_sorted_t : hpx::detail::tag_parallel_algorithm { private: diff --git a/libs/core/algorithms/include/hpx/parallel/util/detail/chunk_size.hpp b/libs/core/algorithms/include/hpx/parallel/util/detail/chunk_size.hpp index 22836ce2de03..691c399c5744 100644 --- a/libs/core/algorithms/include/hpx/parallel/util/detail/chunk_size.hpp +++ b/libs/core/algorithms/include/hpx/parallel/util/detail/chunk_size.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include @@ -132,7 +134,7 @@ namespace hpx::parallel::util::detail { template hpx::util::iterator_range> - get_bulk_iteration_shape(ExPolicy&& policy, IterOrR& it_or_r, + get_bulk_iteration_shape(ExPolicy& policy, IterOrR& it_or_r, std::size_t& count, Stride s = Stride(1)) { if (count == 0) @@ -166,6 +168,10 @@ namespace hpx::parallel::util::detail { // clang-format on } + // update executor with new values + policy = hpx::experimental::prefer( + execution::with_processing_units_count, policy, cores); + auto shape_begin = chunk_size_iterator(it_or_r, chunk_size, count); auto shape_end = chunk_size_iterator(last, chunk_size, count, count); @@ -175,7 +181,7 @@ namespace hpx::parallel::util::detail { template hpx::util::iterator_range> - get_bulk_iteration_shape(ExPolicy&& policy, std::vector& workitems, + get_bulk_iteration_shape(ExPolicy& policy, std::vector& workitems, F1&& f1, IterOrR& it_or_r, std::size_t& count, Stride s = Stride(1)) { if (count == 0) @@ -241,6 +247,10 @@ namespace hpx::parallel::util::detail { // clang-format on } + // update executor with new values + policy = hpx::experimental::prefer( + execution::with_processing_units_count, policy, cores); + auto shape_begin = chunk_size_iterator(it_or_r, chunk_size, count); auto shape_end = chunk_size_iterator(last, chunk_size, count, count); @@ -250,7 +260,7 @@ namespace hpx::parallel::util::detail { template std::vector> - get_bulk_iteration_shape_variable(ExPolicy&& policy, IterOrR& it_or_r, + get_bulk_iteration_shape_variable(ExPolicy& policy, IterOrR& it_or_r, std::size_t& count, Stride s = Stride(1)) { using tuple_type = hpx::tuple; @@ -308,27 +318,31 @@ namespace hpx::parallel::util::detail { } // clang-format on + // update executor with new values + policy = hpx::experimental::prefer( + execution::with_processing_units_count, policy, cores); + return shape; } template - decltype(auto) get_bulk_iteration_shape(std::false_type, ExPolicy&& policy, + decltype(auto) get_bulk_iteration_shape(std::false_type, ExPolicy& policy, std::vector& workitems, F1&& f1, FwdIter& begin, std::size_t& count, Stride s = Stride(1)) { - return get_bulk_iteration_shape(HPX_FORWARD(ExPolicy, policy), - workitems, HPX_FORWARD(F1, f1), begin, count, s); + return get_bulk_iteration_shape( + policy, workitems, HPX_FORWARD(F1, f1), begin, count, s); } template - decltype(auto) get_bulk_iteration_shape(std::true_type, ExPolicy&& policy, + decltype(auto) get_bulk_iteration_shape(std::true_type, ExPolicy& policy, std::vector& workitems, F1&& f1, FwdIter& begin, std::size_t& count, Stride s = Stride(1)) { - return get_bulk_iteration_shape_variable(HPX_FORWARD(ExPolicy, policy), - workitems, HPX_FORWARD(F1, f1), begin, count, s); + return get_bulk_iteration_shape_variable( + policy, workitems, HPX_FORWARD(F1, f1), begin, count, s); } /////////////////////////////////////////////////////////////////////////// @@ -360,7 +374,7 @@ namespace hpx::parallel::util::detail { typename Stride = std::size_t> hpx::util::iterator_range< parallel::util::detail::chunk_size_idx_iterator> - get_bulk_iteration_shape_idx(ExPolicy&& policy, FwdIter begin, + get_bulk_iteration_shape_idx(ExPolicy& policy, FwdIter begin, std::size_t count, Stride s = Stride(1)) { using iterator = @@ -397,6 +411,13 @@ namespace hpx::parallel::util::detail { // clang-format on } + // update executor with new values + policy = hpx::experimental::prefer( + execution::with_processing_units_count, policy, cores); + + using iterator = + parallel::util::detail::chunk_size_idx_iterator; + iterator shape_begin(begin, chunk_size, count, 0, 0); iterator shape_end(last, chunk_size, count, count, 0); @@ -407,7 +428,7 @@ namespace hpx::parallel::util::detail { typename Stride = std::size_t> hpx::util::iterator_range< parallel::util::detail::chunk_size_idx_iterator> - get_bulk_iteration_shape_idx(ExPolicy&& policy, + get_bulk_iteration_shape_idx(ExPolicy& policy, std::vector& workitems, F1&& f1, FwdIter begin, std::size_t count, Stride s = Stride(1)) { @@ -475,6 +496,13 @@ namespace hpx::parallel::util::detail { // clang-format on } + // update executor with new values + policy = hpx::experimental::prefer( + execution::with_processing_units_count, policy, cores); + + using iterator = + parallel::util::detail::chunk_size_idx_iterator; + iterator shape_begin(begin, chunk_size, count, 0, base_idx); iterator shape_end(last, chunk_size, count, count, base_idx); @@ -484,7 +512,7 @@ namespace hpx::parallel::util::detail { template std::vector> - get_bulk_iteration_shape_idx_variable(ExPolicy&& policy, FwdIter first, + get_bulk_iteration_shape_idx_variable(ExPolicy& policy, FwdIter first, std::size_t count, Stride s = Stride(1)) { using tuple_type = hpx::tuple; @@ -543,6 +571,10 @@ namespace hpx::parallel::util::detail { } // clang-format on + // update executor with new values + policy = hpx::experimental::prefer( + execution::with_processing_units_count, policy, cores); + return shape; } } // namespace hpx::parallel::util::detail diff --git a/libs/core/algorithms/include/hpx/parallel/util/foreach_partitioner.hpp b/libs/core/algorithms/include/hpx/parallel/util/foreach_partitioner.hpp index fccac47d871c..a47090890fc9 100644 --- a/libs/core/algorithms/include/hpx/parallel/util/foreach_partitioner.hpp +++ b/libs/core/algorithms/include/hpx/parallel/util/foreach_partitioner.hpp @@ -36,7 +36,7 @@ namespace hpx::parallel::util::detail { template auto foreach_partition( - ExPolicy&& policy, FwdIter first, std::size_t count, F&& f) + ExPolicy policy, FwdIter first, std::size_t count, F&& f) { // estimate a chunk size based on number of cores used using parameters_type = @@ -53,7 +53,7 @@ namespace hpx::parallel::util::detail { "has_variable_chunk_size and invokes_testing_function"); auto&& shape = detail::get_bulk_iteration_shape_idx_variable( - HPX_FORWARD(ExPolicy, policy), first, count); + policy, first, count); return execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, @@ -61,8 +61,8 @@ namespace hpx::parallel::util::detail { } else if constexpr (!invokes_testing_function) { - auto&& shape = detail::get_bulk_iteration_shape_idx( - HPX_FORWARD(ExPolicy, policy), first, count); + auto&& shape = + detail::get_bulk_iteration_shape_idx(policy, first, count); return execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, @@ -72,7 +72,7 @@ namespace hpx::parallel::util::detail { { std::vector> inititems; auto&& shape = detail::get_bulk_iteration_shape_idx( - HPX_FORWARD(ExPolicy, policy), inititems, f, first, count); + policy, inititems, f, first, count); auto&& workitems = execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, diff --git a/libs/core/algorithms/include/hpx/parallel/util/partitioner.hpp b/libs/core/algorithms/include/hpx/parallel/util/partitioner.hpp index 2decc47e4f19..d458e422a6e5 100644 --- a/libs/core/algorithms/include/hpx/parallel/util/partitioner.hpp +++ b/libs/core/algorithms/include/hpx/parallel/util/partitioner.hpp @@ -40,7 +40,7 @@ namespace hpx::parallel::util::detail { template - auto partition(ExPolicy&& policy, IterOrR it_or_r, std::size_t count, F&& f) + auto partition(ExPolicy policy, IterOrR it_or_r, std::size_t count, F&& f) { // estimate a chunk size based on number of cores used using parameters_type = @@ -57,7 +57,7 @@ namespace hpx::parallel::util::detail { "has_variable_chunk_size and invokes_testing_function"); auto&& shape = detail::get_bulk_iteration_shape_variable( - HPX_FORWARD(ExPolicy, policy), it_or_r, count); + policy, it_or_r, count); return execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, @@ -65,8 +65,8 @@ namespace hpx::parallel::util::detail { } else if constexpr (!invokes_testing_function) { - auto&& shape = detail::get_bulk_iteration_shape( - HPX_FORWARD(ExPolicy, policy), it_or_r, count); + auto&& shape = + detail::get_bulk_iteration_shape(policy, it_or_r, count); return execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, @@ -76,7 +76,7 @@ namespace hpx::parallel::util::detail { { std::vector> inititems; auto&& shape = detail::get_bulk_iteration_shape( - HPX_FORWARD(ExPolicy, policy), inititems, f, it_or_r, count); + policy, inititems, f, it_or_r, count); auto&& workitems = execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, @@ -88,8 +88,8 @@ namespace hpx::parallel::util::detail { template - auto partition_with_index(ExPolicy&& policy, FwdIter first, - std::size_t count, Stride stride, F&& f) + auto partition_with_index( + ExPolicy policy, FwdIter first, std::size_t count, Stride stride, F&& f) { // estimate a chunk size based on number of cores used using parameters_type = @@ -106,7 +106,7 @@ namespace hpx::parallel::util::detail { "has_variable_chunk_size and invokes_testing_function"); auto&& shape = detail::get_bulk_iteration_shape_idx_variable( - HPX_FORWARD(ExPolicy, policy), first, count, stride); + policy, first, count, stride); return execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, @@ -115,7 +115,7 @@ namespace hpx::parallel::util::detail { else if constexpr (!invokes_testing_function) { auto&& shape = detail::get_bulk_iteration_shape_idx( - HPX_FORWARD(ExPolicy, policy), first, count, stride); + policy, first, count, stride); return execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, @@ -125,8 +125,7 @@ namespace hpx::parallel::util::detail { { std::vector> inititems; auto&& shape = detail::get_bulk_iteration_shape_idx( - HPX_FORWARD(ExPolicy, policy), inititems, f, first, count, - stride); + policy, inititems, f, first, count, stride); auto&& workitems = execution::bulk_async_execute(policy.executor(), partitioner_iteration{HPX_FORWARD(F, f)}, diff --git a/libs/core/algorithms/tests/regressions/CMakeLists.txt b/libs/core/algorithms/tests/regressions/CMakeLists.txt index e4a023dad590..9c132a490c22 100644 --- a/libs/core/algorithms/tests/regressions/CMakeLists.txt +++ b/libs/core/algorithms/tests/regressions/CMakeLists.txt @@ -12,6 +12,7 @@ set(tests for_loop_5735 for_loop_with_auto_chunk_size minimal_findend + num_cores reduce_3641 scan_different_inits scan_non_commutative diff --git a/libs/core/algorithms/tests/regressions/num_cores.cpp b/libs/core/algorithms/tests/regressions/num_cores.cpp new file mode 100644 index 000000000000..de0287bd02cb --- /dev/null +++ b/libs/core/algorithms/tests/regressions/num_cores.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2023 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +#include + +int hpx_main() +{ + hpx::execution::experimental::num_cores nc(2); + auto policy = hpx::execution::par.with(nc); + + HPX_TEST_EQ( + hpx::parallel::execution::processing_units_count(policy.parameters(), + policy.executor(), hpx::chrono::null_duration, 0), + static_cast(2)); + + auto policy2 = + hpx::parallel::execution::with_processing_units_count(policy, 2); + HPX_TEST_EQ(hpx::parallel::execution::processing_units_count( + hpx::execution::par.parameters(), policy2.executor(), + hpx::chrono::null_duration, 0), + static_cast(2)); + + return hpx::local::finalize(); +} + +int main(int argc, char* argv[]) +{ + HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} diff --git a/libs/core/algorithms/tests/unit/algorithms/rotate_sender.cpp b/libs/core/algorithms/tests/unit/algorithms/rotate_sender.cpp index 3c52d08828a2..44dda8249d61 100644 --- a/libs/core/algorithms/tests/unit/algorithms/rotate_sender.cpp +++ b/libs/core/algorithms/tests/unit/algorithms/rotate_sender.cpp @@ -46,7 +46,7 @@ void test_rotate_direct(Policy l, ExPolicy&& policy, IteratorTag) std::iota(std::begin(c), std::end(c), std::rand()); std::copy(std::begin(c), std::end(c), std::back_inserter(d1)); - std::size_t mid_pos = std::rand() % c.size(); //-V104 + std::size_t const mid_pos = std::rand() % c.size(); //-V104 base_iterator mid = std::begin(c); std::advance(mid, mid_pos); @@ -88,7 +88,7 @@ void test_rotate(Policy l, ExPolicy&& policy, IteratorTag) std::iota(std::begin(c), std::end(c), std::rand()); std::copy(std::begin(c), std::end(c), std::back_inserter(d1)); - std::size_t mid_pos = std::rand() % c.size(); //-V104 + std::size_t const mid_pos = std::rand() % c.size(); //-V104 base_iterator mid = std::begin(c); std::advance(mid, mid_pos); @@ -127,7 +127,7 @@ void test_rotate_async_direct(Policy l, ExPolicy&& p, IteratorTag) std::iota(std::begin(c), std::end(c), std::rand()); std::copy(std::begin(c), std::end(c), std::back_inserter(d1)); - std::size_t mid_pos = std::rand() % c.size(); //-V104 + std::size_t const mid_pos = std::rand() % c.size(); //-V104 base_iterator mid = std::begin(c); std::advance(mid, mid_pos); @@ -191,7 +191,7 @@ void rotate_test() int hpx_main(hpx::program_options::variables_map& vm) { - unsigned int seed = (unsigned int) std::time(nullptr); + unsigned int seed = static_cast(std::time(nullptr)); if (vm.count("seed")) seed = vm["seed"].as(); diff --git a/libs/core/algorithms/tests/unit/container_algorithms/is_sorted_until_range.cpp b/libs/core/algorithms/tests/unit/container_algorithms/is_sorted_until_range.cpp index bb40a007a334..f60e99669ff0 100644 --- a/libs/core/algorithms/tests/unit/container_algorithms/is_sorted_until_range.cpp +++ b/libs/core/algorithms/tests/unit/container_algorithms/is_sorted_until_range.cpp @@ -5,6 +5,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include #include @@ -1214,7 +1215,7 @@ void test_sorted_until_bad_alloc(ExPolicy policy, IteratorTag) decorated_iterator( std::end(c), []() { throw std::runtime_error("test"); })); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1232,7 +1233,7 @@ void test_sorted_until_bad_alloc(ExPolicy policy, IteratorTag) iterator(std::end(c)), [](int, int) -> bool { throw std::runtime_error("test"); }); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1250,7 +1251,7 @@ void test_sorted_until_bad_alloc(ExPolicy policy, IteratorTag) iterator(std::end(c)), std::less(), [](int) -> int { throw std::runtime_error("test"); }); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1285,7 +1286,7 @@ void test_sorted_until_async_bad_alloc(ExPolicy p, IteratorTag) HPX_TEST(false); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1306,7 +1307,7 @@ void test_sorted_until_async_bad_alloc(ExPolicy p, IteratorTag) HPX_TEST(false); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1327,7 +1328,7 @@ void test_sorted_until_async_bad_alloc(ExPolicy p, IteratorTag) HPX_TEST(false); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1361,7 +1362,7 @@ void test_sorted_until_seq_bad_alloc(IteratorTag) decorated_iterator( std::end(c), []() { throw std::runtime_error("test"); })); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1379,7 +1380,7 @@ void test_sorted_until_seq_bad_alloc(IteratorTag) iterator(std::end(c)), [](int, int) -> int { throw std::runtime_error("test"); }); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1397,7 +1398,7 @@ void test_sorted_until_seq_bad_alloc(IteratorTag) iterator(std::end(c)), std::less(), [](int) -> int { throw std::runtime_error("test"); }); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1426,7 +1427,7 @@ void test_sorted_until_bad_alloc(ExPolicy policy) hpx::ranges::is_sorted_until(policy, c, [](int, int) -> bool { throw std::runtime_error("test"); }); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1443,7 +1444,7 @@ void test_sorted_until_bad_alloc(ExPolicy policy) hpx::ranges::is_sorted_until(policy, c, std::less(), [](int) -> int { throw std::runtime_error("test"); }); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1470,7 +1471,7 @@ void test_sorted_until_async_bad_alloc(ExPolicy p) HPX_TEST(false); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1490,7 +1491,7 @@ void test_sorted_until_async_bad_alloc(ExPolicy p) HPX_TEST(false); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1515,7 +1516,7 @@ void test_sorted_until_seq_bad_alloc() hpx::ranges::is_sorted_until( c, [](int, int) -> int { throw std::runtime_error("test"); }); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1532,7 +1533,7 @@ void test_sorted_until_seq_bad_alloc() hpx::ranges::is_sorted_until(c, std::less(), [](int) -> int { throw std::runtime_error("test"); }); } - catch (hpx::exception_list const& e) + catch (hpx::exception_list const&) { caught_bad_alloc = true; } @@ -1585,12 +1586,12 @@ int hpx_main() sorted_until_exception_test(); sorted_until_bad_alloc_test(); - std::vector c(100); - hpx::future f = - hpx::dataflow(hpx::ranges::is_sorted, hpx::execution::par, c); - f = hpx::dataflow( - hpx::unwrapping(hpx::ranges::is_sorted), hpx::execution::par, c, f); - f.get(); + // std::vector c(100); + // hpx::future f = + // hpx::dataflow(hpx::ranges::is_sorted, hpx::execution::par, c); + // f = hpx::dataflow( + // hpx::unwrapping(hpx::ranges::is_sorted), hpx::execution::par, c, f); + // f.get(); return hpx::local::finalize(); } diff --git a/libs/core/execution/include/hpx/execution/executors/execution_parameters_fwd.hpp b/libs/core/execution/include/hpx/execution/executors/execution_parameters_fwd.hpp index ba4b834d6d89..856e389abf6e 100644 --- a/libs/core/execution/include/hpx/execution/executors/execution_parameters_fwd.hpp +++ b/libs/core/execution/include/hpx/execution/executors/execution_parameters_fwd.hpp @@ -64,6 +64,16 @@ namespace hpx::parallel::execution { /////////////////////////////////////////////////////////////////////////// // define customization points + inline constexpr struct null_parameters_t + { + } null_parameters{}; + + /// \cond NOINTERNAL + template <> + struct is_executor_parameters : std::true_type + { + }; + /// \endcond /// Return the number of invocations of the given function \a f which should /// be combined into a single task @@ -287,7 +297,7 @@ namespace hpx::parallel::execution { // clang-format off template ::value + hpx::traits::is_executor_any_v )> // clang-format on friend HPX_FORCEINLINE decltype(auto) tag_fallback_invoke( @@ -295,22 +305,23 @@ namespace hpx::parallel::execution { hpx::chrono::steady_duration const& iteration_duration, std::size_t num_tasks) { - return detail::processing_units_count_fn_helper>::call(HPX_FORWARD(Executor, exec), - iteration_duration, num_tasks); + return detail::processing_units_count_fn_helper>::call(null_parameters, + HPX_FORWARD(Executor, exec), iteration_duration, num_tasks); } // clang-format off template ::value + hpx::traits::is_executor_any_v )> // clang-format on friend HPX_FORCEINLINE decltype(auto) tag_fallback_invoke( processing_units_count_t tag, Executor&& exec, std::size_t num_tasks = 0) { - return tag(HPX_FORWARD(Executor, exec), hpx::chrono::null_duration, + return tag(hpx::parallel::execution::null_parameters, + HPX_FORWARD(Executor, exec), hpx::chrono::null_duration, num_tasks); } } processing_units_count{}; diff --git a/libs/core/execution/include/hpx/execution/executors/num_cores.hpp b/libs/core/execution/include/hpx/execution/executors/num_cores.hpp index eb3a0e128d73..ab02e9b4f2c9 100644 --- a/libs/core/execution/include/hpx/execution/executors/num_cores.hpp +++ b/libs/core/execution/include/hpx/execution/executors/num_cores.hpp @@ -35,6 +35,15 @@ namespace hpx::execution::experimental { /// \cond NOINTERNAL // discover the number of cores to use for parallelization + template + friend std::size_t tag_invoke( + hpx::parallel::execution::processing_units_count_t, + num_cores params, Executor&&, hpx::chrono::steady_duration const&, + std::size_t) noexcept + { + return params.num_cores_; + } + template constexpr std::size_t processing_units_count(Executor&&, hpx::chrono::steady_duration const&, std::size_t) const noexcept diff --git a/libs/core/execution/tests/regressions/is_executor_1691.cpp b/libs/core/execution/tests/regressions/is_executor_1691.cpp index 3184f83b7721..33e4902cd9e3 100644 --- a/libs/core/execution/tests/regressions/is_executor_1691.cpp +++ b/libs/core/execution/tests/regressions/is_executor_1691.cpp @@ -17,6 +17,7 @@ struct my_executor : hpx::execution::parallel_executor }; namespace hpx::parallel::execution { + template <> struct is_one_way_executor : std::true_type { diff --git a/libs/core/execution/tests/unit/executor_parameters_dispatching.cpp b/libs/core/execution/tests/unit/executor_parameters_dispatching.cpp index 0947189d345f..83296b9bb67a 100644 --- a/libs/core/execution/tests/unit/executor_parameters_dispatching.cpp +++ b/libs/core/execution/tests/unit/executor_parameters_dispatching.cpp @@ -27,10 +27,7 @@ std::atomic exec_count(0); struct test_executor_get_chunk_size : hpx::execution::parallel_executor { - test_executor_get_chunk_size() - : hpx::execution::parallel_executor() - { - } + test_executor_get_chunk_size() = default; template static std::size_t get_chunk_size(Parameters&& /* params */, @@ -42,12 +39,11 @@ struct test_executor_get_chunk_size : hpx::execution::parallel_executor } }; -namespace hpx::parallel::execution { - template <> - struct is_two_way_executor : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_two_way_executor< + test_executor_get_chunk_size> : std::true_type +{ +}; struct test_chunk_size { @@ -61,14 +57,11 @@ struct test_chunk_size } }; -namespace hpx::parallel::execution { - /// \cond NOINTERNAL - template <> - struct is_executor_parameters : std::true_type - { - }; - /// \endcond -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_executor_parameters + : std::true_type +{ +}; /////////////////////////////////////////////////////////////////////////////// void test_get_chunk_size() @@ -80,8 +73,8 @@ void test_get_chunk_size() hpx::parallel::execution::get_chunk_size( test_chunk_size{}, hpx::execution::par.executor(), 1, 1); - HPX_TEST_EQ(params_count, std::size_t(1)); - HPX_TEST_EQ(exec_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -91,8 +84,8 @@ void test_get_chunk_size() hpx::parallel::execution::get_chunk_size(test_chunk_size{}, hpx::execution::par.executor(), hpx::chrono::null_duration, 1, 1); - HPX_TEST_EQ(params_count, std::size_t(1)); - HPX_TEST_EQ(exec_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -102,8 +95,8 @@ void test_get_chunk_size() hpx::parallel::execution::get_chunk_size( test_chunk_size{}, test_executor_get_chunk_size{}, 1, 1); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(0)); + HPX_TEST_EQ(exec_count, static_cast(1)); } { @@ -113,8 +106,8 @@ void test_get_chunk_size() hpx::parallel::execution::get_chunk_size(test_chunk_size{}, test_executor_get_chunk_size{}, hpx::chrono::null_duration, 1, 1); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(0)); + HPX_TEST_EQ(exec_count, static_cast(1)); } } @@ -123,10 +116,7 @@ void test_get_chunk_size() struct test_executor_measure_iteration : hpx::execution::parallel_executor { - test_executor_measure_iteration() - : hpx::execution::parallel_executor() - { - } + test_executor_measure_iteration() = default; template static auto measure_iteration(Parameters&&, F&&, std::size_t) @@ -136,12 +126,11 @@ struct test_executor_measure_iteration : hpx::execution::parallel_executor } }; -namespace hpx::parallel::execution { - template <> - struct is_two_way_executor : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_two_way_executor< + test_executor_measure_iteration> : std::true_type +{ +}; struct test_measure_iteration { @@ -153,14 +142,11 @@ struct test_measure_iteration } }; -namespace hpx::parallel::execution { - /// \cond NOINTERNAL - template <> - struct is_executor_parameters : std::true_type - { - }; - /// \endcond -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_executor_parameters + : std::true_type +{ +}; /////////////////////////////////////////////////////////////////////////////// void test_get_measure_iteration() @@ -173,8 +159,8 @@ void test_get_measure_iteration() test_measure_iteration{}, hpx::execution::par.executor(), [](std::size_t) { return 0; }, 1); - HPX_TEST_EQ(params_count, std::size_t(1)); - HPX_TEST_EQ(exec_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -185,8 +171,8 @@ void test_get_measure_iteration() test_measure_iteration{}, test_executor_measure_iteration{}, [](std::size_t) { return 0; }, 1); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(0)); + HPX_TEST_EQ(exec_count, static_cast(1)); } } @@ -196,10 +182,7 @@ void test_get_measure_iteration() struct test_executor_maximal_number_of_chunks : hpx::execution::parallel_executor { - test_executor_maximal_number_of_chunks() - : hpx::execution::parallel_executor() - { - } + test_executor_maximal_number_of_chunks() = default; template static std::size_t maximal_number_of_chunks( @@ -210,18 +193,16 @@ struct test_executor_maximal_number_of_chunks } }; -namespace hpx::parallel::execution { - template <> - struct is_two_way_executor - : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_two_way_executor< + test_executor_maximal_number_of_chunks> : std::true_type +{ +}; struct test_number_of_chunks { template - std::size_t maximal_number_of_chunks( + static std::size_t maximal_number_of_chunks( Executor&&, std::size_t, std::size_t num_tasks) { ++params_count; @@ -229,12 +210,11 @@ struct test_number_of_chunks } }; -namespace hpx::parallel::execution { - template <> - struct is_executor_parameters : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_executor_parameters + : std::true_type +{ +}; /////////////////////////////////////////////////////////////////////////////// void test_maximal_number_of_chunks() @@ -246,8 +226,8 @@ void test_maximal_number_of_chunks() hpx::parallel::execution::maximal_number_of_chunks( test_number_of_chunks{}, hpx::execution::par.executor(), 1, 1); - HPX_TEST_EQ(params_count, std::size_t(1)); - HPX_TEST_EQ(exec_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -258,8 +238,8 @@ void test_maximal_number_of_chunks() test_number_of_chunks{}, test_executor_maximal_number_of_chunks{}, 1, 1); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(0)); + HPX_TEST_EQ(exec_count, static_cast(1)); } } @@ -269,10 +249,7 @@ void test_maximal_number_of_chunks() struct test_executor_reset_thread_distribution : hpx::execution::parallel_executor { - test_executor_reset_thread_distribution() - : hpx::execution::parallel_executor() - { - } + test_executor_reset_thread_distribution() = default; template static void reset_thread_distribution(Parameters&&) @@ -281,29 +258,26 @@ struct test_executor_reset_thread_distribution } }; -namespace hpx::parallel::execution { - template <> - struct is_two_way_executor - : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_two_way_executor< + test_executor_reset_thread_distribution> : std::true_type +{ +}; struct test_thread_distribution { template - void reset_thread_distribution(Executor&&) + static void reset_thread_distribution(Executor&&) { ++params_count; } }; -namespace hpx::parallel::execution { - template <> - struct is_executor_parameters : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_executor_parameters< + test_thread_distribution> : std::true_type +{ +}; /////////////////////////////////////////////////////////////////////////////// void test_reset_thread_distribution() @@ -315,8 +289,8 @@ void test_reset_thread_distribution() hpx::parallel::execution::reset_thread_distribution( test_thread_distribution{}, hpx::execution::par.executor()); - HPX_TEST_EQ(params_count, std::size_t(1)); - HPX_TEST_EQ(exec_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -327,8 +301,8 @@ void test_reset_thread_distribution() test_thread_distribution{}, test_executor_reset_thread_distribution{}); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(0)); + HPX_TEST_EQ(exec_count, static_cast(1)); } } @@ -337,10 +311,7 @@ void test_reset_thread_distribution() struct test_executor_processing_units_count : hpx::execution::parallel_executor { - test_executor_processing_units_count() - : hpx::execution::parallel_executor() - { - } + test_executor_processing_units_count() = default; template static std::size_t processing_units_count( @@ -351,31 +322,30 @@ struct test_executor_processing_units_count : hpx::execution::parallel_executor } }; -namespace hpx::parallel::execution { - template <> - struct is_two_way_executor - : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_two_way_executor< + test_executor_processing_units_count> : std::true_type +{ +}; struct test_processing_units { template - static std::size_t processing_units_count( - Executor&&, hpx::chrono::steady_duration const&, std::size_t) + friend std::size_t tag_invoke( + hpx::parallel::execution::processing_units_count_t, + test_processing_units, Executor&&, hpx::chrono::steady_duration const&, + std::size_t) { ++params_count; return 1; } }; -namespace hpx::parallel::execution { - template <> - struct is_executor_parameters : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_executor_parameters + : std::true_type +{ +}; /////////////////////////////////////////////////////////////////////////////// void test_processing_units_count() @@ -386,7 +356,7 @@ void test_processing_units_count() hpx::parallel::execution::processing_units_count( test_processing_units{}, hpx::execution::parallel_executor()); - HPX_TEST_EQ(params_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(0)); } { @@ -397,8 +367,8 @@ void test_processing_units_count() test_processing_units{}, test_executor_processing_units_count{}, hpx::chrono::null_duration, 0); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -407,38 +377,35 @@ void test_processing_units_count() auto p = hpx::parallel::execution::with_processing_units_count( hpx::execution::par, 2); - std::size_t num_cores = + std::size_t const num_cores = hpx::parallel::execution::processing_units_count( test_processing_units{}, p.executor()); - HPX_TEST_EQ(num_cores, std::size_t(2)); - HPX_TEST_EQ(params_count, std::size_t(0)); + HPX_TEST_EQ(num_cores, static_cast(2)); + HPX_TEST_EQ(params_count, static_cast(0)); } { - params_count = 0; - hpx::execution::experimental::num_cores nc(2); auto p = hpx::parallel::execution::with_processing_units_count( hpx::execution::par, nc); - std::size_t num_cores = + std::size_t const num_cores = hpx::parallel::execution::processing_units_count( - test_processing_units{}, p.executor(), + hpx::parallel::execution::null_parameters, p.executor(), hpx::chrono::null_duration, 0); - HPX_TEST_EQ(num_cores, std::size_t(2)); - HPX_TEST_EQ(params_count, std::size_t(0)); + HPX_TEST_EQ(num_cores, static_cast(2)); } { auto p = hpx::parallel::execution::with_processing_units_count( hpx::execution::par, 2); - std::size_t num_cores = + std::size_t const num_cores = hpx::parallel::execution::processing_units_count(p); - HPX_TEST_EQ(num_cores, std::size_t(2)); + HPX_TEST_EQ(num_cores, static_cast(2)); } } @@ -447,64 +414,59 @@ void test_processing_units_count() struct test_executor_begin_end : hpx::execution::parallel_executor { - test_executor_begin_end() - : hpx::execution::parallel_executor() - { - } + test_executor_begin_end() = default; template - void mark_begin_execution(Parameters&&) + static void mark_begin_execution(Parameters&&) { ++exec_count; } template - void mark_end_of_scheduling(Parameters&&) + static void mark_end_of_scheduling(Parameters&&) { ++exec_count; } template - void mark_end_execution(Parameters&&) + static void mark_end_execution(Parameters&&) { ++exec_count; } }; -namespace hpx::parallel::execution { - template <> - struct is_two_way_executor : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_two_way_executor + : std::true_type +{ +}; struct test_begin_end { template - void mark_begin_execution(Executor&&) + static void mark_begin_execution(Executor&&) { ++params_count; } template - void mark_end_of_scheduling(Executor&&) + static void mark_end_of_scheduling(Executor&&) { ++params_count; } template - void mark_end_execution(Executor&&) + static void mark_end_execution(Executor&&) { ++params_count; } }; -namespace hpx::parallel::execution { - template <> - struct is_executor_parameters : std::true_type - { - }; -} // namespace hpx::parallel::execution +template <> +struct hpx::parallel::execution::is_executor_parameters + : std::true_type +{ +}; /////////////////////////////////////////////////////////////////////////////// void test_mark_begin_execution() @@ -516,8 +478,8 @@ void test_mark_begin_execution() hpx::parallel::execution::mark_begin_execution( test_begin_end{}, hpx::execution::par.executor()); - HPX_TEST_EQ(params_count, std::size_t(1)); - HPX_TEST_EQ(exec_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -527,8 +489,8 @@ void test_mark_begin_execution() hpx::parallel::execution::mark_begin_execution( test_begin_end{}, test_executor_begin_end{}); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(0)); + HPX_TEST_EQ(exec_count, static_cast(1)); } } @@ -541,8 +503,8 @@ void test_mark_end_of_scheduling() hpx::parallel::execution::mark_end_of_scheduling( test_begin_end{}, hpx::execution::par.executor()); - HPX_TEST_EQ(params_count, std::size_t(1)); - HPX_TEST_EQ(exec_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -552,8 +514,8 @@ void test_mark_end_of_scheduling() hpx::parallel::execution::mark_end_of_scheduling( test_begin_end{}, test_executor_begin_end{}); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(0)); + HPX_TEST_EQ(exec_count, static_cast(1)); } } @@ -566,8 +528,8 @@ void test_mark_end_execution() hpx::parallel::execution::mark_end_execution( test_begin_end{}, hpx::execution::par.executor()); - HPX_TEST_EQ(params_count, std::size_t(1)); - HPX_TEST_EQ(exec_count, std::size_t(0)); + HPX_TEST_EQ(params_count, static_cast(1)); + HPX_TEST_EQ(exec_count, static_cast(0)); } { @@ -577,8 +539,8 @@ void test_mark_end_execution() hpx::parallel::execution::mark_end_execution( test_begin_end{}, test_executor_begin_end{}); - HPX_TEST_EQ(params_count, std::size_t(0)); - HPX_TEST_EQ(exec_count, std::size_t(1)); + HPX_TEST_EQ(params_count, static_cast(0)); + HPX_TEST_EQ(exec_count, static_cast(1)); } } diff --git a/libs/core/executors/examples/disable_thread_stealing_executor.cpp b/libs/core/executors/examples/disable_thread_stealing_executor.cpp index 4a3e952a40df..721b1064ec64 100644 --- a/libs/core/executors/examples/disable_thread_stealing_executor.cpp +++ b/libs/core/executors/examples/disable_thread_stealing_executor.cpp @@ -66,6 +66,38 @@ namespace executor_example { } }; + // support all properties exposed by the wrapped executor + // clang-format off + template + )> + auto tag_invoke(Tag tag, + disable_thread_stealing_executor const& exec, + Property&& prop) + -> decltype(disable_thread_stealing_executor( + std::declval()( + std::declval(), std::declval()))) + // clang-format on + { + return disable_thread_stealing_executor( + tag(static_cast(exec), + HPX_FORWARD(Property, prop))); + } + + // clang-format off + template + )> + // clang-format on + auto tag_invoke( + Tag tag, disable_thread_stealing_executor const& exec) + -> decltype(std::declval()(std::declval())) + { + return tag(static_cast(exec)); + } + template auto make_disable_thread_stealing_executor(BaseExecutor&& exec) { diff --git a/libs/core/executors/examples/executor_with_thread_hooks.cpp b/libs/core/executors/examples/executor_with_thread_hooks.cpp index 19a5db048b82..5dc5bd7b113e 100644 --- a/libs/core/executors/examples/executor_with_thread_hooks.cpp +++ b/libs/core/executors/examples/executor_with_thread_hooks.cpp @@ -168,6 +168,12 @@ namespace executor_example { std::forward(predecessor), std::forward(ts)...); } + [[nodiscard]] constexpr std::decay_t const& get_executor() + const noexcept + { + return exec_; + } + private: using thread_hook = hpx::function; diff --git a/libs/core/executors/include/hpx/executors/annotating_executor.hpp b/libs/core/executors/include/hpx/executors/annotating_executor.hpp index 2f34179b140b..6f9a750fa6d2 100644 --- a/libs/core/executors/include/hpx/executors/annotating_executor.hpp +++ b/libs/core/executors/include/hpx/executors/annotating_executor.hpp @@ -203,7 +203,7 @@ namespace hpx::execution::experimental { } std::decay_t exec_; - char const* const annotation_ = nullptr; + char const* annotation_ = nullptr; /// \endcond }; @@ -212,7 +212,7 @@ namespace hpx::execution::experimental { template - )> + )> // clang-format on auto tag_invoke( Tag tag, annotating_executor const& exec, Property&& prop) @@ -227,7 +227,7 @@ namespace hpx::execution::experimental { template - )> + )> // clang-format on auto tag_invoke(Tag tag, annotating_executor const& exec) -> decltype(std::declval()(std::declval())) @@ -259,7 +259,7 @@ namespace hpx::execution::experimental { template - )> + )> // clang-format on constexpr auto tag_fallback_invoke( with_annotation_t, Executor&& exec, char const* annotation) @@ -272,7 +272,7 @@ namespace hpx::execution::experimental { template - )> + )> // clang-format on auto tag_fallback_invoke( with_annotation_t, Executor&& exec, std::string annotation) diff --git a/libs/core/executors/include/hpx/executors/datapar/execution_policy.hpp b/libs/core/executors/include/hpx/executors/datapar/execution_policy.hpp index dd46113d68ed..6ade940bab80 100644 --- a/libs/core/executors/include/hpx/executors/datapar/execution_policy.hpp +++ b/libs/core/executors/include/hpx/executors/datapar/execution_policy.hpp @@ -58,6 +58,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + simd_task_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr simd_task_policy_shim( + simd_task_policy_shim const& rhs) + : base_type( + simd_task_policy_shim(rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + simd_task_policy_shim& operator=( + simd_task_policy_shim const& rhs) + { + base_type::operator=( + simd_task_policy_shim(rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -70,7 +96,8 @@ namespace hpx::execution { /// /// The algorithm returns a future representing the result of the /// corresponding algorithm when invoked with the sequenced_policy. - using simd_task_policy = detail::simd_task_policy_shim; + using simd_task_policy = detail::simd_task_policy_shim>; namespace detail { @@ -96,6 +123,30 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + simd_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr simd_policy_shim( + simd_policy_shim const& rhs) + : base_type(simd_policy_shim(rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + simd_policy_shim& operator=( + simd_policy_shim const& rhs) + { + base_type::operator=( + simd_policy_shim(rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -104,7 +155,8 @@ namespace hpx::execution { /// The class simd_policy is an execution policy type used as a unique type /// to disambiguate parallel algorithm overloading and require that a /// parallel algorithm's execution may not be parallelized. - using simd_policy = detail::simd_policy_shim; + using simd_policy = detail::simd_policy_shim>; /// Default sequential execution policy object. inline constexpr simd_policy simd{}; @@ -135,6 +187,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + par_simd_task_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr par_simd_task_policy_shim( + par_simd_task_policy_shim const& rhs) + : base_type( + par_simd_task_policy_shim(rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + par_simd_task_policy_shim& operator=( + par_simd_task_policy_shim const& rhs) + { + base_type::operator=(par_simd_task_policy_shim( + rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -147,7 +225,8 @@ namespace hpx::execution { /// The algorithm returns a future representing the result of the /// corresponding algorithm when invoked with the parallel_policy. using par_simd_task_policy = - detail::par_simd_task_policy_shim; + detail::par_simd_task_policy_shim>; namespace detail { @@ -174,6 +253,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + par_simd_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr par_simd_policy_shim( + par_simd_policy_shim const& rhs) + : base_type( + par_simd_policy_shim(rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + par_simd_policy_shim& operator=( + par_simd_policy_shim const& rhs) + { + base_type::operator=( + par_simd_policy_shim(rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -185,7 +290,8 @@ namespace hpx::execution { /// /// The algorithm returns a future representing the result of the /// corresponding algorithm when invoked with the parallel_policy. - using par_simd_policy = detail::par_simd_policy_shim; + using par_simd_policy = detail::par_simd_policy_shim>; /// Default data-parallel execution policy object. inline constexpr par_simd_policy par_simd{}; diff --git a/libs/core/executors/include/hpx/executors/datapar/execution_policy_fwd.hpp b/libs/core/executors/include/hpx/executors/datapar/execution_policy_fwd.hpp index e34c4c8a9289..e54f6731e76e 100644 --- a/libs/core/executors/include/hpx/executors/datapar/execution_policy_fwd.hpp +++ b/libs/core/executors/include/hpx/executors/datapar/execution_policy_fwd.hpp @@ -15,16 +15,16 @@ namespace hpx::execution::detail { /////////////////////////////////////////////////////////////////////////// - template + template struct simd_policy_shim; - template + template struct simd_task_policy_shim; - template + template struct par_simd_policy_shim; - template + template struct par_simd_task_policy_shim; } // namespace hpx::execution::detail diff --git a/libs/core/executors/include/hpx/executors/execution_policy.hpp b/libs/core/executors/include/hpx/executors/execution_policy.hpp index 1336d99d6241..e6ce801008fb 100644 --- a/libs/core/executors/include/hpx/executors/execution_policy.hpp +++ b/libs/core/executors/include/hpx/executors/execution_policy.hpp @@ -124,10 +124,7 @@ namespace hpx::execution { // The type of the associated executor parameters object which is // associated with this execution policy - using executor_parameters_type = - std::conditional_t, - hpx::traits::executor_parameters_type_t, - decayed_parameters_type>; + using executor_parameters_type = decayed_parameters_type; // The category of the execution agents created by this execution // policy. @@ -284,6 +281,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + sequenced_task_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr sequenced_task_policy_shim( + sequenced_task_policy_shim const& rhs) + : base_type(sequenced_task_policy_shim( + rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + sequenced_task_policy_shim& operator=( + sequenced_task_policy_shim const& rhs) + { + base_type::operator=(sequenced_task_policy_shim( + rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -297,7 +320,8 @@ namespace hpx::execution { /// The algorithm returns a future representing the result of the /// corresponding algorithm when invoked with the sequenced_policy. using sequenced_task_policy = - detail::sequenced_task_policy_shim; + detail::sequenced_task_policy_shim>; namespace detail { @@ -324,6 +348,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + sequenced_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr sequenced_policy_shim( + sequenced_policy_shim const& rhs) + : base_type( + sequenced_policy_shim(rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + sequenced_policy_shim& operator=( + sequenced_policy_shim const& rhs) + { + base_type::operator=( + sequenced_policy_shim(rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -332,7 +382,8 @@ namespace hpx::execution { /// The class sequenced_policy is an execution policy type used as a unique /// type to disambiguate parallel algorithm overloading and require that a /// parallel algorithm's execution may not be parallelized. - using sequenced_policy = detail::sequenced_policy_shim; + using sequenced_policy = detail::sequenced_policy_shim>; /// Default sequential execution policy object. inline constexpr sequenced_policy seq{}; @@ -364,6 +415,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + parallel_task_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr parallel_task_policy_shim( + parallel_task_policy_shim const& rhs) + : base_type( + parallel_task_policy_shim(rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + parallel_task_policy_shim& operator=( + parallel_task_policy_shim const& rhs) + { + base_type::operator=(parallel_task_policy_shim( + rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -376,7 +453,8 @@ namespace hpx::execution { /// The algorithm returns a future representing the result of the /// corresponding algorithm when invoked with the parallel_policy. using parallel_task_policy = - detail::parallel_task_policy_shim; + detail::parallel_task_policy_shim>; namespace detail { @@ -402,6 +480,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + parallel_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr parallel_policy_shim( + parallel_policy_shim const& rhs) + : base_type( + parallel_policy_shim(rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + parallel_policy_shim& operator=( + parallel_policy_shim const& rhs) + { + base_type::operator=( + parallel_policy_shim(rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -410,7 +514,8 @@ namespace hpx::execution { /// The class parallel_policy is an execution policy type used as a unique /// type to disambiguate parallel algorithm overloading and indicate that a /// parallel algorithm's execution may be parallelized. - using parallel_policy = detail::parallel_policy_shim; + using parallel_policy = detail::parallel_policy_shim>; /// Default parallel execution policy object. inline constexpr parallel_policy par{}; @@ -443,6 +548,34 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + parallel_unsequenced_task_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr parallel_unsequenced_task_policy_shim( + parallel_unsequenced_task_policy_shim const& rhs) + : base_type(parallel_unsequenced_task_policy_shim( + rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + parallel_unsequenced_task_policy_shim& operator=( + parallel_unsequenced_task_policy_shim const& rhs) + { + base_type::operator=(parallel_unsequenced_task_policy_shim( + rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -453,7 +586,8 @@ namespace hpx::execution { /// and indicate that a parallel algorithm's execution may be parallelized /// and vectorized. using parallel_unsequenced_task_policy = - detail::parallel_unsequenced_task_policy_shim; + detail::parallel_unsequenced_task_policy_shim>; namespace detail { @@ -480,6 +614,34 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + parallel_unsequenced_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr parallel_unsequenced_policy_shim( + parallel_unsequenced_policy_shim const& + rhs) + : base_type(parallel_unsequenced_policy_shim( + rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + parallel_unsequenced_policy_shim& operator=( + parallel_unsequenced_policy_shim const& + rhs) + { + base_type::operator=( + parallel_policy_shim(rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -490,7 +652,8 @@ namespace hpx::execution { /// indicate that a parallel algorithm's execution may be parallelized and /// vectorized. using parallel_unsequenced_policy = - detail::parallel_unsequenced_policy_shim; + detail::parallel_unsequenced_policy_shim>; /// Default vector execution policy object. inline constexpr parallel_unsequenced_policy par_unseq{}; @@ -524,6 +687,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + unsequenced_task_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr unsequenced_task_policy_shim( + unsequenced_task_policy_shim const& rhs) + : base_type(unsequenced_task_policy_shim( + rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + unsequenced_task_policy_shim& operator=( + unsequenced_task_policy_shim const& rhs) + { + base_type::operator=(unsequenced_task_policy_shim( + rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -533,7 +722,8 @@ namespace hpx::execution { /// unique type to disambiguate parallel algorithm overloading and indicate /// that a parallel algorithm's execution may be vectorized. using unsequenced_task_policy = - detail::unsequenced_task_policy_shim; + detail::unsequenced_task_policy_shim>; namespace detail { @@ -559,6 +749,32 @@ namespace hpx::execution { HPX_FORWARD(Parameters_, params)) { } + + template , + unsequenced_policy_shim> && + std::is_convertible_v && + std::is_convertible_v>> + explicit constexpr unsequenced_policy_shim( + unsequenced_policy_shim const& rhs) + : base_type( + unsequenced_policy_shim(rhs.executor(), rhs.parameters())) + { + } + + template && + std::is_convertible_v>> + unsequenced_policy_shim& operator=( + unsequenced_policy_shim const& rhs) + { + base_type::operator=( + unsequenced_policy_shim(rhs.executor(), rhs.parameters())); + return *this; + } /// \endcond }; } // namespace detail @@ -568,7 +784,8 @@ namespace hpx::execution { /// unique type to disambiguate parallel algorithm overloading and indicate /// that a parallel algorithm's execution may be vectorized. using unsequenced_policy = - detail::unsequenced_policy_shim; + detail::unsequenced_policy_shim>; /// Default vector execution policy object. inline constexpr unsequenced_policy unseq{}; diff --git a/libs/core/executors/include/hpx/executors/execution_policy_fwd.hpp b/libs/core/executors/include/hpx/executors/execution_policy_fwd.hpp index 557b0f6f5350..a07f8707c3ee 100644 --- a/libs/core/executors/include/hpx/executors/execution_policy_fwd.hpp +++ b/libs/core/executors/include/hpx/executors/execution_policy_fwd.hpp @@ -11,27 +11,27 @@ namespace hpx::execution::detail { // forward declarations, see execution_policy.hpp - template + template struct sequenced_policy_shim; - template + template struct sequenced_task_policy_shim; - template + template struct parallel_policy_shim; - template + template struct parallel_task_policy_shim; - template + template struct unsequenced_task_policy_shim; - template + template struct unsequenced_policy_shim; - template + template struct parallel_unsequenced_task_policy_shim; - template + template struct parallel_unsequenced_policy_shim; } // namespace hpx::execution::detail diff --git a/libs/core/executors/include/hpx/executors/execution_policy_mappings.hpp b/libs/core/executors/include/hpx/executors/execution_policy_mappings.hpp index 83149ed60f32..2994f699d701 100644 --- a/libs/core/executors/include/hpx/executors/execution_policy_mappings.hpp +++ b/libs/core/executors/include/hpx/executors/execution_policy_mappings.hpp @@ -135,7 +135,7 @@ namespace hpx::execution::experimental { }; /////////////////////////////////////////////////////////////////////////// - // Return the matching non-unsequences execution policy + // Return the matching non-unsequenced execution policy inline constexpr struct to_non_unseq_t final : hpx::functional::detail::tag_fallback { diff --git a/libs/core/executors/include/hpx/executors/explicit_scheduler_executor.hpp b/libs/core/executors/include/hpx/executors/explicit_scheduler_executor.hpp index 233bd98849a3..e6c64a0da9c2 100644 --- a/libs/core/executors/include/hpx/executors/explicit_scheduler_executor.hpp +++ b/libs/core/executors/include/hpx/executors/explicit_scheduler_executor.hpp @@ -98,17 +98,23 @@ namespace hpx::execution::experimental { return sched_; } + // clang-format off + template + )> + // clang-format on friend auto tag_invoke( hpx::parallel::execution::processing_units_count_t tag, - explicit_scheduler_executor const& exec, + Parameters&& params, explicit_scheduler_executor const& exec, hpx::chrono::steady_duration const& = hpx::chrono::null_duration, std::size_t = 0) -> decltype(std::declval< hpx::parallel::execution::processing_units_count_t>()( - std::declval(), + std::declval(), std::declval(), std::declval(), 0)) { - return tag(exec.sched_); + return tag(HPX_FORWARD(Parameters, params), exec.sched_); } // Associate the parallel_execution_tag executor tag type as a default @@ -250,16 +256,16 @@ namespace hpx::execution::experimental { HPX_CONCEPT_REQUIRES_( hpx::execution::experimental::is_scheduling_property_v )> - // clang-format on auto tag_invoke(Tag tag, explicit_scheduler_executor const& exec, Property&& prop) - -> decltype( - explicit_scheduler_executor(std::declval()( + -> decltype(explicit_scheduler_executor( + std::declval()( std::declval(), std::declval()))) { return explicit_scheduler_executor( tag(exec.sched(), HPX_FORWARD(Property, prop))); } + // clang-format on // clang-format off template ::call()) + constexpr explicit parallel_policy_executor(Policy l) : pool_(nullptr) , policy_(l) { } + constexpr parallel_policy_executor() + : pool_(nullptr) + , policy_( + parallel::execution::detail::get_default_policy::call()) + { + } + constexpr explicit parallel_policy_executor( threads::thread_pool_base* pool, Policy l, std::size_t hierarchical_threshold = @@ -175,18 +180,29 @@ namespace hpx::execution { // property implementations #if defined(HPX_HAVE_THREAD_DESCRIPTION) - friend constexpr parallel_policy_executor tag_invoke( + // clang-format off + template + )> + // clang-format on + friend constexpr auto tag_invoke( hpx::execution::experimental::with_annotation_t, - parallel_policy_executor const& exec, char const* annotation) + Executor_ const& exec, char const* annotation) { auto exec_with_annotation = exec; exec_with_annotation.annotation_ = annotation; return exec_with_annotation; } - friend parallel_policy_executor tag_invoke( - hpx::execution::experimental::with_annotation_t, - parallel_policy_executor const& exec, std::string annotation) + // clang-format off + template + )> + // clang-format on + friend auto tag_invoke(hpx::execution::experimental::with_annotation_t, + Executor_ const& exec, std::string annotation) { auto exec_with_annotation = exec; exec_with_annotation.annotation_ = @@ -202,18 +218,29 @@ namespace hpx::execution { } #endif - friend constexpr parallel_policy_executor tag_invoke( + // clang-format off + template + )> + // clang-format on + friend constexpr auto tag_invoke( hpx::parallel::execution::with_processing_units_count_t, - parallel_policy_executor const& exec, - std::size_t num_cores) noexcept + Executor_ const& exec, std::size_t num_cores) noexcept { auto exec_with_num_cores = exec; exec_with_num_cores.num_cores_ = num_cores; return exec_with_num_cores; } + // clang-format off + template + )> + // clang-format on friend constexpr std::size_t tag_invoke( - hpx::parallel::execution::processing_units_count_t, + hpx::parallel::execution::processing_units_count_t, Parameters&&, parallel_policy_executor const& exec, hpx::chrono::steady_duration const& = hpx::chrono::null_duration, std::size_t = 0) @@ -221,10 +248,15 @@ namespace hpx::execution { return exec.get_num_cores(); } - friend constexpr parallel_policy_executor tag_invoke( + // clang-format off + template + )> + // clang-format on + friend constexpr auto tag_invoke( hpx::execution::experimental::with_first_core_t, - parallel_policy_executor const& exec, - std::size_t first_core) noexcept + Executor_ const& exec, std::size_t first_core) noexcept { auto exec_with_first_core = exec; exec_with_first_core.first_core_ = first_core; diff --git a/libs/core/executors/include/hpx/executors/restricted_thread_pool_executor.hpp b/libs/core/executors/include/hpx/executors/restricted_thread_pool_executor.hpp index 6404f60243df..e4929a69f55c 100644 --- a/libs/core/executors/include/hpx/executors/restricted_thread_pool_executor.hpp +++ b/libs/core/executors/include/hpx/executors/restricted_thread_pool_executor.hpp @@ -148,18 +148,23 @@ namespace hpx::parallel::execution { friend decltype(auto) tag_invoke( Tag tag, restricted_policy_executor const& exec) { - return hpx::functional::tag_invoke( - tag, exec.generate_executor(exec.get_current_thread_num())); + return tag(exec.generate_executor(exec.get_current_thread_num())); } + // clang-format off + template + )> + // clang-format on friend constexpr std::size_t tag_invoke( hpx::parallel::execution::processing_units_count_t tag, - restricted_policy_executor const& exec, + Parameters&& params, restricted_policy_executor const& exec, hpx::chrono::steady_duration const& duration = hpx::chrono::null_duration, std::size_t num_tasks = 0) { - return hpx::functional::tag_invoke(tag, + return tag(HPX_FORWARD(Parameters, params), exec.generate_executor(exec.get_current_thread_num()), duration, num_tasks); } @@ -242,7 +247,7 @@ namespace hpx::parallel::execution { /// \endcond private: - std::uint16_t const first_thread_; + std::uint16_t first_thread_; mutable std::atomic os_thread_; embedded_executor exec_; diff --git a/libs/core/executors/include/hpx/executors/scheduler_executor.hpp b/libs/core/executors/include/hpx/executors/scheduler_executor.hpp index 439d1d569447..a152d6202c1f 100644 --- a/libs/core/executors/include/hpx/executors/scheduler_executor.hpp +++ b/libs/core/executors/include/hpx/executors/scheduler_executor.hpp @@ -130,17 +130,25 @@ namespace hpx::execution::experimental { using future_type = hpx::future; private: + // clang-format off + template + )> + // clang-format on friend auto tag_invoke( hpx::parallel::execution::processing_units_count_t tag, - scheduler_executor const& exec, - hpx::chrono::steady_duration const& = hpx::chrono::null_duration, - std::size_t = 0) + Parameters&& params, scheduler_executor const& exec, + hpx::chrono::steady_duration const& duration = + hpx::chrono::null_duration, + std::size_t num_cores = 0) -> decltype(std::declval< hpx::parallel::execution::processing_units_count_t>()( - std::declval(), + std::declval(), std::declval(), std::declval(), 0)) { - return tag(exec.sched_); + return tag(HPX_FORWARD(Parameters, params), exec.sched_, duration, + num_cores); } // NonBlockingOneWayExecutor interface diff --git a/libs/core/executors/include/hpx/executors/sequenced_executor.hpp b/libs/core/executors/include/hpx/executors/sequenced_executor.hpp index 24b774308386..53162b7966ba 100644 --- a/libs/core/executors/include/hpx/executors/sequenced_executor.hpp +++ b/libs/core/executors/include/hpx/executors/sequenced_executor.hpp @@ -185,18 +185,29 @@ namespace hpx::execution { } #if defined(HPX_HAVE_THREAD_DESCRIPTION) - friend constexpr sequenced_executor tag_invoke( + // clang-format off + template + )> + // clang-format on + friend constexpr auto tag_invoke( hpx::execution::experimental::with_annotation_t, - sequenced_executor const& exec, char const* annotation) + Executor_ const& exec, char const* annotation) { auto exec_with_annotation = exec; exec_with_annotation.annotation_ = annotation; return exec_with_annotation; } - friend sequenced_executor tag_invoke( - hpx::execution::experimental::with_annotation_t, - sequenced_executor const& exec, std::string annotation) + // clang-format off + template + )> + // clang-format on + friend auto tag_invoke(hpx::execution::experimental::with_annotation_t, + Executor_ const& exec, std::string annotation) { auto exec_with_annotation = exec; exec_with_annotation.annotation_ = @@ -212,8 +223,14 @@ namespace hpx::execution { } #endif + // clang-format off + template + )> + // clang-format on friend constexpr std::size_t tag_invoke( - hpx::parallel::execution::processing_units_count_t, + hpx::parallel::execution::processing_units_count_t, Parameters&&, sequenced_executor const&, hpx::chrono::steady_duration const& = hpx::chrono::null_duration, std::size_t = 0) diff --git a/libs/core/executors/include/hpx/executors/thread_pool_scheduler.hpp b/libs/core/executors/include/hpx/executors/thread_pool_scheduler.hpp index 888e9abe4d4c..e9d2c7d25ddf 100644 --- a/libs/core/executors/include/hpx/executors/thread_pool_scheduler.hpp +++ b/libs/core/executors/include/hpx/executors/thread_pool_scheduler.hpp @@ -99,18 +99,29 @@ namespace hpx::execution::experimental { return pool_; } - friend constexpr thread_pool_policy_scheduler tag_invoke( + // clang-format off + template + )> + // clang-format on + friend constexpr auto tag_invoke( hpx::parallel::execution::with_processing_units_count_t, - thread_pool_policy_scheduler const& scheduler, - std::size_t num_cores) noexcept + Executor_ const& scheduler, std::size_t num_cores) noexcept { auto scheduler_with_num_cores = scheduler; scheduler_with_num_cores.num_cores_ = num_cores; return scheduler_with_num_cores; } + // clang-format off + template + )> + // clang-format on friend constexpr std::size_t tag_invoke( - hpx::parallel::execution::processing_units_count_t, + hpx::parallel::execution::processing_units_count_t, Parameters&&, thread_pool_policy_scheduler const& scheduler, hpx::chrono::steady_duration const& = hpx::chrono::null_duration, std::size_t = 0) @@ -118,10 +129,15 @@ namespace hpx::execution::experimental { return scheduler.get_num_cores(); } - friend constexpr thread_pool_policy_scheduler tag_invoke( + // clang-format off + template + )> + // clang-format on + friend constexpr auto tag_invoke( hpx::execution::experimental::with_first_core_t, - thread_pool_policy_scheduler const& exec, - std::size_t first_core) noexcept + Executor_ const& exec, std::size_t first_core) noexcept { auto exec_with_first_core = exec; exec_with_first_core.first_core_ = first_core; @@ -137,20 +153,29 @@ namespace hpx::execution::experimental { #if defined(HPX_HAVE_THREAD_DESCRIPTION) // support with_annotation property - friend constexpr thread_pool_policy_scheduler tag_invoke( + // clang-format off + template + )> + // clang-format on + friend constexpr auto tag_invoke( hpx::execution::experimental::with_annotation_t, - thread_pool_policy_scheduler const& scheduler, - char const* annotation) + Executor_ const& scheduler, char const* annotation) { auto sched_with_annotation = scheduler; sched_with_annotation.annotation_ = annotation; return sched_with_annotation; } - friend thread_pool_policy_scheduler tag_invoke( - hpx::execution::experimental::with_annotation_t, - thread_pool_policy_scheduler const& scheduler, - std::string annotation) + // clang-format off + template + )> + // clang-format on + friend auto tag_invoke(hpx::execution::experimental::with_annotation_t, + Executor_ const& scheduler, std::string annotation) { auto sched_with_annotation = scheduler; sched_with_annotation.annotation_ = diff --git a/libs/core/executors/include/hpx/executors/thread_pool_scheduler_bulk.hpp b/libs/core/executors/include/hpx/executors/thread_pool_scheduler_bulk.hpp index 6f5eb98943d5..fb826e25e93f 100644 --- a/libs/core/executors/include/hpx/executors/thread_pool_scheduler_bulk.hpp +++ b/libs/core/executors/include/hpx/executors/thread_pool_scheduler_bulk.hpp @@ -643,7 +643,9 @@ namespace hpx::execution::experimental::detail { , f(HPX_FORWARD(F_, f)) , pu_mask(detail::full_mask( hpx::execution::experimental::get_first_core(scheduler), - hpx::parallel::execution::processing_units_count(scheduler))) + hpx::parallel::execution::processing_units_count( + hpx::parallel::execution::null_parameters, scheduler, + hpx::chrono::null_duration, 0))) { } @@ -740,7 +742,9 @@ namespace hpx::execution::experimental::detail { , first_thread( hpx::execution::experimental::get_first_core(scheduler)) , num_worker_threads( - hpx::parallel::execution::processing_units_count(scheduler)) + hpx::parallel::execution::processing_units_count( + hpx::parallel::execution::null_parameters, scheduler, + hpx::chrono::null_duration, 0)) , pu_mask(HPX_MOVE(pumask)) , queues(num_worker_threads) , shape(HPX_FORWARD(Shape_, shape)) diff --git a/libs/core/executors/tests/regressions/pu_count_6184.cpp b/libs/core/executors/tests/regressions/pu_count_6184.cpp index 825e4a65b959..59a2dfb4fa85 100644 --- a/libs/core/executors/tests/regressions/pu_count_6184.cpp +++ b/libs/core/executors/tests/regressions/pu_count_6184.cpp @@ -16,7 +16,7 @@ int hpx_main() { hpx::parallel::execution::restricted_thread_pool_executor executor{0, 3}; HPX_TEST_EQ(hpx::parallel::execution::processing_units_count(executor), - std::size_t(3)); + static_cast(3)); return hpx::local::finalize(); } diff --git a/libs/core/resiliency/include/hpx/resiliency/replay_executor.hpp b/libs/core/resiliency/include/hpx/resiliency/replay_executor.hpp index 23cecc84c582..8610afa54b58 100644 --- a/libs/core/resiliency/include/hpx/resiliency/replay_executor.hpp +++ b/libs/core/resiliency/include/hpx/resiliency/replay_executor.hpp @@ -43,9 +43,9 @@ namespace hpx::resiliency::experimental { using future_type = hpx::traits::executor_future_t; - template - explicit replay_executor(BaseExecutor& exec, std::size_t n, F&& f) - : exec_(exec) + template + explicit replay_executor(BaseExecutor_&& exec, std::size_t n, F&& f) + : exec_(HPX_FORWARD(BaseExecutor_, exec)) , replay_count_(n) , validator_(HPX_FORWARD(F, f)) { @@ -154,12 +154,60 @@ namespace hpx::resiliency::experimental { } /// \endcond + public: + BaseExecutor const& get_executor() const + { + return exec_; + } + std::size_t get_replay_count() const + { + return replay_count_; + } + Validate const& get_validator() const + { + return validator_; + } + private: - BaseExecutor& exec_; + BaseExecutor exec_; std::size_t replay_count_; Validate validator_; }; + /////////////////////////////////////////////////////////////////////////// + // support all properties exposed by the wrapped executor + // clang-format off + template + )> + // clang-format on + auto tag_invoke(Tag tag, + replay_executor const& exec, Property&& prop) + -> decltype(replay_executor( + std::declval()( + std::declval(), std::declval()), + std::declval(), std::declval())) + { + return replay_executor( + tag(exec.get_executor(), HPX_FORWARD(Property, prop)), + exec.get_replay_count(), exec.get_validator()); + } + + // clang-format off + template + )> + // clang-format on + auto tag_invoke( + Tag tag, replay_executor const& exec) + -> decltype(std::declval()(std::declval())) + { + return tag(exec.get_executor()); + } + /////////////////////////////////////////////////////////////////////////// template replay_executor> make_replay_executor( diff --git a/libs/core/resiliency/include/hpx/resiliency/replicate_executor.hpp b/libs/core/resiliency/include/hpx/resiliency/replicate_executor.hpp index 81f499fd4b28..2fee3fe6eb2e 100644 --- a/libs/core/resiliency/include/hpx/resiliency/replicate_executor.hpp +++ b/libs/core/resiliency/include/hpx/resiliency/replicate_executor.hpp @@ -43,10 +43,10 @@ namespace hpx::resiliency::experimental { using future_type = hpx::traits::executor_future_t; - template + template explicit replicate_executor( - BaseExecutor& exec, std::size_t n, V&& v, F&& f) - : exec_(exec) + BaseExecutor_&& exec, std::size_t n, V&& v, F&& f) + : exec_(HPX_FORWARD(BaseExecutor_, exec)) , replicate_count_(n) , voter_(HPX_FORWARD(V, v)) , validator_(HPX_FORWARD(F, f)) @@ -157,13 +157,68 @@ namespace hpx::resiliency::experimental { } /// \endcond + public: + BaseExecutor const& get_executor() const + { + return exec_; + } + std::size_t get_replicate_count() const + { + return replicate_count_; + } + Vote const& get_voter() const + { + return voter_; + } + Validate const& get_validator() const + { + return validator_; + } + private: - BaseExecutor& exec_; + BaseExecutor exec_; std::size_t replicate_count_; Vote voter_; Validate validator_; }; + /////////////////////////////////////////////////////////////////////////// + // support all properties exposed by the wrapped executor + // clang-format off + template + )> + // clang-format on + auto tag_invoke(Tag tag, + replicate_executor const& exec, + Property&& prop) + -> decltype(replicate_executor( + std::declval()( + std::declval(), std::declval()), + std::declval(), std::declval(), + std::declval())) + { + return replicate_executor( + tag(exec.get_executor(), HPX_FORWARD(Property, prop)), + exec.get_replicate_count(), exec.get_voter(), exec.get_validator()); + } + + // clang-format off + template + )> + // clang-format on + auto tag_invoke( + Tag tag, replicate_executor const& exec) + -> decltype(std::declval()(std::declval())) + { + return tag(exec.get_executor()); + } + /////////////////////////////////////////////////////////////////////////// template replicate_executor, diff --git a/libs/core/tag_invoke/include/hpx/functional/detail/tag_fallback_invoke.hpp b/libs/core/tag_invoke/include/hpx/functional/detail/tag_fallback_invoke.hpp index 3a8c959b934b..801569cef949 100644 --- a/libs/core/tag_invoke/include/hpx/functional/detail/tag_fallback_invoke.hpp +++ b/libs/core/tag_invoke/include/hpx/functional/detail/tag_fallback_invoke.hpp @@ -274,7 +274,7 @@ namespace hpx::functional::detail { Args&&...>>>> HPX_HOST_DEVICE HPX_FORCEINLINE constexpr auto operator()( Args&&... args) const - noexcept(is_nothrow_tag_invocable_v) + noexcept(is_nothrow_tag_invocable_v) -> tag_invoke_result_t { return tag_invoke( @@ -289,7 +289,7 @@ namespace hpx::functional::detail { enable_tag_fallback_invoke_t, Args&&...>>>> HPX_HOST_DEVICE HPX_FORCEINLINE constexpr auto operator()( Args&&... args) const - noexcept(is_nothrow_tag_fallback_invocable_v) + noexcept(is_nothrow_tag_fallback_invocable_v) -> tag_fallback_invoke_result_t { return tag_fallback_invoke( diff --git a/libs/core/tag_invoke/include/hpx/functional/detail/tag_priority_invoke.hpp b/libs/core/tag_invoke/include/hpx/functional/detail/tag_priority_invoke.hpp index d759841102d9..593a93034604 100644 --- a/libs/core/tag_invoke/include/hpx/functional/detail/tag_priority_invoke.hpp +++ b/libs/core/tag_invoke/include/hpx/functional/detail/tag_priority_invoke.hpp @@ -258,7 +258,7 @@ namespace hpx::functional::detail { enable_tag_override_invoke_t, Args&&...>>>> HPX_HOST_DEVICE HPX_FORCEINLINE constexpr auto operator()( Args&&... args) const - noexcept(is_nothrow_tag_override_invocable_v) + noexcept(is_nothrow_tag_override_invocable_v) -> tag_override_invoke_result_t { return tag_override_invoke( @@ -274,7 +274,7 @@ namespace hpx::functional::detail { meta::invoke>>> HPX_HOST_DEVICE HPX_FORCEINLINE constexpr auto operator()( Args&&... args) const - noexcept(is_nothrow_tag_invocable_v) + noexcept(is_nothrow_tag_invocable_v) -> tag_invoke_result_t { return tag_invoke( @@ -292,7 +292,7 @@ namespace hpx::functional::detail { enable_tag_fallback_invoke_t, Args&&...>>>> HPX_HOST_DEVICE HPX_FORCEINLINE constexpr auto operator()( Args&&... args) const - noexcept(is_nothrow_tag_fallback_invocable_v) + noexcept(is_nothrow_tag_fallback_invocable_v) -> tag_fallback_invoke_result_t { return tag_fallback_invoke( diff --git a/libs/core/tag_invoke/include/hpx/functional/tag_invoke.hpp b/libs/core/tag_invoke/include/hpx/functional/tag_invoke.hpp index 08b9cbafef1e..00e8ba48f7a6 100644 --- a/libs/core/tag_invoke/include/hpx/functional/tag_invoke.hpp +++ b/libs/core/tag_invoke/include/hpx/functional/tag_invoke.hpp @@ -237,7 +237,7 @@ namespace hpx::functional { meta::invoke>>> HPX_HOST_DEVICE HPX_FORCEINLINE constexpr auto operator()( Args&&... args) const - noexcept(is_nothrow_tag_invocable_v) + noexcept(is_nothrow_tag_invocable_v) -> tag_invoke_result_t { return tag_invoke( diff --git a/libs/full/checkpoint/examples/1d_stencil_4_checkpoint.cpp b/libs/full/checkpoint/examples/1d_stencil_4_checkpoint.cpp index 7e52a55f9632..9a8fcf5f933d 100644 --- a/libs/full/checkpoint/examples/1d_stencil_4_checkpoint.cpp +++ b/libs/full/checkpoint/examples/1d_stencil_4_checkpoint.cpp @@ -6,25 +6,26 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// This is the fourth in a series of examples demonstrating the development of -// a fully distributed solver for a simple 1D heat distribution problem. +// This is the fourth in a series of examples demonstrating the development of a +// fully distributed solver for a simple 1D heat distribution problem. // // This example builds on example three. It futurizes the code from that // example. Compared to example two this code runs much more efficiently. It // allows for changing the amount of work executed in one HPX thread which -// enables tuning the performance for the optimal grain size of the -// computation. This example is still fully local but demonstrates nice -// scalability on SMP machines. +// enables tuning the performance for the optimal grain size of the computation. +// This example is still fully local but demonstrates nice scalability on SMP +// machines. // // In this variation of stencil we use the save_checkpoint and -// revive_checkpint functions to back up the state of the application -// every n time steps. +// restore_checkpoint functions to back up the state of the application every n +// time steps. // #include #include #include +#include #include #include #include @@ -63,16 +64,12 @@ inline std::size_t idx(std::size_t i, int dir, std::size_t size) struct partition_data { private: - typedef hpx::serialization::serialize_buffer buffer_type; + using buffer_type = hpx::serialization::serialize_buffer; public: - partition_data() - : data_() - , size_(0) - { - } + partition_data() = default; - partition_data(std::size_t size) + explicit partition_data(std::size_t size) : data_(std::allocator().allocate(size), size, buffer_type::take) , size_(size) { @@ -82,12 +79,12 @@ struct partition_data : data_(std::allocator().allocate(size), size, buffer_type::take) , size_(size) { - double base_value = double(initial_value * size); + double const base_value = static_cast(initial_value * size); for (std::size_t i = 0; i != size; ++i) - data_[i] = base_value + double(i); + data_[i] = base_value + static_cast(i); } - partition_data(const partition_data& old_part) + partition_data(partition_data const& old_part) : data_(std::allocator().allocate(old_part.size()), old_part.size(), buffer_type::take) , size_(old_part.size()) @@ -114,12 +111,12 @@ struct partition_data private: buffer_type data_; - std::size_t size_; + std::size_t size_ = 0; // Serialization Definitions friend class hpx::serialization::access; template - void serialize(Volume& vol, const unsigned int) + void serialize(Volume& vol, unsigned int const) { // clang-format off vol & data_ & size_; @@ -153,12 +150,12 @@ struct backup , file_name_(file_name) { } - backup(backup&& old) + backup(backup&& old) noexcept : bin(std::move(old.bin)) , file_name_(std::move(old.file_name_)) { } - ~backup() {} + ~backup() = default; void save(partition_data const& status, std::size_t index) { @@ -167,9 +164,10 @@ struct backup void write() { - hpx::util::checkpoint archive_data = + hpx::util::checkpoint const archive_data = hpx::util::save_checkpoint(hpx::launch::sync, bin); - // Make sure file stream is bianary for Windows/Mac machines + + // Make sure file stream is binary for Windows/Mac machines std::ofstream file_archive( file_name_, std::ios::binary | std::ios::out); if (file_archive.is_open()) @@ -180,20 +178,19 @@ struct backup { std::cout << "Error opening file!" << std::endl; } - file_archive.close(); } void revive(std::vector>>& U, std::size_t nx) { hpx::util::checkpoint temp_archive; - // Make sure file stream is bianary for Windows/Mac machines + // Make sure file stream is binary for Windows/Mac machines std::ifstream ist(file_name_, std::ios::binary | std::ios::in); ist >> temp_archive; hpx::util::restore_checkpoint(temp_archive, bin); for (std::size_t i = 0; i < U[0].size(); i++) { - partition_data temp(nx, double(i)); + partition_data temp(nx, static_cast(i)); hpx::util::restore_checkpoint(bin[i], temp); //Check for (std::size_t e = 0; e < temp.size(); e++) @@ -206,7 +203,8 @@ struct backup } }; -void print(std::vector>> U) +void print( + std::vector>> const& U) { for (std::size_t out = 0; out < U[0].size(); out++) { @@ -220,7 +218,7 @@ void print(std::vector>> U) } std::cout << std::endl; } -void print_space(std::vector> next) +void print_space(std::vector> const& next) { for (std::size_t out = 0; out < next.size(); out++) { @@ -239,8 +237,8 @@ void print_space(std::vector> next) struct stepper { // Our data for one time step - typedef hpx::shared_future partition; - typedef std::vector space; + using partition = hpx::shared_future; + using space = std::vector; // Our operator static double heat(double left, double middle, double right) @@ -253,7 +251,7 @@ struct stepper static partition_data heat_part(partition_data const& left, partition_data const& middle, partition_data const& right) { - std::size_t size = middle.size(); + std::size_t const size = middle.size(); partition_data next(size); next[0] = heat(left[size - 1], middle[0], middle[1]); @@ -270,8 +268,9 @@ struct stepper // do all the work on 'np' partitions, 'nx' data points each, for 'nt' // time steps, limit depth of dependency tree to 'nd' - hpx::future do_work(std::size_t np, std::size_t nx, std::size_t nt, - std::uint64_t nd, std::uint64_t cp, std::string rsf, std::string fn) + static hpx::future do_work(std::size_t np, std::size_t nx, + std::size_t nt, std::uint64_t nd, std::uint64_t cp, std::string rsf, + std::string fn) { using hpx::dataflow; using hpx::unwrapping; @@ -302,7 +301,8 @@ struct stepper auto range = hpx::util::counting_shape(np); using hpx::execution::par; hpx::ranges::for_each(par, range, [&U, nx](std::size_t i) { - U[0][i] = hpx::make_ready_future(partition_data(nx, double(i))); + U[0][i] = hpx::make_ready_future( + partition_data(nx, static_cast(i))); }); //Initialize from backup @@ -404,16 +404,18 @@ struct stepper /////////////////////////////////////////////////////////////////////////////// int hpx_main(hpx::program_options::variables_map& vm) { - std::uint64_t np = vm["np"].as(); // Number of partitions. - std::uint64_t nx = + std::uint64_t const np = + vm["np"].as(); // Number of partitions. + std::uint64_t const nx = vm["nx"].as(); // Number of grid points. - std::uint64_t nt = vm["nt"].as(); // Number of steps. - std::uint64_t nd = + std::uint64_t const nt = + vm["nt"].as(); // Number of steps. + std::uint64_t const nd = vm["nd"].as(); // Max depth of dep tree. - std::uint64_t cp = + std::uint64_t const cp = vm["cp"].as(); // Num. steps to checkpoint - std::string rsf = vm["restart-file"].as(); - std::string fn = vm["output-file"].as(); + std::string const rsf = vm["restart-file"].as(); + std::string const fn = vm["output-file"].as(); if (vm.count("no-header")) header = false; @@ -422,7 +424,7 @@ int hpx_main(hpx::program_options::variables_map& vm) stepper step; // Measure execution time. - std::uint64_t t = hpx::chrono::high_resolution_clock::now(); + std::uint64_t const t = hpx::chrono::high_resolution_clock::now(); // Execute nt time steps on nx grid points and print the final solution. hpx::future result = @@ -431,7 +433,7 @@ int hpx_main(hpx::program_options::variables_map& vm) stepper::space solution = result.get(); hpx::wait_all(solution); - std::uint64_t elapsed = hpx::chrono::high_resolution_clock::now() - t; + std::uint64_t const elapsed = hpx::chrono::high_resolution_clock::now() - t; // Print the final solution if (vm.count("results")) From 3d39b6e51ab41eabddbb3b08b575d29721d8ac15 Mon Sep 17 00:00:00 2001 From: Hartmut Kaiser Date: Sun, 20 Aug 2023 12:03:02 -0500 Subject: [PATCH 2/2] Fixing test scheduler_priority_check --- .../tests/unit/scheduler_priority_check.cpp | 101 +++++++++++------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/libs/core/resource_partitioner/tests/unit/scheduler_priority_check.cpp b/libs/core/resource_partitioner/tests/unit/scheduler_priority_check.cpp index 7be77c7ebeda..f38853cf81fb 100644 --- a/libs/core/resource_partitioner/tests/unit/scheduler_priority_check.cpp +++ b/libs/core/resource_partitioner/tests/unit/scheduler_priority_check.cpp @@ -32,7 +32,7 @@ void dummy_task(std::size_t n) { // no other work can take place on this thread whilst it sleeps bool sleep = true; - auto start = std::chrono::steady_clock::now(); + auto const start = std::chrono::steady_clock::now(); do { std::this_thread::sleep_for(std::chrono::microseconds(n) / 25); @@ -45,7 +45,7 @@ void dummy_task(std::size_t n) inline std::size_t st_rand() { - return std::size_t(std::rand()); + return static_cast(std::rand()); } int hpx_main(variables_map& vm) @@ -86,25 +86,31 @@ int hpx_main(variables_map& vm) // randomly create normal priority tasks // and then a set of HP tasks in periodic bursts // Use task plotting tools to validate that scheduling is correct - const int np_loop = vm["nnp"].as(); - const int hp_loop = vm["nhp"].as(); - const int np_m = vm["mnp"].as(); - const int hp_m = vm["mhp"].as(); - const int cycles = vm["cycles"].as(); - - const int np_total = np_loop * cycles; - // + int const np_loop = vm["nnp"].as(); + int const hp_loop = vm["nhp"].as(); + int const np_m = vm["mnp"].as(); + int const hp_m = vm["mhp"].as(); + int const cycles = vm["cycles"].as(); + + int const np_total = np_loop * cycles; + struct dec_counter { explicit dec_counter(std::atomic& counter) : counter_(counter) { } + + dec_counter(dec_counter const&) = delete; + dec_counter(dec_counter&&) = delete; + dec_counter& operator=(dec_counter const&) = delete; + dec_counter& operator=(dec_counter&&) = delete; + ~dec_counter() { --counter_; } - // + std::atomic& counter_; }; @@ -113,52 +119,63 @@ int hpx_main(variables_map& vm) std::atomic hp_task_count(0); std::atomic hp_launch_count(0); std::atomic launch_count(0); - // + std::atomic count_down((np_loop + hp_loop) * cycles); std::atomic counter(0); auto f3 = hpx::async(NP_executor, hpx::annotated_function( - [&]() { + [&]() -> hpx::future { ++launch_count; + + std::vector> v; + v.reserve(np_total); for (int i = 0; i < np_total; ++i) { // normal priority - auto f3 = hpx::async(NP_executor, + auto f = hpx::async(NP_executor, hpx::annotated_function( [&, np_m]() { - np_task_count++; + ++np_task_count; dec_counter dec(count_down); - dummy_task(std::size_t(np_m)); + dummy_task(static_cast(np_m)); }, "NP task")); // continuation runs as a sync task - f3.then(hpx::launch::sync, [&](hpx::future&&) { - // on every Nth task, spawn new HP tasks, otherwise quit - if ((++counter) % np_loop != 0) - return; - - // Launch HP tasks using an HP task to do it - hpx::async(HP_executor, - hpx::annotated_function( - [&]() { - ++hp_launch_count; - for (int j = 0; j < hp_loop; ++j) - { - hpx::async(HP_executor, - hpx::annotated_function( - [&]() { - ++hp_task_count; - dec_counter dec(count_down); - dummy_task( - std::size_t(hp_m)); - }, - "HP task")); - } - }, - "Launch HP")); - }); + v.push_back(f.then(hpx::launch::sync, + [&](hpx::future&&) -> hpx::future { + // on every Nth task, spawn new HP tasks, otherwise quit + if ((++counter) % np_loop != 0) + return hpx::make_ready_future(); + + // Launch HP tasks using an HP task to do it + return hpx::async(HP_executor, + hpx::annotated_function( + [&]() -> hpx::future { + ++hp_launch_count; + + std::vector> v1; + v1.reserve(hp_loop); + for (int j = 0; j < hp_loop; ++j) + { + v1.push_back(hpx::async(HP_executor, + hpx::annotated_function( + [&]() { + ++hp_task_count; + dec_counter dec( + count_down); + dummy_task(static_cast< + std::size_t>(hp_m)); + }, + "HP task"))); + } + return hpx::when_all(std::move(v1)); + }, + "Launch HP")); + })); } + + return hpx::when_all(std::move(v)); }, "Launch")); @@ -168,6 +185,8 @@ int hpx_main(variables_map& vm) hpx::this_thread::yield(); } while (count_down > 0); + f3.get(); + std::cout << "Tasks NP : " << np_task_count << "\n" << "Tasks HP : " << hp_task_count << "\n" << "Launch : " << launch_count << "\n"