diff --git a/.jenkins/lsu/entry.sh b/.jenkins/lsu/entry.sh index 7c53c8ec944e..7f700763f54e 100755 --- a/.jenkins/lsu/entry.sh +++ b/.jenkins/lsu/entry.sh @@ -27,7 +27,7 @@ sbatch \ --job-name="jenkins-hpx-${configuration_name_with_build_type}" \ --nodes="${configuration_slurm_num_nodes}" \ --partition="${configuration_slurm_partition}" \ - --time="01:30:00" \ + --time="03:00:00" \ --output="jenkins-hpx-${configuration_name_with_build_type}.out" \ --error="jenkins-hpx-${configuration_name_with_build_type}.err" \ --wait .jenkins/lsu/batch.sh diff --git a/.jenkins/lsu/slurm-configuration-clang-7.sh b/.jenkins/lsu/slurm-configuration-clang-7.sh index e9ef98e1ea06..0d78dd2220db 100644 --- a/.jenkins/lsu/slurm-configuration-clang-7.sh +++ b/.jenkins/lsu/slurm-configuration-clang-7.sh @@ -4,5 +4,5 @@ # 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) -configuration_slurm_partition="marvin" +configuration_slurm_partition="medusa" configuration_slurm_num_nodes="1" diff --git a/.jenkins/lsu/slurm-configuration-clang-8.sh b/.jenkins/lsu/slurm-configuration-clang-8.sh index e9ef98e1ea06..0d78dd2220db 100644 --- a/.jenkins/lsu/slurm-configuration-clang-8.sh +++ b/.jenkins/lsu/slurm-configuration-clang-8.sh @@ -4,5 +4,5 @@ # 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) -configuration_slurm_partition="marvin" +configuration_slurm_partition="medusa" configuration_slurm_num_nodes="1" diff --git a/.jenkins/lsu/slurm-configuration-clang-9.sh b/.jenkins/lsu/slurm-configuration-clang-9.sh index e9ef98e1ea06..0d78dd2220db 100644 --- a/.jenkins/lsu/slurm-configuration-clang-9.sh +++ b/.jenkins/lsu/slurm-configuration-clang-9.sh @@ -4,5 +4,5 @@ # 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) -configuration_slurm_partition="marvin" +configuration_slurm_partition="medusa" configuration_slurm_num_nodes="1" diff --git a/CMakeLists.txt b/CMakeLists.txt index a0db00a9f993..525077b5016d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -932,8 +932,20 @@ if(HPX_WITH_APEX) endif() # LibCDS option -hpx_option(HPX_WITH_LIBCDS BOOL "Enable LibCDS support." OFF) +hpx_option( + HPX_WITH_LIBCDS BOOL "Enable LibCDS support (experimental)." OFF + CATEGORY "Thread Manager" ADVANCED +) if(HPX_WITH_LIBCDS) + hpx_option( + HPX_WITH_LIBCDS_GIT_REPOSITORY STRING + "Define the LibCDS git repository to use." + https://github.com/STEllAR-GROUP/libcds CATEGORY "Thread Manager" ADVANCED + ) + hpx_option( + HPX_WITH_LIBCDS_GIT_TAG STRING "Define the LibCDS git tag to use." + hpx-thread CATEGORY "Thread Manager" ADVANCED + ) include(HPX_SetupLibCDS) if(NOT libcds_POPULATED) hpx_error("HPX_WITH_LIBCDS was set to ON, but HPX failed to fetch LibCDS") diff --git a/cmake/HPX_SetupLibCDS.cmake b/cmake/HPX_SetupLibCDS.cmake index 3b41ba088032..db11803ab42c 100644 --- a/cmake/HPX_SetupLibCDS.cmake +++ b/cmake/HPX_SetupLibCDS.cmake @@ -17,6 +17,7 @@ if(HPX_WITH_LIBCDS AND NOT TARGET LibCDS::cds) include(FetchContent) + include(HPX_Message) set(LIBCDS_WITH_HPX ON @@ -27,11 +28,14 @@ if(HPX_WITH_LIBCDS AND NOT TARGET LibCDS::cds) CACHE INTERNAL "" ) + hpx_info( + "Fetching libCDS from repository: ${HPX_WITH_LIBCDS_GIT_REPOSITORY}, " + "tag: ${HPX_WITH_LIBCDS_GIT_TAG}" + ) fetchcontent_declare( libcds - # GIT_REPOSITORY https://github.com/khizmax/libcds - GIT_REPOSITORY https://github.com/weilewei/libcds - GIT_TAG hpx-thread + GIT_REPOSITORY ${HPX_WITH_LIBCDS_GIT_REPOSITORY} + GIT_TAG ${HPX_WITH_LIBCDS_GIT_TAG} GIT_SHALLOW TRUE ) fetchcontent_getproperties(libcds) @@ -40,6 +44,9 @@ if(HPX_WITH_LIBCDS AND NOT TARGET LibCDS::cds) fetchcontent_populate(libcds) set(LIBCDS_CXX_STANDARD ${HPX_CXX_STANDARD}) add_subdirectory(${libcds_SOURCE_DIR} ${libcds_BINARY_DIR}) + + set_target_properties(cds PROPERTIES FOLDER "Core") + set_target_properties(cds-s PROPERTIES FOLDER "Core") endif() endif() diff --git a/docs/sphinx/manual/optimizing_hpx_applications.rst b/docs/sphinx/manual/optimizing_hpx_applications.rst index fc0ff5a59251..d40b51f74be5 100644 --- a/docs/sphinx/manual/optimizing_hpx_applications.rst +++ b/docs/sphinx/manual/optimizing_hpx_applications.rst @@ -805,7 +805,7 @@ system and application performance. where: ```` is one of the following: ``primary``, - ``locality``, ``component`` or ``symbol`` + ``locality``, ``component`` or ``symbol`` * ``/total`` @@ -868,7 +868,7 @@ system and application performance. where: ```` is one of the following: ``primary``, - ``locality``, ``component`` or ``symbol``. + ``locality``, ``component`` or ``symbol`` * ``/total`` where: @@ -901,7 +901,7 @@ system and application performance. where: ```` is one of the following: ``cache/evictions``, - ``cache/hits``, ``cache/inserts``, ``cache/misses`` + ``cache/hits``, ``cache/insertions``, ``cache/misses`` * ``locality#*/total`` where: @@ -1143,7 +1143,7 @@ system and application performance. where: ```` is one of the following: ``cache/insertions``, - ``cache/evictions``, ``cache/hits``, ``cache/misses`` ``cache/misses`` + ``cache/evictions``, ``cache/hits``, ``cache/misses`` ` +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using communication_type = double; + +HPX_REGISTER_CHANNEL_DECLARATION(communication_type); +HPX_REGISTER_CHANNEL(communication_type, stencil_communication); + +int hpx_main(boost::program_options::variables_map& vm) +{ + std::size_t Nx_global = vm["Nx"].as(); + std::size_t steps = vm["steps"].as(); + std::size_t nlp = vm["Nlp"].as(); + + typedef hpx::compute::host::block_allocator allocator_type; + typedef hpx::compute::host::block_executor<> executor_type; + typedef hpx::compute::vector data_type; + + std::array U; + + auto numa_domains = hpx::compute::host::numa_domains(); + allocator_type alloc(numa_domains); + + std::size_t num_localities = hpx::get_num_localities(hpx::launch::sync); + std::size_t num_worker_threads = hpx::get_num_worker_threads(); + std::size_t rank = hpx::get_locality_id(); + + hpx::util::high_resolution_timer t_main; + + // Keep only partial data + std::size_t Nx = Nx_global / num_localities; + std::size_t local_nx = Nx / nlp; + + U[0] = data_type(Nx, 0.0, alloc); + U[1] = data_type(Nx, 0.0, alloc); + + init(U, Nx, rank, num_localities); + + // setup communicator + using communicator_type = communicator; + communicator_type comm(rank, num_localities); + + if (rank == 0) + { + std::cout << "Starting benchmark with " << num_localities << + " nodes and " << num_worker_threads << + " threads.\n"; + } + + if (comm.has_neighbor(communicator_type::left)) + { + // Send initial value to the left neighbor + comm.set(communicator_type::left, U[0][0], 0); + } + if (comm.has_neighbor(communicator_type::right)) + { + // Send initial value to the right neighbor + comm.set(communicator_type::right, U[0][Nx-1], 0); + } + + auto range = boost::irange(static_cast(0), nlp); + + executor_type executor(numa_domains); + auto policy = hpx::parallel::execution::par.on(executor); + + hpx::util::high_resolution_timer t; + for (std::size_t t = 0; t < steps; ++t) + { + data_type& curr = U[t % 2]; + data_type& next = U[(t + 1) % 2]; + + hpx::future l = hpx::make_ready_future(); + hpx::future r = hpx::make_ready_future(); + + if (comm.has_neighbor(communicator_type::left)) + { + l = comm.get(communicator_type::left, t) + .then(hpx::launch::sync, + [&next, &curr, &comm, t](hpx::future&& gg) + { + double left = gg.get(); + + next[0] = curr[0] + + ((k*dt)/(dx*dx)) * (left - 2*curr[0] + curr[1]); + + // Dispatch the updated value to left neighbor for it + // to get consumed in the next timestep + comm.set(communicator_type::left, next[0], t+1); + } + ); + } + + if (comm.has_neighbor(communicator_type::right)) + { + r = comm.get(communicator_type::right, t) + .then(hpx::launch::sync, + [&next, &curr, &comm, t, Nx](hpx::future&& gg) + { + double right = gg.get(); + + next[Nx-1] = curr[Nx-1] + ((k*dt)/(dx*dx)) * + (curr[Nx-2] - 2*curr[Nx-1] + right); + + // Dispatch the updated value to right neighbor for it + // to get consumed in the next timestep + comm.set(communicator_type::right, next[Nx-1], t+1); + } + ); + } + + hpx::parallel::for_each( + policy, + std::begin(range), std::end(range), + [&U, local_nx, nlp, t] (std::size_t i) + { + if (i == 0) + stencil_update(U, 1, local_nx, t); + else if (i == nlp-1) + stencil_update(U, i * local_nx, (i + 1) * local_nx - 1, t); + else if (i > 0 && i < nlp-1) + stencil_update(U, i * local_nx, (i + 1) * local_nx, t); + } + ); + + hpx::wait_all(l, r); + } + double elapsed = t.elapsed(); + double telapsed = t_main.elapsed(); + + if (rank == 0) + { + std::cout << "Total time: " << telapsed << std::endl; + std::cout << "Kernel execution time: " << elapsed << std::endl; + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + using namespace hpx::program_options; + + options_description desc_commandline; + desc_commandline.add_options() + ("Nx", value()->default_value(1024), + "Total stencil points") + ("Nlp", value()->default_value(16), + "Number of Local Partitions") + ("steps", value()->default_value(100), + "Number of steps to apply the stencil") + ; + + // Initialize and run HPX, this example requires to run hpx_main on all + // localities + std::vector const cfg = { + "hpx.run_hpx_main!=1", + }; + + return hpx::init(desc_commandline, argc, argv, cfg); +} diff --git a/examples/1d_stencil/CMakeLists.txt b/examples/1d_stencil/CMakeLists.txt index 868f0aab59fc..00625757055e 100644 --- a/examples/1d_stencil/CMakeLists.txt +++ b/examples/1d_stencil/CMakeLists.txt @@ -19,6 +19,7 @@ set(example_programs 1d_stencil_6 1d_stencil_7 1d_stencil_8 + 1d_stencil_channel ) if(HPX_WITH_APEX) diff --git a/examples/1d_stencil/communicator.hpp b/examples/1d_stencil/communicator.hpp new file mode 100644 index 000000000000..70eff8d00a01 --- /dev/null +++ b/examples/1d_stencil/communicator.hpp @@ -0,0 +1,89 @@ +// Copyright (c) 2016 Thomas Heller +// Copyright (c) 2020 Nikunj Gupta +// +// 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) + +#pragma once + +#include + +#include +#include + +template +struct communicator +{ + enum neighbor { + left = 0, + right = 1, + }; + + typedef hpx::lcos::channel channel_type; + + // rank: our rank in the system + // num: number of participating partners + communicator(std::size_t rank, std::size_t num) + { + static const char* left_name = "/stencil/left/"; + static const char* right_name = "/stencil/right/"; + + // Only set left channels if we have more than one partner + if (num > 1) + { + // We have an leftper neighbor if our rank is greater than zero. + if (rank > 0) + { + // Retrieve the channel from our leftper neighbor from which + // we receive the row we need to leftdate the first row in our + // partition. + recv[left] = hpx::find_from_basename< + channel_type>(right_name, rank - 1); + + // Create the channel we use to send our first row to our + // left neighbor + send[left] = channel_type(hpx::find_here()); + // Register the channel with a name such that our neighbor can + // find it. + hpx::register_with_basename(left_name, send[left], rank); + } + if (rank < num - 1) + { + // Retrieve the channel from our neighbor below from which we + // receive the row we need to leftdate the last row in our + // partition. + recv[right] = hpx::find_from_basename< + channel_type>(left_name, rank + 1); + // Create the channel we use to send our last row to our + // neighbor below + send[right] = channel_type(hpx::find_here()); + // Register the channel with a name such that our neighbor + // can find it. + hpx::register_with_basename(right_name, send[right], rank); + } + } + } + + bool has_neighbor(neighbor n) const + { + return recv[n] && send[n]; + } + + void set(neighbor n, T t, std::size_t step) + { + // Send our data to the neighbor n using fire and forget semantics + // Synchronization happens when receiving values. + send[n].set(t, step); + } + + hpx::future get(neighbor n, std::size_t step) + { + // Get our data from our neighbor, we return a future to allow the + // algorithm to synchronize. + return recv[n].get(hpx::launch::async, step); + } + + std::array, 2> recv; + std::array, 2> send; +}; diff --git a/examples/1d_stencil/stencil.hpp b/examples/1d_stencil/stencil.hpp new file mode 100644 index 000000000000..69de42097557 --- /dev/null +++ b/examples/1d_stencil/stencil.hpp @@ -0,0 +1,57 @@ +// Copyright (c) 2020 Nikunj Gupta +// +// 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) + +#pragma once + +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + +using allocator_type = hpx::compute::host::block_allocator; +using data_type = hpx::compute::vector; + +const double k = 0.5; // heat transfer coefficient +const double dt = 1.; // time step +const double dx = 1.; // grid spacing + +template +void init( + std::array& U, std::size_t Nx, + std::size_t rank = 0, std::size_t num_localities = 1) +{ + // Initialize: Boundaries are set to 1, interior is 0 + if (rank == 0) + { + U[0][0] = 1.0; + U[1][0] = 1.0; + } + if (rank == num_localities - 1) + { + U[0][Nx-1] = 100.0; + U[1][Nx-1] = 100.0; + } +} + +void stencil_update(std::array& U, const std::size_t& begin + , const std::size_t& end, const std::size_t t) +{ + data_type& curr = U[t % 2]; + data_type& next = U[(t + 1) % 2]; + + for (std::size_t i = begin; i < end; ++i) + { + next[i] = curr[i] + ((k*dt)/(dx*dx)) * + (curr[i-1] - 2*curr[i] + curr[i+1]); + } +} diff --git a/hpx/lcos/detail/promise_base.hpp b/hpx/lcos/detail/promise_base.hpp index f8eea5c44367..01bb1a981179 100644 --- a/hpx/lcos/detail/promise_base.hpp +++ b/hpx/lcos/detail/promise_base.hpp @@ -270,14 +270,6 @@ namespace lcos { return get_id(false, ec); } -#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY) - HPX_DEPRECATED(HPX_DEPRECATED_MSG) - naming::id_type get_gid(error_code& ec = throws) const - { - return get_id(false, ec); - } -#endif - naming::address resolve(error_code& ec = throws) const { if (!addr_ || !id_) diff --git a/hpx/runtime/actions/continuation.hpp b/hpx/runtime/actions/continuation.hpp index 10b12fd57e88..99a7bde02ff5 100644 --- a/hpx/runtime/actions/continuation.hpp +++ b/hpx/runtime/actions/continuation.hpp @@ -63,14 +63,6 @@ namespace hpx { namespace actions void serialize(hpx::serialization::input_archive& ar, unsigned); void serialize(hpx::serialization::output_archive& ar, unsigned); -#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY) - HPX_DEPRECATED(HPX_DEPRECATED_MSG) - naming::id_type const& get_gid() const - { - return gid_; - } -#endif - naming::id_type const& get_id() const { return gid_; diff --git a/hpx/runtime/components/client_base.hpp b/hpx/runtime/components/client_base.hpp index c98a90303238..581c28a7a182 100644 --- a/hpx/runtime/components/client_base.hpp +++ b/hpx/runtime/components/client_base.hpp @@ -397,14 +397,6 @@ namespace hpx { namespace components } /////////////////////////////////////////////////////////////////////// -#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY) - HPX_DEPRECATED(HPX_DEPRECATED_MSG) - id_type const& get_gid() const - { - return get_id(); - } -#endif - id_type const& get_id() const { return get(); diff --git a/hpx/runtime/components/runtime_support.hpp b/hpx/runtime/components/runtime_support.hpp index 2ddf13e56543..f538baeabca8 100644 --- a/hpx/runtime/components/runtime_support.hpp +++ b/hpx/runtime/components/runtime_support.hpp @@ -139,14 +139,6 @@ namespace hpx { namespace components } /////////////////////////////////////////////////////////////////////// -#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY) - HPX_DEPRECATED(HPX_DEPRECATED_MSG) - naming::id_type const& get_gid() const - { - return gid_; - } -#endif - naming::id_type const& get_id() const { return gid_; diff --git a/hpx/runtime/components/server/component_base.hpp b/hpx/runtime/components/server/component_base.hpp index 1cecc958bfda..26ddc84dd4ee 100644 --- a/hpx/runtime/components/server/component_base.hpp +++ b/hpx/runtime/components/server/component_base.hpp @@ -180,13 +180,6 @@ namespace hpx { namespace components static_cast(*this).get_base_gid()); } -#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY) - HPX_DEPRECATED(HPX_DEPRECATED_MSG) - naming::id_type get_gid() const - { - return get_id(); - } -#endif protected: naming::gid_type get_base_gid( naming::gid_type const& assign_gid = naming::invalid_gid) const diff --git a/hpx/runtime/components/server/fixed_component_base.hpp b/hpx/runtime/components/server/fixed_component_base.hpp index 94bc45eaa418..2c24d2ed998d 100644 --- a/hpx/runtime/components/server/fixed_component_base.hpp +++ b/hpx/runtime/components/server/fixed_component_base.hpp @@ -142,14 +142,6 @@ class fixed_component_base : public traits::detail::fixed_component_tag naming::id_type::unmanaged); } -#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY) - HPX_DEPRECATED(HPX_DEPRECATED_MSG) - naming::id_type get_gid() const - { - return get_unmanaged_id(); - } -#endif - void set_locality_id(std::uint32_t locality_id, error_code& ec = throws) { if (gid_) { diff --git a/hpx/runtime/components/server/managed_component_base.hpp b/hpx/runtime/components/server/managed_component_base.hpp index d782110bba48..6e0f6d581ef0 100644 --- a/hpx/runtime/components/server/managed_component_base.hpp +++ b/hpx/runtime/components/server/managed_component_base.hpp @@ -253,14 +253,6 @@ namespace hpx { namespace components naming::id_type get_unmanaged_id() const; naming::id_type get_id() const; -#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY) - HPX_DEPRECATED(HPX_DEPRECATED_MSG) - naming::id_type get_gid() const - { - return get_unmanaged_id(); - } -#endif - protected: naming::gid_type get_base_gid() const; @@ -453,14 +445,6 @@ namespace hpx { namespace components return naming::id_type(get_base_gid(), naming::id_type::unmanaged); } -#if defined(HPX_HAVE_COMPONENT_GET_GID_COMPATIBILITY) - HPX_DEPRECATED(HPX_DEPRECATED_MSG) - naming::id_type get_gid() const - { - return get_unmanaged_id(); - } -#endif - private: #if !defined(__NVCC__) && !defined(__CUDACC__) // declare friends which are allowed to access get_base_gid() diff --git a/libs/async_mpi/tests/unit/CMakeLists.txt b/libs/async_mpi/tests/unit/CMakeLists.txt index 14b28a7266fe..30e6de80fa01 100644 --- a/libs/async_mpi/tests/unit/CMakeLists.txt +++ b/libs/async_mpi/tests/unit/CMakeLists.txt @@ -4,8 +4,7 @@ # 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) -set(tests # mpi_ring_async_executor -) +set(tests mpi_ring_async_executor) set(mpi_ring_async_executor_PARAMETERS THREADS_PER_LOCALITY 4 LOCALITIES 2 RUNWRAPPER mpi diff --git a/libs/async_mpi/tests/unit/mpi_ring_async_executor.cpp b/libs/async_mpi/tests/unit/mpi_ring_async_executor.cpp index db58cc50a60c..3744c0542549 100644 --- a/libs/async_mpi/tests/unit/mpi_ring_async_executor.cpp +++ b/libs/async_mpi/tests/unit/mpi_ring_async_executor.cpp @@ -167,10 +167,6 @@ int hpx_main(hpx::program_options::variables_map& vm) } } - // This is needed to make sure that one rank does not shut down - // before others have completed. MPI does not handle that well. - MPI_Barrier(MPI_COMM_WORLD); - if (rank == 0) { std::cout << "time " << t.elapsed() << std::endl; @@ -186,6 +182,10 @@ int hpx_main(hpx::program_options::variables_map& vm) // on an hpx thread int main(int argc, char* argv[]) { + // if this test is run with distributed runtime, we need to make sure + // that all ranks run their main function + std::vector cfg = {"hpx.run_hpx_main!=1"}; + // Init MPI int provided = MPI_THREAD_MULTIPLE; MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); @@ -208,7 +208,7 @@ int main(int argc, char* argv[]) // clang-format on // Initialize and run HPX. - auto result = hpx::init(cmdline, argc, argv); + auto result = hpx::init(cmdline, argc, argv, cfg); // Finalize MPI MPI_Finalize(); diff --git a/libs/execution/include/hpx/execution/traits/executor_traits.hpp b/libs/execution/include/hpx/execution/traits/executor_traits.hpp index 952cfe7b1833..0a8792b96f69 100644 --- a/libs/execution/include/hpx/execution/traits/executor_traits.hpp +++ b/libs/execution/include/hpx/execution/traits/executor_traits.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,11 @@ #include #include +namespace hpx { namespace lcos { + template + class future; +}} // namespace hpx::lcos + namespace hpx { namespace parallel { namespace execution { /////////////////////////////////////////////////////////////////////////// struct static_chunk_size; @@ -174,6 +180,65 @@ namespace hpx { namespace parallel { namespace execution { hpx::util::detected_or_t; }; + + /////////////////////////////////////////////////////////////////////////// + namespace detail { + template + struct executor_future; + + template + struct exposes_future_type : std::false_type + { + }; + + template + struct exposes_future_type>::type> + : std::true_type + { + }; + + template + struct executor_future, + typename std::enable_if< + hpx::traits::is_two_way_executor::value && + exposes_future_type::value>::type> + { + using type = typename Executor::template future_type; + }; + + template + struct executor_future, + typename std::enable_if< + hpx::traits::is_two_way_executor::value && + !exposes_future_type::value>::type> + { + using type = decltype(std::declval().async_execute( + std::declval(), std::declval()...)); + }; + + template + struct executor_future::value>::type> + { + using type = hpx::lcos::future; + }; + } // namespace detail + + template + struct executor_future + : detail::executor_future::type, T, + hpx::util::pack::type...>> + { + }; + + template + using executor_future_t = + typename executor_future::type; + }}} // namespace hpx::parallel::execution namespace hpx { namespace traits { @@ -266,6 +331,18 @@ namespace hpx { namespace traits { template using executor_index_t = typename executor_index::type; + template + struct executor_future + : parallel::execution::executor_future< + typename std::decay::type, T, + typename std::decay::type...> + { + }; + + template + using executor_future_t = + typename executor_future::type; + /////////////////////////////////////////////////////////////////////////// // extension template diff --git a/libs/execution/include/hpx/execution/traits/future_then_result_exec.hpp b/libs/execution/include/hpx/execution/traits/future_then_result_exec.hpp index e478617f105d..fe32143ff478 100644 --- a/libs/execution/include/hpx/execution/traits/future_then_result_exec.hpp +++ b/libs/execution/include/hpx/execution/traits/future_then_result_exec.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -22,64 +23,6 @@ #include namespace hpx { namespace traits { - /////////////////////////////////////////////////////////////////////////// - namespace detail { - template - struct executor_future; - - template - struct exposes_future_type : std::false_type - { - }; - - template - struct exposes_future_type>::type> - : std::true_type - { - }; - - template - struct executor_future, - typename std::enable_if< - hpx::traits::is_two_way_executor::value && - exposes_future_type::value>::type> - { - using type = typename Executor::template future_type; - }; - - template - struct executor_future, - typename std::enable_if< - hpx::traits::is_two_way_executor::value && - !exposes_future_type::value>::type> - { - using type = decltype(std::declval().async_execute( - std::declval(), std::declval()...)); - }; - - template - struct executor_future::value>::type> - { - using type = hpx::lcos::future; - }; - } // namespace detail - - template - struct executor_future - : detail::executor_future::type, T, - hpx::util::pack::type...>> - { - }; - - template - using executor_future_t = - typename executor_future::type; - /////////////////////////////////////////////////////////////////////////// namespace detail { /////////////////////////////////////////////////////////////////////// diff --git a/libs/execution_base/CMakeLists.txt b/libs/execution_base/CMakeLists.txt index 4881f68c7a10..347209d7eaa6 100644 --- a/libs/execution_base/CMakeLists.txt +++ b/libs/execution_base/CMakeLists.txt @@ -44,7 +44,13 @@ add_hpx_module( SOURCES ${execution_base_sources} HEADERS ${execution_base_headers} COMPAT_HEADERS ${execution_base_compat_headers} - DEPENDENCIES hpx_assertion hpx_config hpx_errors hpx_format hpx_functional - hpx_timing + DEPENDENCIES + hpx_assertion + hpx_config + hpx_errors + hpx_format + hpx_functional + hpx_iterator_support + hpx_timing CMAKE_SUBDIRS examples tests ) diff --git a/libs/execution_base/include/hpx/execution_base/execution.hpp b/libs/execution_base/include/hpx/execution_base/execution.hpp index 02541715e3f2..206acf65d2b2 100644 --- a/libs/execution_base/include/hpx/execution_base/execution.hpp +++ b/libs/execution_base/include/hpx/execution_base/execution.hpp @@ -10,6 +10,7 @@ #pragma once #include +#include #include #include @@ -309,12 +310,26 @@ namespace hpx { namespace parallel { namespace execution { /////////////////////////////////////////////////////////////////////// // bulk_async_execute customization point + template + using counting_shape_type = hpx::util::iterator_range< + hpx::util::counting_iterator>; + + template + counting_shape_type make_counting_shape(Incrementable n) + { + return hpx::util::make_iterator_range( + hpx::util::make_counting_iterator(Incrementable(0)), + hpx::util::make_counting_iterator(n)); + } + template <> struct customization_point { public: template + typename... Ts, + typename Enable = typename std::enable_if< + !std::is_integral::value>::type> HPX_FORCEINLINE auto operator()( Executor&& exec, F&& f, Shape const& shape, Ts&&... ts) const -> decltype(bulk_async_execute(std::forward(exec), @@ -323,6 +338,22 @@ namespace hpx { namespace parallel { namespace execution { return bulk_async_execute(std::forward(exec), std::forward(f), shape, std::forward(ts)...); } + + template ::value>::type> + HPX_FORCEINLINE auto operator()( + Executor&& exec, F&& f, Shape const& n, Ts&&... ts) const + -> decltype(bulk_async_execute(std::forward(exec), + std::forward(f), + std::declval>(), + std::forward(ts)...)) + { + return bulk_async_execute(std::forward(exec), + std::forward(f), make_counting_shape(n), + std::forward(ts)...); + } }; /////////////////////////////////////////////////////////////////////// @@ -332,7 +363,9 @@ namespace hpx { namespace parallel { namespace execution { { public: template + typename... Ts, + typename Enable = typename std::enable_if< + !std::is_integral::value>::type> HPX_FORCEINLINE auto operator()( Executor&& exec, F&& f, Shape const& shape, Ts&&... ts) const -> decltype(bulk_sync_execute(std::forward(exec), @@ -341,6 +374,22 @@ namespace hpx { namespace parallel { namespace execution { return bulk_sync_execute(std::forward(exec), std::forward(f), shape, std::forward(ts)...); } + + template ::value>::type> + HPX_FORCEINLINE auto operator()( + Executor&& exec, F&& f, Shape const& n, Ts&&... ts) const + -> decltype(bulk_sync_execute(std::forward(exec), + std::forward(f), + std::declval>(), + std::forward(ts)...)) + { + return bulk_sync_execute(std::forward(exec), + std::forward(f), make_counting_shape(n), + std::forward(ts)...); + } }; /////////////////////////////////////////////////////////////////////// @@ -350,7 +399,9 @@ namespace hpx { namespace parallel { namespace execution { { public: template + typename Future, typename... Ts, + typename Enable = typename std::enable_if< + !std::is_integral::value>::type> HPX_FORCEINLINE auto operator()(Executor&& exec, F&& f, Shape const& shape, Future&& predecessor, Ts&&... ts) const -> decltype(bulk_then_execute(std::forward(exec), @@ -361,6 +412,22 @@ namespace hpx { namespace parallel { namespace execution { std::forward(f), shape, std::forward(predecessor), std::forward(ts)...); } + + template ::value>::type> + HPX_FORCEINLINE auto operator()(Executor&& exec, F&& f, + Shape const& n, Future&& predecessor, Ts&&... ts) const + -> decltype(bulk_then_execute(std::forward(exec), + std::forward(f), + std::declval>(), + std::forward(predecessor), std::forward(ts)...)) + { + return bulk_then_execute(std::forward(exec), + std::forward(f), make_counting_shape(n), + std::forward(predecessor), std::forward(ts)...); + } }; /// \endcond } // namespace detail diff --git a/libs/iterator_support/include/hpx/iterator_support/counting_iterator.hpp b/libs/iterator_support/include/hpx/iterator_support/counting_iterator.hpp index 3b5b28156077..047d99ba1d9a 100644 --- a/libs/iterator_support/include/hpx/iterator_support/counting_iterator.hpp +++ b/libs/iterator_support/include/hpx/iterator_support/counting_iterator.hpp @@ -84,7 +84,7 @@ namespace hpx { namespace util { } // namespace detail //////////////////////////////////////////////////////////////////////////// - // specialization for Iterators (non-itengral types) + // specialization for Iterators (non-integral types) template class counting_iterator diff --git a/libs/resiliency/CMakeLists.txt b/libs/resiliency/CMakeLists.txt index 81c00a20bb21..dbf33d39b2fd 100644 --- a/libs/resiliency/CMakeLists.txt +++ b/libs/resiliency/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2019 The STE||AR-Group +# Copyright (c) 2019-2020 The STE||AR-Group # # SPDX-License-Identifier: BSL-1.0 # Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -11,12 +11,13 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Default location is $HPX_ROOT/libs/resiliency/include set(resiliency_headers hpx/resiliency/async_replay.hpp + hpx/resiliency/async_replay_executor.hpp hpx/resiliency/async_replicate.hpp + hpx/resiliency/async_replicate_executor.hpp hpx/resiliency/config.hpp - hpx/resiliency/dataflow_replay.hpp - hpx/resiliency/dataflow_replicate.hpp hpx/resiliency/version.hpp hpx/resiliency/resiliency.hpp + hpx/resiliency/resiliency_cpos.hpp ) # Default location is $HPX_ROOT/libs/resiliency/src @@ -25,9 +26,19 @@ set(resiliency_sources resiliency.cpp) include(HPX_AddModule) add_hpx_module( resiliency - GLOBAL_HEADER_GEN OFF + GLOBAL_HEADER_GEN ON SOURCES ${resiliency_sources} HEADERS ${resiliency_headers} - DEPENDENCIES hpx_assertion hpx_config hpx_datastructures hpx_async_local + DEPENDENCIES + DEPENDENCIES + hpx_assertion + hpx_async_local + hpx_config + hpx_concepts + hpx_datastructures + hpx_execution + hpx_functional + hpx_futures + hpx_type_support CMAKE_SUBDIRS examples tests ) diff --git a/libs/resiliency/docs/index.rst b/libs/resiliency/docs/index.rst index 75bbd026e21e..10c47a11e2d9 100644 --- a/libs/resiliency/docs/index.rst +++ b/libs/resiliency/docs/index.rst @@ -31,27 +31,27 @@ by repeating a task multiple times. The following API functions are exposed: -- :cpp:func:`hpx::resiliency::async_replay`: This version of task replay will +- :cpp:func:`hpx::resiliency::experimental::async_replay`: This version of task replay will catch user-defined exceptions and automatically reschedule the task N times - before throwing an :cpp:func:`hpx::resiliency::abort_replay_exception` if no + before throwing an :cpp:func:`hpx::resiliency::experimental::abort_replay_exception` if no task is able to complete execution without an exception. -- :cpp:func:`hpx::resiliency::async_replay_validate`: This version of replay +- :cpp:func:`hpx::resiliency::experimental::async_replay_validate`: This version of replay adds an argument to async replay which receives a user-provided validation function to test the result of the task against. If the task's output is validated, the result is returned. If the output fails the check or an exception is thrown, the task is replayed until no errors are encountered or the number of specified retries has been exceeded. -- :cpp:func:`hpx::resiliency::async_replicate`: This is the most basic +- :cpp:func:`hpx::resiliency::experimental::async_replicate`: This is the most basic implementation of the task replication. The API returns the first result that runs without detecting any errors. -- :cpp:func:`hpx::resiliency::async_replicate_validate`: This API additionally +- :cpp:func:`hpx::resiliency::experimental::async_replicate_validate`: This API additionally takes a validation function which evaluates the return values produced by the threads. The first task to compute a valid result is returned. -- :cpp:func:`hpx::resiliency::async_replicate_vote`: This API adds a vote +- :cpp:func:`hpx::resiliency::experimental::async_replicate_vote`: This API adds a vote function to the basic replicate function. Many hardware or software failures are silent errors which do not interrupt program flow. In order to detect errors of this kind, it is necessary to run the task several times and compare @@ -60,20 +60,20 @@ The following API functions are exposed: consensus function to properly form a consensus. This voting function then returns the "correct"" answer. -- :cpp:func:`hpx::resiliency::async_replicate_vote_validate`: This combines the +- :cpp:func:`hpx::resiliency::experimental::async_replicate_vote_validate`: This combines the features of the previously discussed replicate set. Replicate vote validate allows a user to provide a validation function to filter results. Additionally, as described in replicate vote, the user can provide a "voting function" which returns the consensus formed by the voting logic. -- :cpp:func:`hpx::resiliency::dataflow_replay`: This version of dataflow replay +- :cpp:func:`hpx::resiliency::experimental::dataflow_replay`: This version of dataflow replay will catch user-defined exceptions and automatically reschedules the task N - times before throwing an :cpp:func:`hpx::resiliency::abort_replay_exception` + times before throwing an :cpp:func:`hpx::resiliency::experimental::abort_replay_exception` if no task is able to complete execution without an exception. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready. -- :cpp:func:`hpx::resiliency::dataflow_replay_validate` : This version of replay +- :cpp:func:`hpx::resiliency::experimental::dataflow_replay_validate` : This version of replay adds an argument to dataflow replay which receives a user-provided validation function to test the result of the task against. If the task's output is validated, the result is returned. If the output fails the check or an @@ -82,19 +82,19 @@ The following API functions are exposed: executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready. -- :cpp:func:`hpx::resiliency::dataflow_replicate`: This is the most basic +- :cpp:func:`hpx::resiliency::experimental::dataflow_replicate`: This is the most basic implementation of the task replication. The API returns the first result that runs without detecting any errors. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready. -- :cpp:func:`hpx::resiliency::dataflow_replicate_validate`: This API +- :cpp:func:`hpx::resiliency::experimental::dataflow_replicate_validate`: This API additionally takes a validation function which evaluates the return values produced by the threads. The first task to compute a valid result is returned. Any arguments for the executed task that are futures will cause the task invocation to be delayed until all of those futures have become ready. -- :cpp:func:`hpx::resiliency::dataflow_replicate_vote`: This API adds a vote +- :cpp:func:`hpx::resiliency::experimental::dataflow_replicate_vote`: This API adds a vote function to the basic replicate function. Many hardware or software failures are silent errors which do not interrupt program flow. In order to detect errors of this kind, it is necessary to run the task several times and compare @@ -105,7 +105,7 @@ The following API functions are exposed: futures will cause the task invocation to be delayed until all of those futures have become ready. -- :cpp:func:`hpx::resiliency::dataflow_replicate_vote_validate`: This combines +- :cpp:func:`hpx::resiliency::experimental::dataflow_replicate_vote_validate`: This combines the features of the previously discussed replicate set. Replicate vote validate allows a user to provide a validation function to filter results. Additionally, as described in replicate vote, the user can provide a "voting diff --git a/libs/resiliency/examples/1d_stencil_replay_exception.cpp b/libs/resiliency/examples/1d_stencil_replay_exception.cpp index db08f759ad44..c8b4465f2a4d 100644 --- a/libs/resiliency/examples/1d_stencil_replay_exception.cpp +++ b/libs/resiliency/examples/1d_stencil_replay_exception.cpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include @@ -164,9 +164,9 @@ int hpx_main(hpx::program_options::variables_map& vm) std::vector next_input(subdomains); for (int j = 0; j < subdomains; ++j) { - next_input[j] = hpx::resiliency::dataflow_replay(n, update, - input[(j - 1 + subdomains) % subdomains], input[j], - input[(j + 1) % subdomains]); + next_input[j] = hpx::resiliency::experimental::dataflow_replay( + n, update, input[(j - 1 + subdomains) % subdomains], + input[j], input[(j + 1) % subdomains]); } std::swap(input, next_input); } diff --git a/libs/resiliency/examples/1d_stencil_replay_validate.cpp b/libs/resiliency/examples/1d_stencil_replay_validate.cpp index cf5800c5b9b9..00c14d456040 100644 --- a/libs/resiliency/examples/1d_stencil_replay_validate.cpp +++ b/libs/resiliency/examples/1d_stencil_replay_validate.cpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include @@ -181,10 +181,11 @@ int hpx_main(hpx::program_options::variables_map& vm) std::vector next_input(subdomains); for (int j = 0; j < subdomains; ++j) { - next_input[j] = hpx::resiliency::dataflow_replay_validate(n, - &validate_result, update, - input[(j - 1 + subdomains) % subdomains], input[j], - input[(j + 1) % subdomains]); + next_input[j] = + hpx::resiliency::experimental::dataflow_replay_validate(n, + &validate_result, update, + input[(j - 1 + subdomains) % subdomains], input[j], + input[(j + 1) % subdomains]); } std::swap(input, next_input); } diff --git a/libs/resiliency/examples/async_replay.cpp b/libs/resiliency/examples/async_replay.cpp index e594974708ab..c53459e50c70 100644 --- a/libs/resiliency/examples/async_replay.cpp +++ b/libs/resiliency/examples/async_replay.cpp @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include @@ -36,7 +36,7 @@ bool validate(int result) int no_answer() { - throw hpx::resiliency::abort_replay_exception(); + throw hpx::resiliency::experimental::abort_replay_exception(); } int deep_thought() @@ -60,18 +60,19 @@ int hpx_main(hpx::program_options::variables_map& vm) hpx::util::high_resolution_timer t; // successful replay - hpx::future f = hpx::resiliency::async_replay(sr, &deep_thought); + hpx::future f = + hpx::resiliency::experimental::async_replay(sr, &deep_thought); std::cout << "universal answer: " << f.get() << "\n"; // successful replay validate - f = hpx::resiliency::async_replay_validate( + f = hpx::resiliency::experimental::async_replay_validate( sr, &validate, &universal_answer); std::cout << "universal answer: " << f.get() << "\n"; // unsuccessful replay - f = hpx::resiliency::async_replay(usr, &deep_thought); + f = hpx::resiliency::experimental::async_replay(usr, &deep_thought); try { f.get(); @@ -82,35 +83,36 @@ int hpx_main(hpx::program_options::variables_map& vm) } // unsuccessful replay validate - f = hpx::resiliency::async_replay_validate( + f = hpx::resiliency::experimental::async_replay_validate( usr, &validate, &universal_answer); try { f.get(); } - catch (hpx::resiliency::abort_replay_exception const&) + catch (hpx::resiliency::experimental::abort_replay_exception const&) { std::cout << "no universal answer!\n"; } // aborted replay - f = hpx::resiliency::async_replay(a, &no_answer); + f = hpx::resiliency::experimental::async_replay(a, &no_answer); try { f.get(); } - catch (hpx::resiliency::abort_replay_exception const&) + catch (hpx::resiliency::experimental::abort_replay_exception const&) { std::cout << "aborted universal answer calculation!\n"; } // aborted replay validate - f = hpx::resiliency::async_replay_validate(a, &validate, &no_answer); + f = hpx::resiliency::experimental::async_replay_validate( + a, &validate, &no_answer); try { f.get(); } - catch (hpx::resiliency::abort_replay_exception const&) + catch (hpx::resiliency::experimental::abort_replay_exception const&) { std::cout << "aborted universal answer calculation!\n"; } diff --git a/libs/resiliency/examples/async_replicate.cpp b/libs/resiliency/examples/async_replicate.cpp index 74da4fe906c4..cfebdc10ba34 100644 --- a/libs/resiliency/examples/async_replicate.cpp +++ b/libs/resiliency/examples/async_replicate.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, // LLC (NTESS). -// Copyright (c) 2018 Hartmut Kaiser +// Copyright (c) 2018-2020 Hartmut Kaiser // Copyright (c) 2019 Adrian Serio // Copyright (c) 2019 Nikunj Gupta // @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include #include @@ -35,7 +35,7 @@ bool validate(int result) int no_answer() { - throw hpx::resiliency::abort_replicate_exception(); + throw hpx::resiliency::experimental::abort_replicate_exception(); } int deep_thought() @@ -60,18 +60,18 @@ int hpx_main(hpx::program_options::variables_map& vm) // successful replicate hpx::future f = - hpx::resiliency::async_replicate(sr, &deep_thought); + hpx::resiliency::experimental::async_replicate(sr, &deep_thought); std::cout << "universal answer: " << f.get() << "\n"; // successful replicate_validate - f = hpx::resiliency::async_replicate_validate( + f = hpx::resiliency::experimental::async_replicate_validate( sr, &validate, &universal_answer); std::cout << "universal answer: " << f.get() << "\n"; // unsuccessful replicate - f = hpx::resiliency::async_replicate(usr, &deep_thought); + f = hpx::resiliency::experimental::async_replicate(usr, &deep_thought); try { f.get(); @@ -82,35 +82,36 @@ int hpx_main(hpx::program_options::variables_map& vm) } // unsuccessful replicate_validate - f = hpx::resiliency::async_replicate_validate( + f = hpx::resiliency::experimental::async_replicate_validate( usr, &validate, &universal_answer); try { f.get(); } - catch (hpx::resiliency::abort_replicate_exception const&) + catch (hpx::resiliency::experimental::abort_replicate_exception const&) { std::cout << "no universal answer!\n"; } // aborted replicate - f = hpx::resiliency::async_replicate(a, &no_answer); + f = hpx::resiliency::experimental::async_replicate(a, &no_answer); try { f.get(); } - catch (hpx::resiliency::abort_replicate_exception const&) + catch (hpx::resiliency::experimental::abort_replicate_exception const&) { std::cout << "aborted universal answer calculation!\n"; } // aborted replicate validate - f = hpx::resiliency::async_replicate_validate(a, &validate, &no_answer); + f = hpx::resiliency::experimental::async_replicate_validate( + a, &validate, &no_answer); try { f.get(); } - catch (hpx::resiliency::abort_replicate_exception const&) + catch (hpx::resiliency::experimental::abort_replicate_exception const&) { std::cout << "aborted universal answer calculation!\n"; } diff --git a/libs/resiliency/examples/async_replicate_vote.cpp b/libs/resiliency/examples/async_replicate_vote.cpp index 773c8c7bffb2..4df2489ae141 100644 --- a/libs/resiliency/examples/async_replicate_vote.cpp +++ b/libs/resiliency/examples/async_replicate_vote.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -47,7 +47,8 @@ int hpx_main(hpx::program_options::variables_map& vm) hpx::util::high_resolution_timer t; hpx::future f = - hpx::resiliency::async_replicate_vote(n, &vote, &universal_ans); + hpx::resiliency::experimental::async_replicate_vote( + n, &vote, &universal_ans); std::cout << "Universal ans (maybe true): " << f.get() << std::endl; @@ -59,8 +60,9 @@ int hpx_main(hpx::program_options::variables_map& vm) // Initialize a high resolution timer hpx::util::high_resolution_timer t; - hpx::future f = hpx::resiliency::async_replicate_vote_validate( - n, &vote, &validate, &universal_ans); + hpx::future f = + hpx::resiliency::experimental::async_replicate_vote_validate( + n, &vote, &validate, &universal_ans); std::cout << "Universal ans (true ans): " << f.get() << std::endl; diff --git a/libs/resiliency/examples/dataflow_replicate.cpp b/libs/resiliency/examples/dataflow_replicate.cpp index 3bad3730b11d..827212e48c8f 100644 --- a/libs/resiliency/examples/dataflow_replicate.cpp +++ b/libs/resiliency/examples/dataflow_replicate.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include @@ -57,8 +57,8 @@ int hpx_main(hpx::program_options::variables_map& vm) { // Successful replicate - hpx::future f = - hpx::resiliency::dataflow_replicate(sr, moody_add, 5, 5); + hpx::future f = hpx::resiliency::experimental::dataflow_replicate( + sr, moody_add, 5, 5); try { std::cout << f.get() << std::endl; @@ -73,7 +73,8 @@ int hpx_main(hpx::program_options::variables_map& vm) } // Unsuccessful replicate - f = hpx::resiliency::dataflow_replay(usr, moody_add, 0, 5); + f = hpx::resiliency::experimental::dataflow_replay( + usr, moody_add, 0, 5); try { std::cout << f.get() << std::endl; @@ -88,7 +89,7 @@ int hpx_main(hpx::program_options::variables_map& vm) } // Aborted replicate - f = hpx::resiliency::dataflow_replay(a, bad_add, 10, 5); + f = hpx::resiliency::experimental::dataflow_replay(a, bad_add, 10, 5); try { std::cout << f.get() << std::endl; diff --git a/libs/resiliency/examples/version.cpp b/libs/resiliency/examples/version.cpp index 0ebc6b201662..54c4c4c0e93c 100644 --- a/libs/resiliency/examples/version.cpp +++ b/libs/resiliency/examples/version.cpp @@ -7,13 +7,13 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include #include int main(int argc, char* argv[]) { std::cout << "HPX Resiliency module version: " - << hpx::resiliency::full_version_str() << "\n"; + << hpx::resiliency::experimental::full_version_str() << "\n"; return 0; } diff --git a/libs/resiliency/include/hpx/resiliency/async_replay.hpp b/libs/resiliency/include/hpx/resiliency/async_replay.hpp index 9643d37ce2f2..e28084d4ef0b 100644 --- a/libs/resiliency/include/hpx/resiliency/async_replay.hpp +++ b/libs/resiliency/include/hpx/resiliency/async_replay.hpp @@ -1,6 +1,6 @@ // Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, // LLC (NTESS). -// Copyright (c) 2018-2019 Hartmut Kaiser +// Copyright (c) 2018-2020 Hartmut Kaiser // Copyright (c) 2018-2019 Adrian Serio // Copyright (c) 2019 Nikunj Gupta // @@ -11,6 +11,7 @@ #pragma once #include +#include #include #include @@ -25,7 +26,7 @@ #include #include -namespace hpx { namespace resiliency { +namespace hpx { namespace resiliency { namespace experimental { /////////////////////////////////////////////////////////////////////////// struct HPX_ALWAYS_EXPORT abort_replay_exception : std::exception @@ -164,13 +165,14 @@ namespace hpx { namespace resiliency { } // namespace detail /////////////////////////////////////////////////////////////////////////// - /// Asynchronously launch given function \a f. Verify the result of - /// those invocations using the given predicate \a pred. Repeat launching - /// on error exactly \a n times (except if abort_replay_exception is thrown). + // Asynchronously launch given function \a f. Verify the result of + // those invocations using the given predicate \a pred. Repeat launching + // on error exactly \a n times (except if abort_replay_exception is thrown). template hpx::future< typename hpx::util::detail::invoke_deferred_result::type> - async_replay_validate(std::size_t n, Pred&& pred, F&& f, Ts&&... ts) + tag_invoke( + async_replay_validate_t, std::size_t n, Pred&& pred, F&& f, Ts&&... ts) { using result_type = typename hpx::util::detail::invoke_deferred_result::type; @@ -183,45 +185,20 @@ namespace hpx { namespace resiliency { } /////////////////////////////////////////////////////////////////////////// - /// Asynchronously launch given function \a f. Repeat launching - /// on error exactly \a n times (except if abort_replay_exception is thrown). + // Asynchronously launch given function \a f. Repeat launching + // on error exactly \a n times (except if abort_replay_exception is thrown). template hpx::future< typename hpx::util::detail::invoke_deferred_result::type> - async_replay(std::size_t n, F&& f, Ts&&... ts) + tag_invoke(async_replay_t, std::size_t n, F&& f, Ts&&... ts) { - return async_replay_validate(n, detail::replay_validator{}, - std::forward(f), std::forward(ts)...); - } - - /////////////////////////////////////////////////////////////////////////// - /// Functional version of \a hpx::resiliency::async_replay - namespace functional { + using result_type = + typename hpx::util::detail::invoke_deferred_result::type; - struct async_replay_validate - { - template - auto operator()(std::size_t n, Pred&& pred, F&& f, Ts&&... ts) const - -> decltype(hpx::resiliency::async_replay_validate(n, - std::forward(pred), std::forward(f), - std::forward(ts)...)) - { - return hpx::resiliency::async_replay_validate(n, - std::forward(pred), std::forward(f), - std::forward(ts)...); - } - }; + auto helper = detail::make_async_replay_helper( + detail::replay_validator{}, std::forward(f), + std::forward(ts)...); - struct async_replay - { - template - auto operator()(std::size_t n, F&& f, Ts&&... ts) const - -> decltype(hpx::resiliency::async_replay( - n, std::forward(f), std::forward(ts)...)) - { - return hpx::resiliency::async_replay( - n, std::forward(f), std::forward(ts)...); - } - }; - } // namespace functional -}} // namespace hpx::resiliency + return helper->call(n); + } +}}} // namespace hpx::resiliency::experimental diff --git a/libs/resiliency/include/hpx/resiliency/async_replay_executor.hpp b/libs/resiliency/include/hpx/resiliency/async_replay_executor.hpp new file mode 100644 index 000000000000..a74e9d4211b9 --- /dev/null +++ b/libs/resiliency/include/hpx/resiliency/async_replay_executor.hpp @@ -0,0 +1,197 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018-2020 Hartmut Kaiser +// Copyright (c) 2018-2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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) + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace hpx { namespace resiliency { namespace experimental { + + /////////////////////////////////////////////////////////////////////////// + namespace detail { + + /////////////////////////////////////////////////////////////////////// + template + struct async_replay_executor_helper + : std::enable_shared_from_this< + async_replay_executor_helper> + { + template + async_replay_executor_helper(Pred_&& pred, F_&& f, Tuple_&& tuple) + : pred_(std::forward(pred)) + , f_(std::forward(f)) + , t_(std::forward(tuple)) + { + } + + template + Result invoke(Executor&& exec, hpx::util::index_pack) + { + return hpx::parallel::execution::async_execute( + std::forward(exec), f_, std::get(t_)...); + } + + template + Result call(Executor&& exec, std::size_t n) + { + // launch given function asynchronously + using pack_type = + hpx::util::make_index_pack::value>; + + Result f = invoke(exec, pack_type{}); + + // attach a continuation that will relaunch the task, if + // necessary + auto this_ = this->shared_from_this(); + return f.then(hpx::launch::sync, + [this_ = std::move(this_), + exec = std::forward(exec), + n](Result&& f) mutable { + if (f.has_exception()) + { + // rethrow abort_replay_exception, if caught + auto ex = rethrow_on_abort_replay(f); + + // execute the task again if an error occurred and + // this was not the last attempt + if (n != 0) + { + return this_->call(std::move(exec), n - 1); + } + + // rethrow exception if the number of replays has + // been exhausted + std::rethrow_exception(ex); + } + + auto&& result = f.get(); + + if (!hpx::util::invoke(this_->pred_, result)) + { + // execute the task again if an error occurred and + // this was not the last attempt + if (n != 0) + { + return this_->call(std::move(exec), n - 1); + } + + // throw aborting exception as attempts were + // exhausted + throw abort_replay_exception(); + } + + if (n != 0) + { + // return result + return hpx::make_ready_future(std::move(result)); + } + + // throw aborting exception as attempts were + // exhausted + throw abort_replay_exception(); + }); + } + + Pred pred_; + F f_; + Tuple t_; + }; + + template + std::shared_ptr::type, typename std::decay::type, + std::tuple::type...>>> + make_async_replay_executor_helper(Pred&& pred, F&& f, Ts&&... ts) + { + using tuple_type = std::tuple::type...>; + + using return_type = async_replay_executor_helper::type, typename std::decay::type, + std::tuple::type...>>; + + return std::make_shared(std::forward(pred), + std::forward(f), std::make_tuple(std::forward(ts)...)); + } + } // namespace detail + + /////////////////////////////////////////////////////////////////////////// + // Asynchronously launch given function \a f. Verify the result of + // those invocations using the given predicate \a pred. Repeat launching + // on error exactly \a n times (except if abort_replay_exception is thrown). + // clang-format off + template ::value || + hpx::traits::is_two_way_executor::value || + hpx::traits::is_threads_executor::value + )> + // clang-format on + decltype(auto) tag_invoke(async_replay_validate_t, Executor&& exec, + std::size_t n, Pred&& pred, F&& f, Ts&&... ts) + { + using result_type = + typename hpx::util::detail::invoke_deferred_result::type; + + using future_type = + typename hpx::parallel::execution::executor_future::type; + + auto helper = detail::make_async_replay_executor_helper( + std::forward(pred), std::forward(f), + std::forward(ts)...); + + return helper->call(std::forward(exec), n); + } + + /////////////////////////////////////////////////////////////////////////// + // Asynchronously launch given function \a f. Repeat launching + // on error exactly \a n times (except if abort_replay_exception is thrown). + // clang-format off + template ::value || + hpx::traits::is_two_way_executor::value || + hpx::traits::is_threads_executor::value + )> + // clang-format on + decltype(auto) tag_invoke( + async_replay_t, Executor&& exec, std::size_t n, F&& f, Ts&&... ts) + { + using result_type = + typename hpx::util::detail::invoke_deferred_result::type; + + using future_type = + typename hpx::parallel::execution::executor_future::type; + + auto helper = detail::make_async_replay_executor_helper( + detail::replay_validator{}, std::forward(f), + std::forward(ts)...); + + return helper->call(std::forward(exec), n); + } +}}} // namespace hpx::resiliency::experimental diff --git a/libs/resiliency/include/hpx/resiliency/async_replicate.hpp b/libs/resiliency/include/hpx/resiliency/async_replicate.hpp index cf013234821c..3a4d4615b341 100644 --- a/libs/resiliency/include/hpx/resiliency/async_replicate.hpp +++ b/libs/resiliency/include/hpx/resiliency/async_replicate.hpp @@ -1,6 +1,6 @@ // Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, // LLC (NTESS). -// Copyright (c) 2018-2019 Hartmut Kaiser +// Copyright (c) 2018-2020 Hartmut Kaiser // Copyright (c) 2018-2019 Adrian Serio // Copyright (c) 2019 Nikunj Gupta // @@ -11,6 +11,7 @@ #pragma once #include +#include #include #include @@ -21,7 +22,7 @@ #include #include -namespace hpx { namespace resiliency { +namespace hpx { namespace resiliency { namespace experimental { /////////////////////////////////////////////////////////////////////////// struct HPX_ALWAYS_EXPORT abort_replicate_exception : std::exception @@ -69,177 +70,133 @@ namespace hpx { namespace resiliency { } return ex; } - } // namespace detail - /////////////////////////////////////////////////////////////////////////// - /// Asynchronously launch given function \a f exactly \a n times. Verify - /// the result of those invocations using the given predicate \a pred. - /// Run all the valid results against a user provided voting function. - /// Return the valid output. - template - hpx::future< - typename hpx::util::detail::invoke_deferred_result::type> - async_replicate_vote_validate( - std::size_t n, Vote&& vote, Pred&& pred, F&& f, Ts&&... ts) - { - using result_type = - typename hpx::util::detail::invoke_deferred_result::type; + /////////////////////////////////////////////////////////////////////// + template + hpx::future< + typename hpx::util::detail::invoke_deferred_result::type> + async_replicate_vote_validate( + std::size_t n, Vote&& vote, Pred&& pred, F&& f, Ts&&... ts) + { + using result_type = + typename hpx::util::detail::invoke_deferred_result::type; - // launch given function n times - std::vector> results; - results.reserve(n); + // launch given function n times + std::vector> results; + results.reserve(n); - for (std::size_t i = 0; i != n; ++i) - { - results.emplace_back(hpx::async(f, ts...)); - } + for (std::size_t i = 0; i != n; ++i) + { + results.emplace_back(hpx::async(f, ts...)); + } - // wait for all threads to finish executing and return the first result - // that passes the predicate, properly handle exceptions - return hpx::dataflow( - hpx::launch::sync, // do not schedule new thread for the lambda - [pred = std::forward(pred), vote = std::forward(vote), - n](std::vector>&& results) mutable - -> result_type { - // Store all valid results - std::vector valid_results; - valid_results.reserve(n); - - std::exception_ptr ex; - - for (auto&& f : std::move(results)) - { - if (f.has_exception()) + // wait for all threads to finish executing and return the first result + // that passes the predicate, properly handle exceptions + return hpx::dataflow( + hpx::launch:: + sync, // do not schedule new thread for the lambda + [pred = std::forward(pred), + vote = std::forward(vote), + n](std::vector>&& results) mutable + -> result_type { + // Store all valid results + std::vector valid_results; + valid_results.reserve(n); + + std::exception_ptr ex; + + for (auto&& f : std::move(results)) { - // rethrow abort_replicate_exception, if caught - ex = detail::rethrow_on_abort_replicate(f); - } - else - { - auto&& result = f.get(); - if (hpx::util::invoke(pred, result)) + if (f.has_exception()) + { + // rethrow abort_replicate_exception, if caught + ex = detail::rethrow_on_abort_replicate(f); + } + else { - valid_results.emplace_back(std::move(result)); + auto&& result = f.get(); + if (hpx::util::invoke(pred, result)) + { + valid_results.emplace_back(std::move(result)); + } } } - } - if (!valid_results.empty()) - { - return hpx::util::invoke( - std::forward(vote), std::move(valid_results)); - } + if (!valid_results.empty()) + { + return hpx::util::invoke( + std::forward(vote), std::move(valid_results)); + } + + if (bool(ex)) + std::rethrow_exception(ex); - if (bool(ex)) - std::rethrow_exception(ex); + // throw aborting exception no correct results ere produced + throw abort_replicate_exception{}; + }, + std::move(results)); + } + } // namespace detail - // throw aborting exception no correct results ere produced - throw abort_replicate_exception{}; - }, - std::move(results)); + /////////////////////////////////////////////////////////////////////////// + // Asynchronously launch given function \a f exactly \a n times. Verify + // the result of those invocations using the given predicate \a pred. + // Run all the valid results against a user provided voting function. + // Return the valid output. + template + hpx::future< + typename hpx::util::detail::invoke_deferred_result::type> + tag_invoke(async_replicate_vote_validate_t, std::size_t n, Vote&& vote, + Pred&& pred, F&& f, Ts&&... ts) + { + return detail::async_replicate_vote_validate(n, + std::forward(vote), std::forward(pred), + std::forward(f), std::forward(ts)...); } /////////////////////////////////////////////////////////////////////////// - /// Asynchronously launch given function \a f exactly \a n times. Verify - /// the result of those invocations using the given predicate \a pred. Run - /// all the valid results against a user provided voting function. - /// Return the valid output. + // Asynchronously launch given function \a f exactly \a n times. Verify + // the result of those invocations using the given predicate \a pred. Run + // all the valid results against a user provided voting function. + // Return the valid output. template hpx::future< typename hpx::util::detail::invoke_deferred_result::type> - async_replicate_vote(std::size_t n, Vote&& vote, F&& f, Ts&&... ts) + tag_invoke( + async_replicate_vote_t, std::size_t n, Vote&& vote, F&& f, Ts&&... ts) { - return async_replicate_vote_validate(n, std::forward(vote), - detail::replicate_validator{}, std::forward(f), - std::forward(ts)...); + return detail::async_replicate_vote_validate(n, + std::forward(vote), detail::replicate_validator{}, + std::forward(f), std::forward(ts)...); } /////////////////////////////////////////////////////////////////////////// - /// Asynchronously launch given function \a f exactly \a n times. Verify - /// the result of those invocations using the given predicate \a pred. - /// Return the first valid result. + // Asynchronously launch given function \a f exactly \a n times. Verify + // the result of those invocations using the given predicate \a pred. + // Return the first valid result. template hpx::future< typename hpx::util::detail::invoke_deferred_result::type> - async_replicate_validate(std::size_t n, Pred&& pred, F&& f, Ts&&... ts) + tag_invoke(async_replicate_validate_t, std::size_t n, Pred&& pred, F&& f, + Ts&&... ts) { - return async_replicate_vote_validate(n, detail::replicate_voter{}, - std::forward(pred), std::forward(f), - std::forward(ts)...); + return detail::async_replicate_vote_validate(n, + detail::replicate_voter{}, std::forward(pred), + std::forward(f), std::forward(ts)...); } /////////////////////////////////////////////////////////////////////////// - /// Asynchronously launch given function \a f exactly \a n times. Verify - /// the result of those invocations by checking for exception. - /// Return the first valid result. + // Asynchronously launch given function \a f exactly \a n times. Verify + // the result of those invocations by checking for exception. + // Return the first valid result. template hpx::future< typename hpx::util::detail::invoke_deferred_result::type> - async_replicate(std::size_t n, F&& f, Ts&&... ts) + tag_invoke(async_replicate_t, std::size_t n, F&& f, Ts&&... ts) { - return async_replicate_vote_validate(n, detail::replicate_voter{}, - detail::replicate_validator{}, std::forward(f), - std::forward(ts)...); + return detail::async_replicate_vote_validate(n, + detail::replicate_voter{}, detail::replicate_validator{}, + std::forward(f), std::forward(ts)...); } - - /////////////////////////////////////////////////////////////////////////// - /// Functional version of \a hpx::resiliency::async_replicate_validate and - /// \a hpx::resiliency::async_replicate - namespace functional { - - struct async_replicate_vote_validate - { - template - auto operator()(std::size_t n, Vote&& vote, Pred&& pred, F&& f, - Ts&&... ts) const - -> decltype(hpx::resiliency::async_replicate_vote_validate(n, - std::forward(vote), std::forward(pred), - std::forward(f), std::forward(ts)...)) - { - return hpx::resiliency::async_replicate_vote_validate(n, - std::forward(vote), std::forward(pred), - std::forward(f), std::forward(ts)...); - } - }; - - struct async_replicate_vote - { - template - auto operator()(std::size_t n, Vote&& vote, F&& f, Ts&&... ts) const - -> decltype(hpx::resiliency::async_replicate_vote(n, - std::forward(vote), std::forward(f), - std::forward(ts)...)) - { - return hpx::resiliency::async_replicate_vote(n, - std::forward(vote), std::forward(f), - std::forward(ts)...); - } - }; - - struct async_replicate_validate - { - template - auto operator()(std::size_t n, Pred&& pred, F&& f, Ts&&... ts) const - -> decltype(hpx::resiliency::async_replicate_validate(n, - std::forward(pred), std::forward(f), - std::forward(ts)...)) - { - return hpx::resiliency::async_replicate_validate(n, - std::forward(pred), std::forward(f), - std::forward(ts)...); - } - }; - - struct async_replicate - { - template - auto operator()(std::size_t n, F&& f, Ts&&... ts) const - -> decltype(hpx::resiliency::async_replicate( - n, std::forward(f), std::forward(ts)...)) - { - return hpx::resiliency::async_replicate( - n, std::forward(f), std::forward(ts)...); - } - }; - } // namespace functional -}} // namespace hpx::resiliency +}}} // namespace hpx::resiliency::experimental diff --git a/libs/resiliency/include/hpx/resiliency/async_replicate_executor.hpp b/libs/resiliency/include/hpx/resiliency/async_replicate_executor.hpp new file mode 100644 index 000000000000..bebbc298ec64 --- /dev/null +++ b/libs/resiliency/include/hpx/resiliency/async_replicate_executor.hpp @@ -0,0 +1,195 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018-2020 Hartmut Kaiser +// Copyright (c) 2018-2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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) + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace hpx { namespace resiliency { namespace experimental { + namespace detail { + + /////////////////////////////////////////////////////////////////////// + template + typename hpx::traits::executor_future::type>::type + async_replicate_vote_validate_executor(Executor&& exec, std::size_t n, + Vote&& vote, Pred&& pred, F&& f, Ts&&... ts) + { + using result_type = + typename hpx::util::detail::invoke_deferred_result::type; + + using future_type = typename hpx::traits::executor_future::type; + + // launch given function n times + auto func = [f = std::forward(f), + t = hpx::util::make_tuple(std::forward(ts)...)]( + std::size_t) -> result_type { + // ignore argument (invocation count of bulk_execute) + return hpx::util::invoke_fused(f, t); + }; + + std::vector results = + hpx::parallel::execution::bulk_async_execute( + std::forward(exec), std::move(func), n); + + // wait for all threads to finish executing and return the first + // result that passes the predicate, properly handle exceptions + // do not schedule new thread for the lambda + return hpx::dataflow( + hpx::launch::sync, + [pred = std::forward(pred), + vote = std::forward(vote), n]( + std::vector&& results) mutable -> result_type { + // Store all valid results + std::vector valid_results; + valid_results.reserve(n); + + std::exception_ptr ex; + + for (auto&& f : std::move(results)) + { + if (f.has_exception()) + { + // rethrow abort_replicate_exception, if caught + ex = detail::rethrow_on_abort_replicate(f); + } + else + { + auto&& result = f.get(); + if (hpx::util::invoke(pred, result)) + { + valid_results.emplace_back(std::move(result)); + } + } + } + + if (!valid_results.empty()) + { + return hpx::util::invoke( + std::forward(vote), std::move(valid_results)); + } + + if (bool(ex)) + { + std::rethrow_exception(ex); + } + + // throw aborting exception no correct results ere produced + throw abort_replicate_exception{}; + }, + std::move(results)); + } + } // namespace detail + + /////////////////////////////////////////////////////////////////////////// + // Asynchronously launch given function \a f exactly \a n times. Verify + // the result of those invocations using the given predicate \a pred. + // Run all the valid results against a user provided voting function. + // Return the valid output. + // clang-format off + template ::value || + hpx::traits::is_two_way_executor::value || + hpx::traits::is_threads_executor::value + )> + // clang-format on + decltype(auto) tag_invoke(async_replicate_vote_validate_t, Executor&& exec, + std::size_t n, Vote&& vote, Pred&& pred, F&& f, Ts&&... ts) + { + return detail::async_replicate_vote_validate_executor( + std::forward(exec), n, std::forward(vote), + std::forward(pred), std::forward(f), + std::forward(ts)...); + } + + /////////////////////////////////////////////////////////////////////////// + // Asynchronously launch given function \a f exactly \a n times. Verify + // the result of those invocations using the given predicate \a pred. Run + // all the valid results against a user provided voting function. + // Return the valid output. + // clang-format off + template ::value || + hpx::traits::is_two_way_executor::value || + hpx::traits::is_threads_executor::value + )> + // clang-format on + decltype(auto) tag_invoke(async_replicate_vote_t, Executor&& exec, + std::size_t n, Vote&& vote, F&& f, Ts&&... ts) + { + return detail::async_replicate_vote_validate_executor( + std::forward(exec), n, std::forward(vote), + detail::replicate_validator{}, std::forward(f), + std::forward(ts)...); + } + + /////////////////////////////////////////////////////////////////////////// + // Asynchronously launch given function \a f exactly \a n times. Verify + // the result of those invocations using the given predicate \a pred. + // Return the first valid result. + // clang-format off + template ::value || + hpx::traits::is_two_way_executor::value || + hpx::traits::is_threads_executor::value + )> + // clang-format on + decltype(auto) tag_invoke(async_replicate_validate_t, Executor&& exec, + std::size_t n, Pred&& pred, F&& f, Ts&&... ts) + { + return detail::async_replicate_vote_validate_executor( + std::forward(exec), n, detail::replicate_voter{}, + std::forward(pred), std::forward(f), + std::forward(ts)...); + } + + /////////////////////////////////////////////////////////////////////////// + // Asynchronously launch given function \a f exactly \a n times. Verify + // the result of those invocations by checking for exception. + // Return the first valid result. + // clang-format off + template ::value || + hpx::traits::is_two_way_executor::value || + hpx::traits::is_threads_executor::value + )> + // clang-format on + decltype(auto) tag_invoke( + async_replicate_t, Executor&& exec, std::size_t n, F&& f, Ts&&... ts) + { + return detail::async_replicate_vote_validate_executor( + std::forward(exec), n, detail::replicate_voter{}, + detail::replicate_validator{}, std::forward(f), + std::forward(ts)...); + } +}}} // namespace hpx::resiliency::experimental diff --git a/libs/resiliency/include/hpx/resiliency/dataflow_replay.hpp b/libs/resiliency/include/hpx/resiliency/dataflow_replay.hpp deleted file mode 100644 index ed0f45238eb8..000000000000 --- a/libs/resiliency/include/hpx/resiliency/dataflow_replay.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, -// LLC (NTESS). -// Copyright (c) 2018-2019 Hartmut Kaiser -// Copyright (c) 2018-2019 Adrian Serio -// -// 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) - -#pragma once - -#include -#include - -#include -#include - -#include -#include - -namespace hpx { namespace resiliency { - - /// Asynchronously launch given function \a f. Verify the result of - /// those invocations using the given predicate \a pred. Repeat launching - /// on error exactly \a n times. - /// - /// Delay the invocation of \a f if any of the arguments to \a f are - /// futures. - template - hpx::future< - typename hpx::util::detail::invoke_deferred_result::type> - dataflow_replay_validate(std::size_t n, Pred&& pred, F&& f, Ts&&... ts) - { - return hpx::dataflow( - hpx::resiliency::functional::async_replay_validate{}, n, - std::forward(pred), std::forward(f), - std::forward(ts)...); - } - - /// Asynchronously launch given function \a f. Repeat launching on error - /// exactly \a n times. - /// - /// Delay the invocation of \a f if any of the arguments to \a f are - /// futures. - template - hpx::future< - typename hpx::util::detail::invoke_deferred_result::type> - dataflow_replay(std::size_t n, F&& f, Ts&&... ts) - { - return hpx::dataflow(hpx::resiliency::functional::async_replay{}, n, - std::forward(f), std::forward(ts)...); - } -}} // namespace hpx::resiliency diff --git a/libs/resiliency/include/hpx/resiliency/dataflow_replicate.hpp b/libs/resiliency/include/hpx/resiliency/dataflow_replicate.hpp deleted file mode 100644 index 1e184faf159a..000000000000 --- a/libs/resiliency/include/hpx/resiliency/dataflow_replicate.hpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, -// LLC (NTESS). -// Copyright (c) 2018-2019 Hartmut Kaiser -// Copyright (c) 2018-2019 Adrian Serio -// Copyright (c) 2019 Nikunj Gupta -// -// 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) - -#pragma once - -#include -#include - -#include -#include - -#include -#include - -namespace hpx { namespace resiliency { - - /// Launch given function \a f exactly \a n times. Run all the valid - /// results against a user provided voting function. - /// Return the valid output. - /// - /// Delay the invocation of \a f if any of the arguments to \a f are - /// futures. - template - hpx::future< - typename hpx::util::detail::invoke_deferred_result::type> - dataflow_replicate_vote_validate( - std::size_t n, Vote&& vote, Pred&& pred, F&& f, Ts&&... ts) - { - return hpx::dataflow( - hpx::resiliency::functional::async_replicate_vote_validate{}, n, - std::forward(vote), std::forward(pred), - std::forward(f), std::forward(ts)...); - } - - /// Launch given function \a f exactly \a n times. Run all the valid - /// results against a user provided voting function. - /// Return the valid output. - /// - /// Delay the invocation of \a f if any of the arguments to \a f are - /// futures. - template - hpx::future< - typename hpx::util::detail::invoke_deferred_result::type> - dataflow_replicate_vote(std::size_t n, Vote&& vote, F&& f, Ts&&... ts) - { - return hpx::dataflow( - hpx::resiliency::functional::async_replicate_vote{}, n, - std::forward(vote), std::forward(f), - std::forward(ts)...); - } - - /// Launch given function \a f exactly \a n times. Verify the result of - /// those invocations using the given predicate \a pred. Return the first - /// valid result. - /// - /// Delay the invocation of \a f if any of the arguments to \a f are - /// futures. - template - hpx::future< - typename hpx::util::detail::invoke_deferred_result::type> - dataflow_replicate_validate(std::size_t n, Pred&& pred, F&& f, Ts&&... ts) - { - return hpx::dataflow( - hpx::resiliency::functional::async_replicate_validate{}, n, - std::forward(pred), std::forward(f), - std::forward(ts)...); - } - - /// Launch given function \a f exactly \a n times. Return the first - /// valid result. - /// - /// Delay the invocation of \a f if any of the arguments to \a f are - /// futures. - template - hpx::future< - typename hpx::util::detail::invoke_deferred_result::type> - dataflow_replicate(std::size_t n, F&& f, Ts&&... ts) - { - return hpx::dataflow(hpx::resiliency::functional::async_replicate{}, n, - std::forward(f), std::forward(ts)...); - } -}} // namespace hpx::resiliency diff --git a/libs/resiliency/include/hpx/resiliency/resiliency.hpp b/libs/resiliency/include/hpx/resiliency/resiliency.hpp index 6c53a2e4fe90..9fad9d5d8ecf 100644 --- a/libs/resiliency/include/hpx/resiliency/resiliency.hpp +++ b/libs/resiliency/include/hpx/resiliency/resiliency.hpp @@ -1,6 +1,6 @@ // Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, // LLC (NTESS). -// Copyright (c) 2018-2019 Hartmut Kaiser +// Copyright (c) 2018-2020 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -8,9 +8,4 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include diff --git a/libs/resiliency/include/hpx/resiliency/resiliency_cpos.hpp b/libs/resiliency/include/hpx/resiliency/resiliency_cpos.hpp new file mode 100644 index 000000000000..90f842126611 --- /dev/null +++ b/libs/resiliency/include/hpx/resiliency/resiliency_cpos.hpp @@ -0,0 +1,166 @@ +// Copyright (c) 2018-2020 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) + +#pragma once + +#include +#include +#include + +#include + +namespace hpx { namespace resiliency { namespace experimental { + + /////////////////////////////////////////////////////////////////////////// + // helper base class implementing the deferred tag_invoke logic for CPOs + template + struct tag_deferred : hpx::functional::tag + { + // force unwrapping of the inner future on return + template + friend HPX_FORCEINLINE auto tag_invoke(Tag, Args&&... args) -> + typename hpx::functional::tag_invoke_result::type + { + return hpx::dataflow(BaseTag{}, std::forward(args)...); + } + }; + + /////////////////////////////////////////////////////////////////////////// + // Replay customization points + + /// Customization point for asynchronously launching the given function \a f. + /// repeatedly. Verify the result of those invocations using the given + /// predicate \a pred. + /// Repeat launching on error exactly \a n times (except if + /// abort_replay_exception is thrown). + HPX_INLINE_CONSTEXPR_VARIABLE struct async_replay_validate_t final + : hpx::functional::tag + { + } async_replay_validate; + + /// Customization point for asynchronously launching given function \a f + /// repeatedly. Repeat launching on error exactly \a n times (except if + /// abort_replay_exception is thrown). + HPX_INLINE_CONSTEXPR_VARIABLE struct async_replay_t final + : hpx::functional::tag + { + } async_replay; + + /// Customization point for asynchronously launching the given function \a f. + /// repeatedly. Verify the result of those invocations using the given + /// predicate \a pred. + /// Repeat launching on error exactly \a n times. + /// + /// Delay the invocation of \a f if any of the arguments to \a f are + /// futures. + HPX_INLINE_CONSTEXPR_VARIABLE struct dataflow_replay_validate_t final + : tag_deferred + { + } dataflow_replay_validate; + + /// Customization point for asynchronously launching the given function \a f. + /// repeatedly. + /// Repeat launching on error exactly \a n times. + /// + /// Delay the invocation of \a f if any of the arguments to \a f are + /// futures. + HPX_INLINE_CONSTEXPR_VARIABLE struct dataflow_replay_t final + : tag_deferred + { + } dataflow_replay; + + /////////////////////////////////////////////////////////////////////////// + // Replicate customization points + + /// Customization point for asynchronously launching the given function \a f + /// exactly \a n times concurrently. Verify the result of those invocations + /// using the given predicate \a pred. + /// Run all the valid results against a user provided voting function. + /// Return the valid output. + HPX_INLINE_CONSTEXPR_VARIABLE struct async_replicate_vote_validate_t final + : hpx::functional::tag + { + } async_replicate_vote_validate; + + /////////////////////////////////////////////////////////////////////////// + /// Customization point for asynchronously launching the given function \a f + /// exactly \a n times concurrently. Verify the result of those invocations + /// using the given predicate \a pred. + /// Run all the valid results against a user provided voting function. + /// Return the valid output. + HPX_INLINE_CONSTEXPR_VARIABLE struct async_replicate_vote_t final + : hpx::functional::tag + { + } async_replicate_vote; + + /////////////////////////////////////////////////////////////////////////// + /// Customization point for asynchronously launching the given function \a f + /// exactly \a n times concurrently. Verify the result of those invocations + /// using the given predicate \a pred. + /// Return the first valid result. + HPX_INLINE_CONSTEXPR_VARIABLE struct async_replicate_validate_t final + : hpx::functional::tag + { + } async_replicate_validate; + + /////////////////////////////////////////////////////////////////////////// + /// Customization point for asynchronously launching the given function \a f + /// exactly \a n times concurrently. Verify the result of those invocations + /// by checking for exception. + /// Return the first valid result. + HPX_INLINE_CONSTEXPR_VARIABLE struct async_replicate_t final + : hpx::functional::tag + { + } async_replicate; + + /// Customization point for asynchronously launching the given function \a f + /// exactly \a n times concurrently. Run all the valid results against a + /// user provided voting function. + /// Return the valid output. + /// + /// Delay the invocation of \a f if any of the arguments to \a f are + /// futures. + HPX_INLINE_CONSTEXPR_VARIABLE struct dataflow_replicate_vote_validate_t + final + : tag_deferred + { + } dataflow_replicate_vote_validate; + + /// Customization point for asynchronously launching the given function \a f + /// exactly \a n times concurrently. Run all the valid results against a + /// user provided voting function. + /// Return the valid output. + /// + /// Delay the invocation of \a f if any of the arguments to \a f are + /// futures. + HPX_INLINE_CONSTEXPR_VARIABLE struct dataflow_replicate_vote_t final + : tag_deferred + { + } dataflow_replicate_vote; + + /// Customization point for asynchronously launching the given function \a f + /// exactly \a n times concurrently. Verify the result of those invocations + /// using the given predicate \a pred. Return the first valid result. + /// + /// Delay the invocation of \a f if any of the arguments to \a f are + /// futures. + HPX_INLINE_CONSTEXPR_VARIABLE struct dataflow_replicate_validate_t final + : tag_deferred + { + } dataflow_replicate_validate; + + /// Customization point for asynchronously launching the given function \a f + /// exactly \a n times concurrently. Return the first valid result. + /// + /// Delay the invocation of \a f if any of the arguments to \a f are + /// futures. + HPX_INLINE_CONSTEXPR_VARIABLE struct dataflow_replicate_t final + : tag_deferred + { + } dataflow_replicate; +}}} // namespace hpx::resiliency::experimental diff --git a/libs/resiliency/include/hpx/resiliency/version.hpp b/libs/resiliency/include/hpx/resiliency/version.hpp index 70cb618b149e..ddc21281ac39 100644 --- a/libs/resiliency/include/hpx/resiliency/version.hpp +++ b/libs/resiliency/include/hpx/resiliency/version.hpp @@ -1,6 +1,6 @@ // Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, // LLC (NTESS). -// Copyright (c) 2018-2019 Hartmut Kaiser +// Copyright (c) 2018-2020 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -30,7 +30,7 @@ #define HPX_RESILIENCY_VERSION_DATE 20190823 -namespace hpx { namespace resiliency { +namespace hpx { namespace resiliency { namespace experimental { // return version of this library HPX_EXPORT unsigned int major_version(); @@ -39,4 +39,4 @@ namespace hpx { namespace resiliency { HPX_EXPORT unsigned long full_version(); HPX_EXPORT std::string full_version_str(); -}} // namespace hpx::resiliency +}}} // namespace hpx::resiliency::experimental diff --git a/libs/resiliency/src/resiliency.cpp b/libs/resiliency/src/resiliency.cpp index 08a66a7a3b80..d449106a70ca 100644 --- a/libs/resiliency/src/resiliency.cpp +++ b/libs/resiliency/src/resiliency.cpp @@ -11,7 +11,7 @@ #include -namespace hpx { namespace resiliency { +namespace hpx { namespace resiliency { namespace experimental { unsigned int major_version() { @@ -39,4 +39,4 @@ namespace hpx { namespace resiliency { std::to_string(HPX_RESILIENCY_VERSION_MINOR) + "." + std::to_string(HPX_RESILIENCY_VERSION_SUBMINOR); } -}} // namespace hpx::resiliency +}}} // namespace hpx::resiliency::experimental diff --git a/libs/resiliency/tests/performance/replay/1d_stencil_checksum.cpp b/libs/resiliency/tests/performance/replay/1d_stencil_checksum.cpp index abf3d37c55f1..d4a0641ec372 100644 --- a/libs/resiliency/tests/performance/replay/1d_stencil_checksum.cpp +++ b/libs/resiliency/tests/performance/replay/1d_stencil_checksum.cpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include @@ -237,7 +237,7 @@ struct stepper std::uint64_t nd, std::uint64_t n_value, double error, hpx::lcos::local::sliding_semaphore& sem) { - using hpx::resiliency::dataflow_replay_validate; + using hpx::resiliency::experimental::dataflow_replay_validate; using hpx::util::unwrapping; // U[t][i] is the state of position i at time t. @@ -264,9 +264,12 @@ struct stepper for (std::size_t i = 0; i != subdomains; ++i) { - next[i] = dataflow_replay_validate(n_value, validate_result, Op, - sti, error, current[(i - 1 + subdomains) % subdomains], - current[i], current[(i + 1) % subdomains]); + // explicitly unwrap future + hpx::future f = + dataflow_replay_validate(n_value, validate_result, Op, sti, + error, current[(i - 1 + subdomains) % subdomains], + current[i], current[(i + 1) % subdomains]); + next[i] = std::move(f); } // every nd time steps, attach additional continuation which will diff --git a/libs/resiliency/tests/performance/replay/1d_stencil_replay.cpp b/libs/resiliency/tests/performance/replay/1d_stencil_replay.cpp index d3b4b48ac128..04a0f5670fb2 100644 --- a/libs/resiliency/tests/performance/replay/1d_stencil_replay.cpp +++ b/libs/resiliency/tests/performance/replay/1d_stencil_replay.cpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include @@ -194,7 +194,7 @@ struct stepper std::uint64_t nd, std::uint64_t n_value, double error, hpx::lcos::local::sliding_semaphore& sem) { - using hpx::resiliency::dataflow_replay; + using hpx::resiliency::experimental::dataflow_replay; using hpx::util::unwrapping; // U[t][i] is the state of position i at time t. @@ -221,9 +221,11 @@ struct stepper for (std::size_t i = 0; i != subdomains; ++i) { - next[i] = dataflow_replay(n_value, Op, sti, error, - current[(i - 1 + subdomains) % subdomains], current[i], - current[(i + 1) % subdomains]); + // explicitly unwrap future + hpx::future f = dataflow_replay(n_value, Op, + sti, error, current[(i - 1 + subdomains) % subdomains], + current[i], current[(i + 1) % subdomains]); + next[i] = std::move(f); } // every nd time steps, attach additional continuation which will diff --git a/libs/resiliency/tests/performance/replay/async_replay.cpp b/libs/resiliency/tests/performance/replay/async_replay.cpp index 5f7d86165caa..fa3b5da95cde 100644 --- a/libs/resiliency/tests/performance/replay/async_replay.cpp +++ b/libs/resiliency/tests/performance/replay/async_replay.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -90,7 +90,7 @@ int hpx_main(hpx::program_options::variables_map& vm) for (int i = 0; i < num_iterations; ++i) { - hpx::future f = hpx::resiliency::async_replay( + hpx::future f = hpx::resiliency::experimental::async_replay( n, &universal_ans, delay * 1000, error); vect.push_back(std::move(f)); } @@ -108,7 +108,7 @@ int hpx_main(hpx::program_options::variables_map& vm) "past the injected error levels" << std::endl; } - catch (hpx::resiliency::abort_replay_exception const&) + catch (hpx::resiliency::experimental::abort_replay_exception const&) { std::cout << "Number of repeat launches were not enough to get " "past the injected error levels" diff --git a/libs/resiliency/tests/performance/replay/async_replay_validate.cpp b/libs/resiliency/tests/performance/replay/async_replay_validate.cpp index 801e7f292f1a..daf33726c795 100644 --- a/libs/resiliency/tests/performance/replay/async_replay_validate.cpp +++ b/libs/resiliency/tests/performance/replay/async_replay_validate.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -93,8 +93,9 @@ int hpx_main(hpx::program_options::variables_map& vm) for (int i = 0; i < num_iterations; ++i) { - hpx::future f = hpx::resiliency::async_replay_validate( - n, &validate, &universal_ans, delay * 1000, error); + hpx::future f = + hpx::resiliency::experimental::async_replay_validate( + n, &validate, &universal_ans, delay * 1000, error); vect.push_back(std::move(f)); } @@ -111,7 +112,7 @@ int hpx_main(hpx::program_options::variables_map& vm) "past the injected error levels" << std::endl; } - catch (hpx::resiliency::abort_replay_exception const&) + catch (hpx::resiliency::experimental::abort_replay_exception const&) { std::cout << "Number of repeat launches were not enough to get " "past the injected error levels" diff --git a/libs/resiliency/tests/performance/replay/dataflow_replay.cpp b/libs/resiliency/tests/performance/replay/dataflow_replay.cpp index 3352849f39f1..cfadcc233a47 100644 --- a/libs/resiliency/tests/performance/replay/dataflow_replay.cpp +++ b/libs/resiliency/tests/performance/replay/dataflow_replay.cpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include @@ -239,7 +239,7 @@ struct stepper std::uint64_t n_value, double error, hpx::lcos::local::sliding_semaphore& sem) { - using hpx::resiliency::dataflow_replay; + using hpx::resiliency::experimental::dataflow_replay; using hpx::util::unwrapping; // U[t][i] is the state of position i at time t. diff --git a/libs/resiliency/tests/performance/replay/dataflow_replay_validate.cpp b/libs/resiliency/tests/performance/replay/dataflow_replay_validate.cpp index 662804c7b65c..df2e8c328838 100644 --- a/libs/resiliency/tests/performance/replay/dataflow_replay_validate.cpp +++ b/libs/resiliency/tests/performance/replay/dataflow_replay_validate.cpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include @@ -231,7 +231,7 @@ struct stepper std::uint64_t n_value, double error, hpx::lcos::local::sliding_semaphore& sem) { - using hpx::resiliency::dataflow_replay_validate; + using hpx::resiliency::experimental::dataflow_replay_validate; using hpx::util::unwrapping; // U[t][i] is the state of position i at time t. @@ -258,9 +258,12 @@ struct stepper for (std::size_t i = 0; i != subdomains; ++i) { - next[i] = dataflow_replay_validate(n_value, validate_result, Op, - error, current[(i - 1 + subdomains) % subdomains], - current[i], current[(i + 1) % subdomains]); + // explicitly unwrap future + hpx::future f = + dataflow_replay_validate(n_value, validate_result, Op, + error, current[(i - 1 + subdomains) % subdomains], + current[i], current[(i + 1) % subdomains]); + next[i] = std::move(f); } // every nd time steps, attach additional continuation which will diff --git a/libs/resiliency/tests/performance/replay/pure_async_for_replay.cpp b/libs/resiliency/tests/performance/replay/pure_async_for_replay.cpp index 8c50f4d1240e..48959f3150ed 100644 --- a/libs/resiliency/tests/performance/replay/pure_async_for_replay.cpp +++ b/libs/resiliency/tests/performance/replay/pure_async_for_replay.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -105,7 +105,7 @@ int hpx_main(hpx::program_options::variables_map& vm) { std::cout << "Exceptions thrown" << std::endl; } - catch (hpx::resiliency::abort_replay_exception const&) + catch (hpx::resiliency::experimental::abort_replay_exception const&) { std::cout << "Exceptions thrown" << std::endl; } diff --git a/libs/resiliency/tests/performance/replicate/1d_stencil_replicate.cpp b/libs/resiliency/tests/performance/replicate/1d_stencil_replicate.cpp index fb806ce9c224..204f4c17f478 100644 --- a/libs/resiliency/tests/performance/replicate/1d_stencil_replicate.cpp +++ b/libs/resiliency/tests/performance/replicate/1d_stencil_replicate.cpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include @@ -195,7 +195,7 @@ struct stepper std::uint64_t nd, std::uint64_t n_value, double error, hpx::lcos::local::sliding_semaphore& sem) { - using hpx::resiliency::dataflow_replicate; + using hpx::resiliency::experimental::dataflow_replicate; using hpx::util::unwrapping; // U[t][i] is the state of position i at time t. diff --git a/libs/resiliency/tests/performance/replicate/1d_stencil_replicate_checksum.cpp b/libs/resiliency/tests/performance/replicate/1d_stencil_replicate_checksum.cpp index dbdb048226ba..bc88b8d4b89f 100644 --- a/libs/resiliency/tests/performance/replicate/1d_stencil_replicate_checksum.cpp +++ b/libs/resiliency/tests/performance/replicate/1d_stencil_replicate_checksum.cpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include @@ -236,7 +236,7 @@ struct stepper std::uint64_t nd, std::uint64_t n_value, double error, hpx::lcos::local::sliding_semaphore& sem) { - using hpx::resiliency::dataflow_replicate_validate; + using hpx::resiliency::experimental::dataflow_replicate_validate; using hpx::util::unwrapping; // U[t][i] is the state of position i at time t. diff --git a/libs/resiliency/tests/performance/replicate/async_replicate.cpp b/libs/resiliency/tests/performance/replicate/async_replicate.cpp index 3c3b6c3c0298..b9f1c64c3b2e 100644 --- a/libs/resiliency/tests/performance/replicate/async_replicate.cpp +++ b/libs/resiliency/tests/performance/replicate/async_replicate.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -90,7 +90,7 @@ int hpx_main(hpx::program_options::variables_map& vm) for (int i = 0; i < num_iterations; ++i) { - hpx::future f = hpx::resiliency::async_replicate( + hpx::future f = hpx::resiliency::experimental::async_replicate( n, &universal_ans, delay * 1000, error); vect.push_back(std::move(f)); } diff --git a/libs/resiliency/tests/performance/replicate/async_replicate_validate.cpp b/libs/resiliency/tests/performance/replicate/async_replicate_validate.cpp index 200eface3992..240981ed79d4 100644 --- a/libs/resiliency/tests/performance/replicate/async_replicate_validate.cpp +++ b/libs/resiliency/tests/performance/replicate/async_replicate_validate.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -98,8 +98,9 @@ int hpx_main(hpx::program_options::variables_map& vm) for (int i = 0; i < num_iterations; ++i) { - hpx::future f = hpx::resiliency::async_replicate_validate( - n, &validate, &universal_ans, delay * 1000, error); + hpx::future f = + hpx::resiliency::experimental::async_replicate_validate( + n, &validate, &universal_ans, delay * 1000, error); vect.push_back(std::move(f)); } diff --git a/libs/resiliency/tests/performance/replicate/async_replicate_vote.cpp b/libs/resiliency/tests/performance/replicate/async_replicate_vote.cpp index a33f386240e5..bca7e1ea5db2 100644 --- a/libs/resiliency/tests/performance/replicate/async_replicate_vote.cpp +++ b/libs/resiliency/tests/performance/replicate/async_replicate_vote.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -98,8 +98,9 @@ int hpx_main(hpx::program_options::variables_map& vm) for (int i = 0; i < num_iterations; ++i) { - hpx::future f = hpx::resiliency::async_replicate_validate( - n, &validate, &universal_ans, delay * 1000, error); + hpx::future f = + hpx::resiliency::experimental::async_replicate_validate( + n, &validate, &universal_ans, delay * 1000, error); vect.push_back(std::move(f)); } diff --git a/libs/resiliency/tests/performance/replicate/async_replicate_vote_validate.cpp b/libs/resiliency/tests/performance/replicate/async_replicate_vote_validate.cpp index 55a216f0560d..5c6a81410f77 100644 --- a/libs/resiliency/tests/performance/replicate/async_replicate_vote_validate.cpp +++ b/libs/resiliency/tests/performance/replicate/async_replicate_vote_validate.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -95,8 +95,9 @@ int hpx_main(hpx::program_options::variables_map& vm) for (int i = 0; i < num_iterations; ++i) { - hpx::future f = hpx::resiliency::async_replicate_vote( - n, &vote, &universal_ans, delay * 1000, error); + hpx::future f = + hpx::resiliency::experimental::async_replicate_vote( + n, &vote, &universal_ans, delay * 1000, error); vect.push_back(std::move(f)); } diff --git a/libs/resiliency/tests/performance/replicate/pure_async_for_replicate.cpp b/libs/resiliency/tests/performance/replicate/pure_async_for_replicate.cpp index 42bde2c5def1..030ea88ebd91 100644 --- a/libs/resiliency/tests/performance/replicate/pure_async_for_replicate.cpp +++ b/libs/resiliency/tests/performance/replicate/pure_async_for_replicate.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include diff --git a/libs/resiliency/tests/unit/CMakeLists.txt b/libs/resiliency/tests/unit/CMakeLists.txt index e050627465c9..238b7284a0aa 100644 --- a/libs/resiliency/tests/unit/CMakeLists.txt +++ b/libs/resiliency/tests/unit/CMakeLists.txt @@ -1,5 +1,36 @@ -# Copyright (c) 2019 The STE||AR-Group +# Copyright (c) 2020 The STE||AR-Group # # 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) + +set(tests + async_replay_executor + async_replay_plain + async_replicate_executor + async_replicate_plain + async_replicate_vote_executor + async_replicate_vote_plain + dataflow_replay_executor + dataflow_replay_plain + dataflow_replicate_executor + dataflow_replicate_plain +) + +foreach(test ${tests}) + set(sources ${test}.cpp) + + source_group("Source Files" FILES ${sources}) + + set(folder_name "Tests/Unit/Modules/Resiliency") + + # add test executable + add_hpx_executable( + ${test}_test INTERNAL_FLAGS + SOURCES ${sources} ${${test}_FLAGS} + EXCLUDE_FROM_ALL + FOLDER ${folder_name} + ) + + add_hpx_unit_test("modules.resiliency" ${test} ${${test}_PARAMETERS}) +endforeach() diff --git a/libs/resiliency/tests/unit/async_replay_executor.cpp b/libs/resiliency/tests/unit/async_replay_executor.cpp new file mode 100644 index 000000000000..54f0b1b774b6 --- /dev/null +++ b/libs/resiliency/tests/unit/async_replay_executor.cpp @@ -0,0 +1,152 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018-2020 Hartmut Kaiser +// Copyright (c) 2018-2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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 + +#include +#include + +std::atomic answer(35); +struct vogon_exception : std::exception +{ +}; + +int universal_answer() +{ + return ++answer; +} + +bool validate(int result) +{ + return result == 42; +} + +int no_answer() +{ + throw hpx::resiliency::experimental::abort_replay_exception(); +} + +int deep_thought() +{ + static int ans = 35; + ++ans; + if (ans == 42) + return ans; + else + throw vogon_exception(); +} + +int hpx_main() +{ + { + hpx::parallel::execution::parallel_executor exec; + + // successful replay + hpx::future f = hpx::resiliency::experimental::async_replay( + exec, 10, &deep_thought); + HPX_TEST(f.get() == 42); + + // successful replay validate + f = hpx::resiliency::experimental::async_replay_validate( + exec, 10, &validate, &universal_answer); + HPX_TEST(f.get() == 42); + + // unsuccessful replay + f = hpx::resiliency::experimental::async_replay(exec, 6, &deep_thought); + + bool exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (vogon_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // unsuccessful replay validate + f = hpx::resiliency::experimental::async_replay_validate( + exec, 6, &validate, &universal_answer); + + exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replay + f = hpx::resiliency::experimental::async_replay(exec, 1, &no_answer); + + exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replay validate + f = hpx::resiliency::experimental::async_replay_validate( + exec, 1, &validate, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/async_replay_plain.cpp b/libs/resiliency/tests/unit/async_replay_plain.cpp new file mode 100644 index 000000000000..db5f8657b4e9 --- /dev/null +++ b/libs/resiliency/tests/unit/async_replay_plain.cpp @@ -0,0 +1,149 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018-2020 Hartmut Kaiser +// Copyright (c) 2018-2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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 +#include + +std::atomic answer(35); +struct vogon_exception : std::exception +{ +}; + +int universal_answer() +{ + return ++answer; +} + +bool validate(int result) +{ + return result == 42; +} + +int no_answer() +{ + throw hpx::resiliency::experimental::abort_replay_exception(); +} + +int deep_thought() +{ + static int ans = 35; + ++ans; + if (ans == 42) + return ans; + else + throw vogon_exception(); +} + +int hpx_main() +{ + { + // successful replay + hpx::future f = + hpx::resiliency::experimental::async_replay(10, &deep_thought); + HPX_TEST(f.get() == 42); + + // successful replay validate + f = hpx::resiliency::experimental::async_replay_validate( + 10, &validate, &universal_answer); + HPX_TEST(f.get() == 42); + + // unsuccessful replay + f = hpx::resiliency::experimental::async_replay(6, &deep_thought); + + bool exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (vogon_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // unsuccessful replay validate + f = hpx::resiliency::experimental::async_replay_validate( + 6, &validate, &universal_answer); + + exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replay + f = hpx::resiliency::experimental::async_replay(1, &no_answer); + + exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replay validate + f = hpx::resiliency::experimental::async_replay_validate( + 1, &validate, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/async_replicate_executor.cpp b/libs/resiliency/tests/unit/async_replicate_executor.cpp new file mode 100644 index 000000000000..0f25ae07a73c --- /dev/null +++ b/libs/resiliency/tests/unit/async_replicate_executor.cpp @@ -0,0 +1,151 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018-2020 Hartmut Kaiser +// Copyright (c) 2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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 + +#include +#include + +std::atomic answer(35); + +struct vogon_exception : std::exception +{ +}; + +int universal_answer() +{ + return ++answer; +} + +bool validate(int result) +{ + return result == 42; +} + +int no_answer() +{ + throw hpx::resiliency::experimental::abort_replicate_exception(); +} + +int deep_thought() +{ + static int ans = 35; + ++ans; + if (ans == 42) + return ans; + else + throw vogon_exception(); +} + +int hpx_main() +{ + { + hpx::parallel::execution::parallel_executor exec; + + // successful replicate + hpx::future f = hpx::resiliency::experimental::async_replicate( + exec, 10, &deep_thought); + HPX_TEST(f.get() == 42); + + // successful replicate_validate + f = hpx::resiliency::experimental::async_replicate_validate( + exec, 10, &validate, &universal_answer); + HPX_TEST(f.get() == 42); + + // unsuccessful replicate + f = hpx::resiliency::experimental::async_replicate( + exec, 6, &deep_thought); + + bool exception_caught = false; + try + { + f.get(); + } + catch (vogon_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // unsuccessful replicate_validate + f = hpx::resiliency::experimental::async_replicate_validate( + exec, 6, &validate, &universal_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replicate + f = hpx::resiliency::experimental::async_replicate(exec, 1, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replicate validate + f = hpx::resiliency::experimental::async_replicate_validate( + exec, 1, &validate, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/async_replicate_plain.cpp b/libs/resiliency/tests/unit/async_replicate_plain.cpp new file mode 100644 index 000000000000..85b1e09be3b6 --- /dev/null +++ b/libs/resiliency/tests/unit/async_replicate_plain.cpp @@ -0,0 +1,147 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018-2020 Hartmut Kaiser +// Copyright (c) 2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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 +#include + +std::atomic answer(35); + +struct vogon_exception : std::exception +{ +}; + +int universal_answer() +{ + return ++answer; +} + +bool validate(int result) +{ + return result == 42; +} + +int no_answer() +{ + throw hpx::resiliency::experimental::abort_replicate_exception(); +} + +int deep_thought() +{ + static int ans = 35; + ++ans; + if (ans == 42) + return ans; + else + throw vogon_exception(); +} + +int hpx_main() +{ + { + // successful replicate + hpx::future f = + hpx::resiliency::experimental::async_replicate(10, &deep_thought); + HPX_TEST(f.get() == 42); + + // successful replicate_validate + f = hpx::resiliency::experimental::async_replicate_validate( + 10, &validate, &universal_answer); + HPX_TEST(f.get() == 42); + + // unsuccessful replicate + f = hpx::resiliency::experimental::async_replicate(6, &deep_thought); + + bool exception_caught = false; + try + { + f.get(); + } + catch (vogon_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // unsuccessful replicate_validate + f = hpx::resiliency::experimental::async_replicate_validate( + 6, &validate, &universal_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replicate + f = hpx::resiliency::experimental::async_replicate(1, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replicate validate + f = hpx::resiliency::experimental::async_replicate_validate( + 1, &validate, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/async_replicate_vote_executor.cpp b/libs/resiliency/tests/unit/async_replicate_vote_executor.cpp new file mode 100644 index 000000000000..a9ecf662fee0 --- /dev/null +++ b/libs/resiliency/tests/unit/async_replicate_vote_executor.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2019 Nikunj Gupta +// Copyright (c) 2018-2020 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 +#include +#include + +std::random_device rd; +std::mt19937 mt(rd()); +std::uniform_real_distribution dist(1.0, 10.0); + +int vote(std::vector vect) +{ + return vect.at(0); +} + +int universal_ans() +{ + if (dist(mt) > 5) + return 42; + return 84; +} + +bool validate(int ans) +{ + return ans == 42; +} + +int hpx_main() +{ + { + hpx::parallel::execution::parallel_executor exec; + + hpx::future f = + hpx::resiliency::experimental::async_replicate_vote( + exec, 10, &vote, &universal_ans); + + auto result = f.get(); + HPX_TEST(result == 42 || result == 84); + } + + { + hpx::parallel::execution::parallel_executor exec; + + hpx::future f = + hpx::resiliency::experimental::async_replicate_vote_validate( + exec, 10, &vote, &validate, &universal_ans); + + auto result = f.get(); + HPX_TEST(result == 42 || result == 84); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/async_replicate_vote_plain.cpp b/libs/resiliency/tests/unit/async_replicate_vote_plain.cpp new file mode 100644 index 000000000000..9d1c228b880a --- /dev/null +++ b/libs/resiliency/tests/unit/async_replicate_vote_plain.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2019 Nikunj Gupta +// Copyright (c) 2018-2020 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 +#include + +std::random_device rd; +std::mt19937 mt(rd()); +std::uniform_real_distribution dist(1.0, 10.0); + +int vote(std::vector vect) +{ + return vect.at(0); +} + +int universal_ans() +{ + if (dist(mt) > 5) + return 42; + return 84; +} + +bool validate(int ans) +{ + return ans == 42; +} + +int hpx_main() +{ + { + hpx::future f = + hpx::resiliency::experimental::async_replicate_vote( + 10, &vote, &universal_ans); + + auto result = f.get(); + HPX_TEST(result == 42 || result == 84); + } + + { + hpx::future f = + hpx::resiliency::experimental::async_replicate_vote_validate( + 10, &vote, &validate, &universal_ans); + + auto result = f.get(); + HPX_TEST(result == 42 || result == 84); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/dataflow_replay_executor.cpp b/libs/resiliency/tests/unit/dataflow_replay_executor.cpp new file mode 100644 index 000000000000..fe27d295e54c --- /dev/null +++ b/libs/resiliency/tests/unit/dataflow_replay_executor.cpp @@ -0,0 +1,153 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018-2020 Hartmut Kaiser +// Copyright (c) 2018-2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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 + +#include +#include + +std::atomic answer(35); +struct vogon_exception : std::exception +{ +}; + +int universal_answer() +{ + return ++answer; +} + +bool validate(int result) +{ + return result == 42; +} + +int no_answer() +{ + throw hpx::resiliency::experimental::abort_replay_exception(); +} + +int deep_thought() +{ + static int ans = 35; + ++ans; + if (ans == 42) + return ans; + else + throw vogon_exception(); +} + +int hpx_main() +{ + { + hpx::parallel::execution::parallel_executor exec; + + // successful replay + hpx::future f = hpx::resiliency::experimental::dataflow_replay( + exec, 10, &deep_thought); + HPX_TEST(f.get() == 42); + + // successful replay validate + f = hpx::resiliency::experimental::dataflow_replay_validate( + exec, 10, &validate, &universal_answer); + HPX_TEST(f.get() == 42); + + // unsuccessful replay + f = hpx::resiliency::experimental::dataflow_replay( + exec, 6, &deep_thought); + + bool exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (vogon_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // unsuccessful replay validate + f = hpx::resiliency::experimental::dataflow_replay_validate( + exec, 6, &validate, &universal_answer); + + exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replay + f = hpx::resiliency::experimental::dataflow_replay(exec, 1, &no_answer); + + exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replay validate + f = hpx::resiliency::experimental::dataflow_replay_validate( + exec, 1, &validate, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/dataflow_replay_plain.cpp b/libs/resiliency/tests/unit/dataflow_replay_plain.cpp new file mode 100644 index 000000000000..ea33eb5636c9 --- /dev/null +++ b/libs/resiliency/tests/unit/dataflow_replay_plain.cpp @@ -0,0 +1,149 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018-2020 Hartmut Kaiser +// Copyright (c) 2018-2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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 +#include + +std::atomic answer(35); +struct vogon_exception : std::exception +{ +}; + +int universal_answer() +{ + return ++answer; +} + +bool validate(int result) +{ + return result == 42; +} + +int no_answer() +{ + throw hpx::resiliency::experimental::abort_replay_exception(); +} + +int deep_thought() +{ + static int ans = 35; + ++ans; + if (ans == 42) + return ans; + else + throw vogon_exception(); +} + +int hpx_main() +{ + { + // successful replay + hpx::future f = + hpx::resiliency::experimental::dataflow_replay(10, &deep_thought); + HPX_TEST(f.get() == 42); + + // successful replay validate + f = hpx::resiliency::experimental::dataflow_replay_validate( + 10, &validate, &universal_answer); + HPX_TEST(f.get() == 42); + + // unsuccessful replay + f = hpx::resiliency::experimental::dataflow_replay(6, &deep_thought); + + bool exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (vogon_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // unsuccessful replay validate + f = hpx::resiliency::experimental::dataflow_replay_validate( + 6, &validate, &universal_answer); + + exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replay + f = hpx::resiliency::experimental::dataflow_replay(1, &no_answer); + + exception_caught = false; + try + { + f.get(); + HPX_TEST(false); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replay validate + f = hpx::resiliency::experimental::dataflow_replay_validate( + 1, &validate, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replay_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/dataflow_replicate_executor.cpp b/libs/resiliency/tests/unit/dataflow_replicate_executor.cpp new file mode 100644 index 000000000000..7da3e499f168 --- /dev/null +++ b/libs/resiliency/tests/unit/dataflow_replicate_executor.cpp @@ -0,0 +1,152 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018 Hartmut Kaiser +// Copyright (c) 2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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 + +#include +#include + +std::atomic answer(35); + +struct vogon_exception : std::exception +{ +}; + +int universal_answer() +{ + return ++answer; +} + +bool validate(int result) +{ + return result == 42; +} + +int no_answer() +{ + throw hpx::resiliency::experimental::abort_replicate_exception(); +} + +int deep_thought() +{ + static int ans = 35; + ++ans; + if (ans == 42) + return ans; + else + throw vogon_exception(); +} + +int hpx_main() +{ + { + hpx::parallel::execution::parallel_executor exec; + + // successful replicate + hpx::future f = hpx::resiliency::experimental::dataflow_replicate( + exec, 10, &deep_thought); + HPX_TEST(f.get() == 42); + + // successful replicate_validate + f = hpx::resiliency::experimental::dataflow_replicate_validate( + exec, 10, &validate, &universal_answer); + HPX_TEST(f.get() == 42); + + // unsuccessful replicate + f = hpx::resiliency::experimental::dataflow_replicate( + exec, 6, &deep_thought); + + bool exception_caught = false; + try + { + f.get(); + } + catch (vogon_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // unsuccessful replicate_validate + f = hpx::resiliency::experimental::dataflow_replicate_validate( + exec, 6, &validate, &universal_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replicate + f = hpx::resiliency::experimental::dataflow_replicate( + exec, 1, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replicate validate + f = hpx::resiliency::experimental::dataflow_replicate_validate( + exec, 1, &validate, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/resiliency/tests/unit/dataflow_replicate_plain.cpp b/libs/resiliency/tests/unit/dataflow_replicate_plain.cpp new file mode 100644 index 000000000000..71b5fde5237a --- /dev/null +++ b/libs/resiliency/tests/unit/dataflow_replicate_plain.cpp @@ -0,0 +1,147 @@ +// Copyright (c) 2019 National Technology & Engineering Solutions of Sandia, +// LLC (NTESS). +// Copyright (c) 2018 Hartmut Kaiser +// Copyright (c) 2019 Adrian Serio +// Copyright (c) 2019 Nikunj Gupta +// +// 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 +#include + +std::atomic answer(35); + +struct vogon_exception : std::exception +{ +}; + +int universal_answer() +{ + return ++answer; +} + +bool validate(int result) +{ + return result == 42; +} + +int no_answer() +{ + throw hpx::resiliency::experimental::abort_replicate_exception(); +} + +int deep_thought() +{ + static int ans = 35; + ++ans; + if (ans == 42) + return ans; + else + throw vogon_exception(); +} + +int hpx_main() +{ + { + // successful replicate + hpx::future f = hpx::resiliency::experimental::dataflow_replicate( + 10, &deep_thought); + HPX_TEST(f.get() == 42); + + // successful replicate_validate + f = hpx::resiliency::experimental::dataflow_replicate_validate( + 10, &validate, &universal_answer); + HPX_TEST(f.get() == 42); + + // unsuccessful replicate + f = hpx::resiliency::experimental::dataflow_replicate(6, &deep_thought); + + bool exception_caught = false; + try + { + f.get(); + } + catch (vogon_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // unsuccessful replicate_validate + f = hpx::resiliency::experimental::dataflow_replicate_validate( + 6, &validate, &universal_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replicate + f = hpx::resiliency::experimental::dataflow_replicate(1, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + + // aborted replicate validate + f = hpx::resiliency::experimental::dataflow_replicate_validate( + 1, &validate, &no_answer); + + exception_caught = false; + try + { + f.get(); + } + catch (hpx::resiliency::experimental::abort_replicate_exception const&) + { + exception_caught = true; + } + catch (...) + { + HPX_TEST(false); + } + HPX_TEST(exception_caught); + } + + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // Initialize and run HPX + HPX_TEST(hpx::init(argc, argv) == 0); + return hpx::util::report_errors(); +} diff --git a/libs/synchronization/include/hpx/synchronization/lock_types.hpp b/libs/synchronization/include/hpx/synchronization/lock_types.hpp index 29da6d02cd9c..c636ce11a42e 100644 --- a/libs/synchronization/include/hpx/synchronization/lock_types.hpp +++ b/libs/synchronization/include/hpx/synchronization/lock_types.hpp @@ -38,7 +38,7 @@ namespace hpx { namespace lcos { namespace local { upgrade_lock& operator=(upgrade_lock const&) = delete; upgrade_lock() noexcept - : m(0) + : m(nullptr) , is_locked(false) { } @@ -71,7 +71,7 @@ namespace hpx { namespace lcos { namespace local { , is_locked(other.is_locked) { other.is_locked = false; - other.m = 0; + other.m = nullptr; } explicit upgrade_lock(std::unique_lock&& other) @@ -105,7 +105,7 @@ namespace hpx { namespace lcos { namespace local { Mutex* release() noexcept { Mutex* const res = m; - m = 0; + m = nullptr; is_locked = false; return res; } @@ -119,7 +119,7 @@ namespace hpx { namespace lcos { namespace local { void lock() { - if (m == 0) + if (m == nullptr) { HPX_THROW_EXCEPTION( lock_error, "mutex::unlock", "upgrade_lock has no mutex"); @@ -134,7 +134,7 @@ namespace hpx { namespace lcos { namespace local { } bool try_lock() { - if (m == 0) + if (m == nullptr) { HPX_THROW_EXCEPTION( lock_error, "mutex::unlock", "upgrade_lock has no mutex"); @@ -149,7 +149,7 @@ namespace hpx { namespace lcos { namespace local { } void unlock() { - if (m == 0) + if (m == nullptr) { HPX_THROW_EXCEPTION( lock_error, "mutex::unlock", "upgrade_lock has no mutex"); @@ -209,7 +209,7 @@ namespace hpx { namespace lcos { namespace local { } ~upgrade_to_unique_lock() { - if (source) + if (source != nullptr) { *source = upgrade_lock(std::move(exclusive)); } @@ -219,7 +219,7 @@ namespace hpx { namespace lcos { namespace local { : source(other.source) , exclusive(std::move(other.exclusive)) { - other.source = 0; + other.source = nullptr; } upgrade_to_unique_lock& operator=( diff --git a/tests/performance/local/CMakeLists.txt b/tests/performance/local/CMakeLists.txt index 8d468297e961..8a4c88034884 100644 --- a/tests/performance/local/CMakeLists.txt +++ b/tests/performance/local/CMakeLists.txt @@ -13,6 +13,7 @@ set(benchmarks delay_baseline delay_baseline_threaded function_object_wrapper_overhead + future_overhead hpx_tls_overhead native_tls_overhead print_heterogeneous_payloads @@ -111,7 +112,6 @@ if(HPX_WITH_DISTRIBUTED_RUNTIME) ${benchmarks} agas_cache_timings foreach_scaling - future_overhead hpx_homogeneous_timed_task_spawn_executors hpx_heterogeneous_timed_task_spawn parent_vs_child_stealing @@ -149,7 +149,7 @@ set(hpx_heterogeneous_timed_task_spawn_FLAGS DEPENDENCIES iostreams_component set(parent_vs_child_stealing_FLAGS DEPENDENCIES iostreams_component hpx_timing) set(skynet_FLAGS DEPENDENCIES iostreams_component) set(wait_all_timings_FLAGS DEPENDENCIES iostreams_component hpx_timing) -set(future_overhead_FLAGS DEPENDENCIES iostreams_component hpx_timing) +set(future_overhead_FLAGS DEPENDENCIES hpx_timing) set(sizeof_FLAGS DEPENDENCIES iostreams_component) set(foreach_scaling_FLAGS DEPENDENCIES iostreams_component hpx_timing) set(spinlock_overhead1_FLAGS DEPENDENCIES iostreams_component hpx_timing) diff --git a/tests/performance/local/future_overhead.cpp b/tests/performance/local/future_overhead.cpp index eb2d5bf943a8..a3efcbe982e5 100644 --- a/tests/performance/local/future_overhead.cpp +++ b/tests/performance/local/future_overhead.cpp @@ -6,21 +6,24 @@ // 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 +#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME) #include +#include +#endif #include #include #include #include #include -#include #include #include #include #include #include #include -#include #include +#include #include #include @@ -44,9 +47,6 @@ using hpx::program_options::variables_map; using hpx::finalize; using hpx::init; -using hpx::find_here; -using hpx::naming::id_type; - using hpx::apply; using hpx::async; using hpx::future; @@ -54,9 +54,6 @@ using hpx::lcos::wait_each; using hpx::util::high_resolution_timer; -using hpx::cout; -using hpx::flush; - // global vars we stick here to make printouts easy for plotting static std::string queuing = "default"; static std::size_t numa_sensitive = 0; @@ -131,8 +128,6 @@ double null_function() noexcept return 0.0; } -HPX_PLAIN_ACTION(null_function, null_action) - struct scratcher { void operator()(future r) const @@ -141,10 +136,13 @@ struct scratcher } }; +#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME) +HPX_PLAIN_ACTION(null_function, null_action) + // Time async action execution using wait each on futures vector void measure_action_futures_wait_each(std::uint64_t count, bool csv) { - const id_type here = find_here(); + const hpx::naming::id_type here = hpx::find_here(); std::vector> futures; futures.reserve(count); @@ -162,7 +160,7 @@ void measure_action_futures_wait_each(std::uint64_t count, bool csv) // Time async action execution using wait each on futures vector void measure_action_futures_wait_all(std::uint64_t count, bool csv) { - const id_type here = find_here(); + const hpx::naming::id_type here = hpx::find_here(); std::vector> futures; futures.reserve(count); @@ -176,6 +174,7 @@ void measure_action_futures_wait_all(std::uint64_t count, bool csv) const double duration = walltime.elapsed(); print_stats("action", "WaitAll", "no-executor", count, duration, csv); } +#endif // Time async execution using wait each on futures vector template @@ -568,8 +567,10 @@ int hpx_main(variables_map& vm) if (test_all) { measure_function_futures_limiting_executor(count, csv, tpe); +#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME) measure_action_futures_wait_each(count, csv); measure_action_futures_wait_all(count, csv); +#endif measure_function_futures_wait_each(count, csv, par); measure_function_futures_wait_each(count, csv, tpe); measure_function_futures_wait_all(count, csv, par); diff --git a/tests/performance/local/libcds_hazard_pointer_overhead.cpp b/tests/performance/local/libcds_hazard_pointer_overhead.cpp index 3922498d297f..8b25c9d8af32 100644 --- a/tests/performance/local/libcds_hazard_pointer_overhead.cpp +++ b/tests/performance/local/libcds_hazard_pointer_overhead.cpp @@ -10,15 +10,13 @@ #include #include #include -#include #include #include #include +#include #include #include #include -#include -#include #include #include @@ -115,10 +113,27 @@ double global_scratch = 0; std::uint64_t num_iterations = 0; /////////////////////////////////////////////////////////////////////////////// +struct libcds_thread_manager_wrapper +{ + explicit libcds_thread_manager_wrapper(bool uselibcds) + : uselibcds_(uselibcds) + { + if (uselibcds_) + cds::gc::hp::smr::attach_thread(); + } + ~libcds_thread_manager_wrapper() + { + if (uselibcds_) + cds::gc::hp::smr::detach_thread(); + } + + bool uselibcds_; +}; + double null_function(bool uselibcds) noexcept { - if (uselibcds) - cds::threading::Manager::attachThread(); + libcds_thread_manager_wrapper wrap(uselibcds); + if (num_iterations > 0) { const int array_size = 4096; @@ -132,8 +147,6 @@ double null_function(bool uselibcds) noexcept } return dummy[0]; } - if (uselibcds) - cds::threading::Manager::detachThread(); return 0.0; } @@ -210,10 +223,10 @@ void measure_function_futures_create_thread_hierarchical_placement( }; auto const thread_func = hpx::threads::detail::thread_function_nullary{func}; - auto const desc = hpx::util::thread_description(); + auto desc = hpx::util::thread_description(); auto prio = hpx::threads::thread_priority_normal; - auto const stack_size = hpx::threads::thread_stacksize_small; - auto const num_threads = hpx::get_num_worker_threads(); + auto stack_size = hpx::threads::thread_stacksize_small; + auto num_threads = hpx::get_num_worker_threads(); hpx::error_code ec; // start the clock @@ -223,7 +236,7 @@ void measure_function_futures_create_thread_hierarchical_placement( auto const hint = hpx::threads::thread_schedule_hint(static_cast(t)); auto spawn_func = [&thread_func, sched, hint, t, count, num_threads, - desc, prio]() { + desc, prio, stack_size]() { std::uint64_t const count_start = t * count / num_threads; std::uint64_t const count_end = (t + 1) * count / num_threads; hpx::error_code ec; @@ -253,15 +266,27 @@ void measure_function_futures_create_thread_hierarchical_placement( } /////////////////////////////////////////////////////////////////////////////// +struct libcds_wrapper +{ + libcds_wrapper() + { + // Initialize libcds + cds::Initialize(); + } + + ~libcds_wrapper() + { + // Terminate libcds + cds::Terminate(); + } +}; + int hpx_main(variables_map& vm) { // Initialize libcds - cds::Initialize(); + libcds_wrapper wrapper; { - // Initialize Hazard Pointer singleton - cds::gc::HP hpGC; - if (vm.count("hpx:queuing")) queuing = vm["hpx:queuing"].as(); @@ -284,12 +309,11 @@ int hpx_main(variables_map& vm) if (HPX_UNLIKELY(0 == count)) throw std::logic_error("error: count of 0 futures specified\n"); + cds::gc::HP hpGC; + hpx::parallel::execution::parallel_executor par; hpx::parallel::execution::parallel_executor_aggregated par_agg; hpx::parallel::execution::thread_pool_executor tpe; - hpx::parallel::execution::thread_pool_executor tpe_nostack( - hpx::threads::thread_priority_default, - hpx::threads::thread_stacksize_nostack); for (int i = 0; i < repetitions; i++) { @@ -299,15 +323,14 @@ int hpx_main(variables_map& vm) count, csv, bool(cds)); measure_function_futures_thread_count( count, csv, par, bool(cds)); + measure_function_futures_thread_count( + count, csv, par_agg, bool(cds)); measure_function_futures_thread_count( count, csv, tpe, bool(cds)); } } } - // Terminate libcds - cds::Terminate(); - return hpx::finalize(); } @@ -318,20 +341,20 @@ int main(int argc, char* argv[]) options_description cmdline("usage: " HPX_APPLICATION_STRING " [options]"); // clang-format off - cmdline.add_options()("futures", - value()->default_value(500000), - "number of futures to invoke") + cmdline.add_options() + ("futures", value()->default_value(500000), + "number of futures to invoke") - ("delay-iterations", value()->default_value(0), - "number of iterations in the delay loop") + ("delay-iterations", value()->default_value(0), + "number of iterations in the delay loop") - ("csv", "output results as csv (format: count,duration)") - ("test-all", "run all benchmarks") - ("repetitions", value()->default_value(1), - "number of repetitions of the full benchmark") + ("csv", "output results as csv (format: count,duration)") + ("test-all", "run all benchmarks") + ("repetitions", value()->default_value(1), + "number of repetitions of the full benchmark") - ("info", value()->default_value("no-info"), - "extra info for plot output (e.g. branch name)"); + ("info", value()->default_value("no-info"), + "extra info for plot output (e.g. branch name)"); // clang-format on // Initialize and run HPX. diff --git a/tests/unit/component/CMakeLists.txt b/tests/unit/component/CMakeLists.txt index ed7fcf8bc75e..a15df3d0a694 100644 --- a/tests/unit/component/CMakeLists.txt +++ b/tests/unit/component/CMakeLists.txt @@ -20,6 +20,7 @@ if(HPX_WITH_DISTRIBUTED_RUNTIME) inheritance_3_classes_1_abstract inheritance_3_classes_2_abstract inheritance_2_classes_concrete_simple + inheritance_3_classes_2_concrete inheritance_3_classes_concrete local_new migrate_component @@ -59,6 +60,8 @@ if(HPX_WITH_DISTRIBUTED_RUNTIME) set(inheritance_3_classes_concrete_FLAGS DEPENDENCIES iostreams_component) + set(inheritance_3_classes_2_concrete_FLAGS DEPENDENCIES iostreams_component) + set(migrate_component_to_storage_FLAGS DEPENDENCIES unordered_component component_storage_component ) diff --git a/tests/unit/component/inheritance_3_classes_2_concrete.cpp b/tests/unit/component/inheritance_3_classes_2_concrete.cpp new file mode 100644 index 000000000000..1e312a32cdfd --- /dev/null +++ b/tests/unit/component/inheritance_3_classes_2_concrete.cpp @@ -0,0 +1,320 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2012 Bryce Adelstein-Lelbach +// +// 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 + +bool a_ctor = false; +bool a_dtor = false; +bool b_ctor = false; +bool b_dtor = false; +bool c_ctor = false; +bool c_dtor = false; + +/////////////////////////////////////////////////////////////////////////////// +// Concrete +struct A : hpx::components::component_base +{ + A() + { + a_ctor = true; + } + virtual ~A() + { + a_dtor = true; + } + + virtual std::string test0() const + { + return "A"; + } + std::string test0_nonvirt() const + { + return test0(); + } + HPX_DEFINE_COMPONENT_ACTION(A, test0_nonvirt, test0_action); +}; + +typedef hpx::components::component serverA_type; +HPX_REGISTER_COMPONENT(serverA_type, A); + +typedef A::test0_action test0_action; +HPX_REGISTER_ACTION_DECLARATION(test0_action); +HPX_REGISTER_ACTION(test0_action); + +/////////////////////////////////////////////////////////////////////////////// +// Concrete +struct B : hpx::components::component_base +{ + B() + { + b_ctor = true; + } + virtual ~B() + { + b_dtor = true; + } + + virtual std::string test1() const + { + return "B"; + } + std::string test1_nonvirt() const + { + return test1(); + } + HPX_DEFINE_COMPONENT_ACTION(B, test1_nonvirt, test1_action); +}; + +typedef hpx::components::component serverB_type; +HPX_REGISTER_COMPONENT(serverB_type, B); + +typedef B::test1_action test1_action; +HPX_REGISTER_ACTION_DECLARATION(test1_action); +HPX_REGISTER_ACTION(test1_action); + +/////////////////////////////////////////////////////////////////////////////// +// Concrete +struct C + : A + , B + , hpx::components::component_base +{ + typedef hpx::components::component_base::wrapping_type wrapping_type; + typedef hpx::components::component_base::wrapped_type wrapped_type; + + using hpx::components::component_base::finalize; + using hpx::components::component_base::get_base_gid; + using hpx::components::component_base::get_current_address; + + typedef C type_holder; + typedef B base_type_holder; + + C() + { + c_ctor = true; + } + ~C() + { + c_dtor = true; + } + + std::string test0() const + { + return "C"; + } + + std::string test1() const + { + return "C"; + } + + std::string test2() const + { + return "C"; + } + HPX_DEFINE_COMPONENT_ACTION(C, test2, test2_action); +}; + +typedef hpx::components::component serverC_type; +HPX_REGISTER_DERIVED_COMPONENT_FACTORY(serverC_type, C, "B"); + +typedef C::test2_action test2_action; +HPX_REGISTER_ACTION_DECLARATION(test2_action); +HPX_REGISTER_ACTION(test2_action); + +/////////////////////////////////////////////////////////////////////////////// +struct clientA : hpx::components::client_base +{ + typedef hpx::components::client_base base_type; + + clientA(hpx::shared_future const& gid) + : base_type(gid) + { + } + + std::string test0() + { + test0_action act; + return act(base_type::get_id()); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +struct clientB : hpx::components::client_base +{ + typedef hpx::components::client_base base_type; + + clientB(hpx::shared_future const& gid) + : base_type(gid) + { + } + + std::string test1() + { + test1_action act; + return act(base_type::get_id()); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +struct clientC : hpx::components::client_base +{ + typedef hpx::components::client_base base_type; + + clientC(hpx::shared_future const& gid) + : base_type(gid) + { + } + + std::string test0() + { + test0_action act; + return act(base_type::get_id()); + } + + std::string test1() + { + test1_action act; + return act(base_type::get_id()); + } + + std::string test2() + { + test2_action act; + return act(base_type::get_id()); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +void reset_globals() +{ + a_ctor = false; + a_dtor = false; + b_ctor = false; + b_dtor = false; + c_ctor = false; + c_dtor = false; +} + +int main() +{ + /////////////////////////////////////////////////////////////////////////// + { + // Client to A, instance of A + clientA obj(hpx::components::new_(hpx::find_here())); + + HPX_TEST_EQ(obj.test0(), "A"); + } + + // Make sure AGAS kicked in... + hpx::agas::garbage_collect(); + hpx::this_thread::yield(); + + HPX_TEST(a_ctor); + HPX_TEST(a_dtor); + HPX_TEST(!b_ctor); + HPX_TEST(!b_dtor); + HPX_TEST(!c_ctor); + HPX_TEST(!c_dtor); + + reset_globals(); + + /////////////////////////////////////////////////////////////////////////// + { + // Client to A, instance of C + clientA obj(hpx::components::new_(hpx::find_here())); + + HPX_TEST_EQ(obj.test0(), "C"); + } + + // Make sure AGAS kicked in... + hpx::agas::garbage_collect(); + hpx::this_thread::yield(); + + HPX_TEST(a_ctor); + HPX_TEST(a_dtor); + HPX_TEST(b_ctor); + HPX_TEST(b_dtor); + HPX_TEST(c_ctor); + HPX_TEST(c_dtor); + + reset_globals(); + + /////////////////////////////////////////////////////////////////////////// + { + // Client to B, instance of B + clientB obj(hpx::components::new_(hpx::find_here())); + + HPX_TEST_EQ(obj.test1(), "B"); + } + + // Make sure AGAS kicked in... + hpx::agas::garbage_collect(); + hpx::this_thread::yield(); + + HPX_TEST(!a_ctor); + HPX_TEST(!a_dtor); + HPX_TEST(b_ctor); + HPX_TEST(b_dtor); + HPX_TEST(!c_ctor); + HPX_TEST(!c_dtor); + + reset_globals(); + + /////////////////////////////////////////////////////////////////////////// + { + // Client to B, instance of C + clientB obj(hpx::components::new_(hpx::find_here())); + + HPX_TEST_EQ(obj.test1(), "C"); + } + + // Make sure AGAS kicked in... + hpx::agas::garbage_collect(); + hpx::this_thread::yield(); + + HPX_TEST(a_ctor); + HPX_TEST(a_dtor); + HPX_TEST(b_ctor); + HPX_TEST(b_dtor); + HPX_TEST(c_ctor); + HPX_TEST(c_dtor); + + reset_globals(); + + /////////////////////////////////////////////////////////////////////////// + { + // Client to C, instance of C + clientC obj(hpx::components::new_(hpx::find_here())); + + HPX_TEST_EQ(obj.test0(), "C"); + HPX_TEST_EQ(obj.test1(), "C"); + HPX_TEST_EQ(obj.test2(), "C"); + } + + // Make sure AGAS kicked in... + hpx::agas::garbage_collect(); + hpx::this_thread::yield(); + + HPX_TEST(a_ctor); + HPX_TEST(a_dtor); + HPX_TEST(b_ctor); + HPX_TEST(b_dtor); + HPX_TEST(c_ctor); + HPX_TEST(c_dtor); + + reset_globals(); + + return 0; +}