Skip to content

Commit

Permalink
Merge pull request #6431 from isidorostsa/include_stdexec
Browse files Browse the repository at this point in the history
Integrate NVIDIA's S/R implementation into HPX
  • Loading branch information
hkaiser authored Aug 26, 2024
2 parents d9b5f6c + 16f0245 commit bd43586
Show file tree
Hide file tree
Showing 118 changed files with 6,143 additions and 1,019 deletions.
27 changes: 26 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright (c) 2020 Mikael Simberg
# Copyright (c) 2007-2024 Hartmut Kaiser
# Copyright (c) 2011-2014 Thomas Heller
# Copyright (c) 2024 Isidoros Tsaousis-Seiras
# Copyright (c) 2007-2008 Chirag Dekate
# Copyright (c) 2011 Bryce Lelbach
# Copyright (c) 2011 Vinay C Amatya
Expand Down Expand Up @@ -578,6 +579,27 @@ if(HPX_WITH_CUDA AND HPX_WITH_HIP)
)
endif()

# ## HPX STDEXEC configuration ##

hpx_option(
HPX_WITH_STDEXEC BOOL
"Use STDEXEC executors instead of native HPX.(default: OFF)" OFF
CATEGORY "Executor"
ADVANCED
)

hpx_option(
HPX_WITH_FETCH_STDEXEC BOOL "Use FetchContent to fetch STDEXEC.(default: ON)"
ON
CATEGORY "Executor"
ADVANCED
)

hpx_option(
HPX_WITH_STDEXEC_TAG STRING "STDEXEC repository tag or branch" "main"
CATEGORY "Executor"
)

# ##############################################################################
# HPX SYCL configuration
# ##############################################################################
Expand Down Expand Up @@ -1346,7 +1368,7 @@ if(HPX_WITH_NETWORKING AND HPX_WITH_PARCELPORT_LCI)
endif()
endif()

# External libraries/frameworks used by sme of the examples and benchmarks
# External libraries/frameworks used by some of the examples and benchmarks
hpx_option(
HPX_WITH_EXAMPLES_OPENMP BOOL
"Enable examples requiring OpenMP support (default: OFF)." OFF
Expand Down Expand Up @@ -2265,6 +2287,9 @@ if(HPX_WITH_CUDA OR HPX_WITH_HIP)
hpx_add_config_define(HPX_HAVE_GPU_SUPPORT)
endif()

# Setup NVIDIA's stdexec if requested
include(HPX_SetupStdexec)

if(HPX_WITH_SANITIZERS)
hpx_add_config_define(HPX_HAVE_SANITIZERS)
endif()
Expand Down
39 changes: 39 additions & 0 deletions cmake/FindStdexec.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright (c) 2024 Isidoros Tsaousis-Seiras
#
# 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)

if(NOT TARGET STDEXEC::stdexec)
if(STDEXEC_ROOT AND NOT Stdexec_ROOT)
set(Stdexec_ROOT
${STDEXEC_ROOT}
CACHE PATH "stdexec base directory"
)
unset(STDEXEC_ROOT CACHE)
endif()

find_path(Stdexec_INCLUDE_DIR stdexec HINTS ${Stdexec_ROOT})
message(STATUS "stdexec include dir: ${Stdexec_INCLUDE_DIR}")
if(Stdexec_INCLUDE_DIR)
file(TO_CMAKE_PATH ${Stdexec_INCLUDE_DIR} Stdexec_INCLUDE_DIR)
else()
message(FATAL_ERROR "stdexec not found")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
Stdexec
REQUIRED_VARS Stdexec_INCLUDE_DIR
FOUND_VAR Stdexec_FOUND
VERSION_VAR Stdexec_VERSION
FAIL_MESSAGE "stdexec not found"
)

add_library(STDEXEC::stdexec INTERFACE IMPORTED)
target_include_directories(
STDEXEC::stdexec SYSTEM INTERFACE ${Stdexec_INCLUDE_DIR}
)

mark_as_advanced(Stdexec_INCLUDE_DIR Stdexec_ROOT)
endif()
9 changes: 9 additions & 0 deletions cmake/HPX_AddConfigTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,15 @@ function(hpx_check_for_cxx20_std_bit_cast)
)
endfunction()

# ##############################################################################
function(hpx_check_for_cxx20_std_identity)
add_hpx_config_test(
HPX_WITH_CXX20_STD_IDENTITY
SOURCE cmake/tests/cxx20_std_identity.cpp
FILE ${ARGN}
)
endfunction()

# ##############################################################################
function(hpx_check_for_cxx20_constexpr_destructor)
add_hpx_config_test(
Expand Down
2 changes: 2 additions & 0 deletions cmake/HPX_PerformCxxFeatureTests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ function(hpx_perform_cxx_feature_tests)

hpx_check_for_cxx20_std_bit_cast(DEFINITIONS HPX_HAVE_CXX20_STD_BIT_CAST)

hpx_check_for_cxx20_std_identity(DEFINITIONS HPX_HAVE_CXX20_STD_IDENTITY)

hpx_check_for_cxx20_constexpr_destructor(
DEFINITIONS HPX_HAVE_CXX20_CONSTEXPR_DESTRUCTOR
)
Expand Down
104 changes: 104 additions & 0 deletions cmake/HPX_SetupStdexec.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright (c) 2024 Isidoros Tsaousis-Seiras
#
# 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)

if(HPX_WITH_STDEXEC)
if(HPX_WITH_CXX_STANDARD LESS 20)
hpx_error("HPX_WITH_STDEXEC Requires C++20 or later.")
endif()
if(NOT HPX_WITH_CXX20_STD_IDENTITY)
hpx_error("HPX_WITH_STDEXEC Requires std::identity.")
endif()
if(MSVC)
hpx_error("HPX_WITH_STDEXEC is not available on MSVC.")
endif()
endif()

if(STDEXEC_ROOT AND NOT Stdexec_ROOT)
set(Stdexec_ROOT ${STDEXEC_ROOT})
# remove STDEXEC_ROOT from the cache
unset(STDEXEC_ROOT CACHE)
endif()

if(HPX_WITH_STDEXEC)
# prefer HPX_WITH_FETCH_STDEXEC by default
if(Stdexec_ROOT AND HPX_WITH_FETCH_STDEXEC)
hpx_warn(
"Both Stdexec_ROOT and HPX_WITH_FETCH_STDEXEC are provided. HPX_WITH_FETCH_STDEXEC will take precedence."
)
endif()

hpx_add_config_define(HPX_HAVE_STDEXEC)

if(HPX_WITH_FETCH_STDEXEC)
hpx_info(
"HPX_WITH_FETCH_STDEXEC=${HPX_WITH_FETCH_STDEXEC}, Stdexec will be fetched using CMake's FetchContent and installed alongside HPX (HPX_WITH_STDEXEC_TAG=${HPX_WITH_STDEXEC_TAG})"
)
if(UNIX)
include(FetchContent)
fetchcontent_declare(
Stdexec
GIT_REPOSITORY https://github.com/NVIDIA/stdexec.git
GIT_TAG ${HPX_WITH_STDEXEC_TAG}
)

fetchcontent_getproperties(Stdexec)
if(NOT Stdexec_POPULATED)
fetchcontent_populate(Stdexec)
endif()
set(Stdexec_ROOT ${stdexec_SOURCE_DIR})

add_library(Stdexec INTERFACE)
target_include_directories(
Stdexec INTERFACE $<BUILD_INTERFACE:${stdexec_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

install(
TARGETS Stdexec
EXPORT HPXStdexecTarget
COMPONENT core
)

install(
DIRECTORY ${Stdexec_ROOT}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT core
FILES_MATCHING
PATTERN "*.hpp"
)

export(
TARGETS Stdexec
NAMESPACE Stdexec::
FILE "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${HPX_PACKAGE_NAME}/HPXStdexecTarget.cmake"
)

install(
EXPORT HPXStdexecTarget
NAMESPACE Stdexec::
FILE HPXStdexecTarget.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${HPX_PACKAGE_NAME}
COMPONENT cmake
)

# TODO: Enforce a single spelling
add_library(Stdexec::Stdexec ALIAS Stdexec)
add_library(STDEXEC::stdexec ALIAS Stdexec)

endif()

else()
find_package(Stdexec REQUIRED)

if(Stdexec_FOUND)
hpx_add_config_define(HPX_HAVE_STDEXEC)
else()
hpx_error(
"Stdexec could not be found, please specify Stdexec_ROOT to point to the correct location or enable HPX_WITH_FETCH_STDEXEC"
)
endif()
endif()
endif()
14 changes: 14 additions & 0 deletions cmake/templates/HPXConfig.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ else()
include(HPX_SetupAsio)
endif()


# Stdexec can be installed by HPX or externally installed. In the first case we use
# exported targets, in the second we find Stdexec again using find_package.
if(HPX_WITH_STDEXEC)
if(HPX_WITH_FETCH_STDEXEC)
include("${CMAKE_CURRENT_LIST_DIR}/HPXStdexecTarget.cmake")
else()
set(Stdexec_ROOT "@Stdexec_ROOT@")
include(HPX_SetupStdexec)
endif()
endif()



# NLohnmann JSON can be installed by HPX or externally installed. In the first
# case we use exported targets, in the second we find JSON again using
# find_package.
Expand Down
14 changes: 14 additions & 0 deletions cmake/tests/cxx20_std_identity.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2024 Isidoros Tsaousis-Seiras
//
// 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)

// test for availability of std::identity

#include <functional>

int main()
{
auto f = std::identity{}(3);
}
4 changes: 4 additions & 0 deletions libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ if(HPX_WITH_ITTNOTIFY)
target_link_libraries(hpx_core PUBLIC Amplifier::amplifier)
endif()

if(TARGET STDEXEC::stdexec)
target_link_libraries(hpx_core INTERFACE STDEXEC::stdexec)
endif()

if(HPX_WITH_PARCELPORT_GASNET AND GASNET_LIBRARY_DIRS)
target_link_directories(hpx_core PUBLIC ${GASNET_LIBRARY_DIRS})
endif()
Expand Down
76 changes: 53 additions & 23 deletions libs/core/algorithms/include/hpx/parallel/algorithms/rotate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
// 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)

/// \file hpx/parallel/algorithms/rotate.hpp
/// \page hpx::rotate, hpx::rotate_copy
/// \headerfile hpx/algorithm.hpp
/// \file hpx/parallel/algorithms/rotate.hpp

#pragma once

Expand Down Expand Up @@ -266,27 +265,58 @@ namespace hpx::parallel {

detail::reverse<FwdIter> r;

return hpx::dataflow(
hpx::launch::sync,
[=](auto&& f1, auto&& f2) mutable {
// propagate exceptions, if appropriate
constexpr bool handle_futures =
hpx::traits::is_future_v<decltype((f1))> &&
hpx::traits::is_future_v<decltype((f2))>;

if constexpr (handle_futures)
{
f1.get();
f2.get();
}

r.call(p(hpx::execution::non_task), first, last);

std::advance(first, size_right);
return util::in_out_result<FwdIter, Sent>{first, last};
},
r.call(left_policy, first, new_first),
r.call(right_policy, new_first, last));
auto&& process = [=](auto&& f1, auto&& f2) mutable {
// propagate exceptions, if appropriate
constexpr bool handle_futures =
hpx::traits::is_future_v<decltype((f1))> &&
hpx::traits::is_future_v<decltype((f2))>;

if constexpr (handle_futures)
{
f1.get();
f2.get();
}

r.call(p(hpx::execution::non_task), first, last);

std::advance(first, size_right);
return util::in_out_result<FwdIter, Sent>{first, last};
};

using rcall_left_t =
decltype(r.call(left_policy, first, new_first));
using rcall_right_t =
decltype(r.call(right_policy, new_first, last));

// Sanity check
static_assert(std::is_same_v<rcall_left_t, rcall_right_t>);

constexpr bool handle_senders =
hpx::execution::experimental::is_sender_v<rcall_left_t>;
constexpr bool handle_futures =
hpx::traits::is_future_v<rcall_left_t>;
constexpr bool handle_both = handle_senders && handle_futures;

static_assert(handle_senders || handle_futures,
"the reverse operation must return either a sender or a "
"future");

// Futures pass the concept check for senders, so if something is
// both a future and a sender we treat it as a future.
if constexpr (handle_futures || handle_both)
{
return hpx::dataflow(hpx::launch::sync, std::move(process),
r.call(left_policy, first, new_first),
r.call(right_policy, new_first, last));
}
else if constexpr (handle_senders && !handle_both)
{
return hpx::execution::experimental::then(
hpx::execution::experimental::when_all(
r.call(left_policy, first, new_first),
r.call(right_policy, new_first, last)),
std::move(process));
}
}

template <typename IterPair>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
#include <hpx/futures/future.hpp>
#include <hpx/type_support/unused.hpp>

#if defined(HPX_HAVE_STDEXEC)
// For is_sender
#include <hpx/execution_base/completion_signatures.hpp>
#endif

#include <type_traits>
#include <utility>

Expand Down
Loading

0 comments on commit bd43586

Please sign in to comment.