diff --git a/libs/core/allocator_support/CMakeLists.txt b/libs/core/allocator_support/CMakeLists.txt index 1e5bcb0f10ab..9464a7dd3392 100644 --- a/libs/core/allocator_support/CMakeLists.txt +++ b/libs/core/allocator_support/CMakeLists.txt @@ -42,7 +42,7 @@ set(allocator_support_compat_headers ) # cmake-format: on -set(allocator_support_sources) +set(allocator_support_sources thread_local_caching_allocator.cpp) include(HPX_AddModule) add_hpx_module( @@ -52,6 +52,7 @@ add_hpx_module( HEADERS ${allocator_support_headers} COMPAT_HEADERS ${allocator_support_compat_headers} DEPENDENCIES hpx_dependencies_allocator - MODULE_DEPENDENCIES hpx_concepts hpx_config hpx_preprocessor hpx_type_support + MODULE_DEPENDENCIES hpx_assertion hpx_concepts hpx_config hpx_preprocessor + hpx_type_support CMAKE_SUBDIRS examples tests ) diff --git a/libs/core/allocator_support/include/hpx/allocator_support/thread_local_caching_allocator.hpp b/libs/core/allocator_support/include/hpx/allocator_support/thread_local_caching_allocator.hpp index f389213a8b53..2b3deae46d86 100644 --- a/libs/core/allocator_support/include/hpx/allocator_support/thread_local_caching_allocator.hpp +++ b/libs/core/allocator_support/include/hpx/allocator_support/thread_local_caching_allocator.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2023 Hartmut Kaiser +// Copyright (c) 2023-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -8,11 +8,13 @@ #include #include +#include #include +#include +#include #include #include -#include #include #include @@ -21,14 +23,42 @@ namespace hpx::util { #if defined(HPX_ALLOCATOR_SUPPORT_HAVE_CACHING) && \ !((defined(HPX_HAVE_CUDA) && defined(__CUDACC__)) || \ defined(HPX_HAVE_HIP)) + + namespace detail { + + HPX_CORE_EXPORT void init_allocator_cache( + std::size_t, std::function&& clear_cache); + HPX_CORE_EXPORT std::pair allocate_from_cache( + std::size_t) noexcept; + [[nodiscard]] HPX_CORE_EXPORT bool cache_empty(std::size_t) noexcept; + HPX_CORE_EXPORT void return_to_cache( + std::size_t, void* p, std::size_t n); + + // maximal number of caches [0...max) + inline constexpr int max_number_of_caches = 16; + + /////////////////////////////////////////////////////////////////////// + constexpr int next_power_of_two(std::int64_t n) noexcept + { + int i = 0; + for (--n; n > 0; n >>= 1) + { + ++i; + } + return i; + } + } // namespace detail + /////////////////////////////////////////////////////////////////////////// template > struct thread_local_caching_allocator { HPX_NO_UNIQUE_ADDRESS Allocator alloc; + private: using traits = std::allocator_traits; + public: using value_type = typename traits::value_type; using pointer = typename traits::pointer; using const_pointer = typename traits::const_pointer; @@ -50,86 +80,38 @@ namespace hpx::util { using propagate_on_container_swap = typename traits::propagate_on_container_swap; - private: - struct allocated_cache + explicit thread_local_caching_allocator( + Allocator const& alloc = Allocator{}) noexcept(noexcept(std:: + is_nothrow_copy_constructible_v)) + : alloc(alloc) { - explicit allocated_cache(Allocator const& a) noexcept( - noexcept(std::is_nothrow_copy_constructible_v)) - : alloc(a) - { - } - - allocated_cache(allocated_cache const&) = delete; - allocated_cache(allocated_cache&&) = delete; - allocated_cache& operator=(allocated_cache const&) = delete; - allocated_cache& operator=(allocated_cache&&) = delete; - - ~allocated_cache() - { - clear_cache(); - } - - pointer allocate(size_type n) - { - pointer p; - if (data.empty()) + // Note: capturing the allocator will be ok only as long as it + // doesn't have any state as this lambda will be possibly called + // very late during destruction of the thread_local cache. + static_assert(std::is_empty_v, + "Please don't use allocators with state in conjunction with " + "the thread_local_caching_allocator"); + + constexpr std::size_t num_cache = + detail::next_power_of_two(sizeof(T)); + + static_assert(num_cache < detail::max_number_of_caches, + "This allocator does not support allocating objects larger " + "than 2^16 bytes"); + + auto f = [=]() mutable { + while (!detail::cache_empty(num_cache)) { - p = traits::allocate(alloc, n); - if (p == nullptr) + auto [p, n] = detail::allocate_from_cache(num_cache); + if (p != nullptr) { - throw std::bad_alloc(); + traits::deallocate(const_cast(alloc), + static_cast(p), n); } } - else - { - p = data.top().first; - data.pop(); - } - - ++allocated; - return p; - } + }; - void deallocate(pointer p, size_type n) noexcept - { - data.push(std::make_pair(p, n)); - if (++deallocated > 2 * (allocated + 16)) - { - clear_cache(); - allocated = 0; - deallocated = 0; - } - } - - private: - void clear_cache() noexcept - { - while (!data.empty()) - { - traits::deallocate( - alloc, data.top().first, data.top().second); - data.pop(); - } - } - - HPX_NO_UNIQUE_ADDRESS Allocator alloc; - std::stack> data; - std::size_t allocated = 0; - std::size_t deallocated = 0; - }; - - allocated_cache& cache() - { - thread_local allocated_cache allocated_data(alloc); - return allocated_data; - } - - public: - explicit thread_local_caching_allocator( - Allocator const& alloc = Allocator{}) noexcept(noexcept(std:: - is_nothrow_copy_constructible_v)) - : alloc(alloc) - { + detail::init_allocator_cache(num_cache, HPX_MOVE(f)); } template @@ -154,16 +136,32 @@ namespace hpx::util { [[nodiscard]] pointer allocate(size_type n, void const* = nullptr) { - if (max_size() < n) + constexpr std::size_t num_cache = + detail::next_power_of_two(sizeof(T)); + std::size_t N = n * (1ull << num_cache); + + if (max_size() < N) { throw std::bad_array_new_length(); } - return cache().allocate(n); + + auto [p, _] = detail::allocate_from_cache(num_cache); + if (p == nullptr) + { + p = traits::allocate(alloc, N); + if (p == nullptr) + { + throw std::bad_alloc(); + } + } + return static_cast(p); } - void deallocate(pointer p, size_type n) noexcept + void deallocate(pointer p, size_type n) { - cache().deallocate(p, n); + constexpr std::size_t num_cache = + detail::next_power_of_two(sizeof(T)); + detail::return_to_cache(num_cache, p, n * (1ull << num_cache)); } [[nodiscard]] constexpr size_type max_size() noexcept diff --git a/libs/core/allocator_support/src/thread_local_caching_allocator.cpp b/libs/core/allocator_support/src/thread_local_caching_allocator.cpp new file mode 100644 index 000000000000..e030ca3c5ed1 --- /dev/null +++ b/libs/core/allocator_support/src/thread_local_caching_allocator.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2023-2024 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 + +#if defined(HPX_ALLOCATOR_SUPPORT_HAVE_CACHING) && \ + !((defined(HPX_HAVE_CUDA) && defined(__CUDACC__)) || \ + defined(HPX_HAVE_HIP)) + +#include +#include +#include + +#include +#include +#include +#include + +namespace hpx::util::detail { + + /////////////////////////////////////////////////////////////////////////// + struct allocated_cache + { + explicit allocated_cache() noexcept = default; + + void init(std::function&& clear) + { + if (!clear_cache) // initialize once + { + clear_cache = HPX_MOVE(clear); + util::reinit_register(std::function(), clear_cache); + } + } + + allocated_cache(allocated_cache const&) = delete; + allocated_cache(allocated_cache&&) = delete; + allocated_cache& operator=(allocated_cache const&) = delete; + allocated_cache& operator=(allocated_cache&&) = delete; + + ~allocated_cache() + { + if (clear_cache) + { + clear_cache(); + } + } + + std::pair allocate() noexcept + { + std::pair p{nullptr, 0}; + if (!data.empty()) + { + p = data.top(); + data.pop(); + + ++allocated; + } + return p; + } + + void deallocate(void* p, std::size_t n) + { + data.emplace(p, n); + if (++deallocated > 2 * (allocated + 16)) + { + if (clear_cache) + { + clear_cache(); + } + + allocated = 0; + deallocated = 0; + } + } + + [[nodiscard]] bool empty() const noexcept + { + return data.empty(); + } + + private: + std::stack> data; + std::size_t allocated = 0; + std::size_t deallocated = 0; + std::function clear_cache; + }; + + /////////////////////////////////////////////////////////////////////////// + allocated_cache& cache(std::size_t n) + { + HPX_ASSERT(n < max_number_of_caches); + + thread_local allocated_cache allocated_data[max_number_of_caches]; + return allocated_data[n]; + } + + void init_allocator_cache( + std::size_t n, std::function&& clear_cache) + { + cache(n).init(HPX_MOVE(clear_cache)); + } + + std::pair allocate_from_cache(std::size_t n) noexcept + { + return cache(n).allocate(); + } + + void return_to_cache(std::size_t n, void* p, std::size_t const size) + { + cache(n).deallocate(p, size); + } + + bool cache_empty(std::size_t n) noexcept + { + return cache(n).empty(); + } +} // namespace hpx::util::detail + +#endif diff --git a/libs/core/async_combinators/include/hpx/async_combinators/when_all.hpp b/libs/core/async_combinators/include/hpx/async_combinators/when_all.hpp index 58d425b982d4..8fff887a6276 100644 --- a/libs/core/async_combinators/include/hpx/async_combinators/when_all.hpp +++ b/libs/core/async_combinators/include/hpx/async_combinators/when_all.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // Copyright (c) 2013 Agustin Berge // Copyright (c) 2017 Denis Blank // @@ -201,14 +201,16 @@ namespace hpx::lcos::detail { return async_visit_future(HPX_FORWARD(T, current)); } + // clang-format off template auto operator()(hpx::util::async_traverse_detach_tag, T&& current, N&& next) -> decltype(async_detach_future(HPX_FORWARD(T, current), - HPX_FORWARD(N, next))) + HPX_FORWARD(N, next))) { return async_detach_future( HPX_FORWARD(T, current), HPX_FORWARD(N, next)); } + // clang-format on template void operator()(hpx::util::async_traverse_complete_tag, T&& pack) diff --git a/libs/core/futures/include/hpx/futures/packaged_continuation.hpp b/libs/core/futures/include/hpx/futures/packaged_continuation.hpp index f337114d1d23..a7af9ea93e20 100644 --- a/libs/core/futures/include/hpx/futures/packaged_continuation.hpp +++ b/libs/core/futures/include/hpx/futures/packaged_continuation.hpp @@ -540,7 +540,7 @@ struct hpx::traits::detail::shared_state_allocator< namespace hpx::lcos::detail { template - inline traits::detail::shared_state_ptr_t> + traits::detail::shared_state_ptr_t> unwrap_impl_alloc(Allocator const& a, Future&& future, error_code& /*ec*/) { using base_allocator = Allocator; @@ -573,15 +573,15 @@ namespace hpx::lcos::detail { } template - inline traits::detail::shared_state_ptr_t> + traits::detail::shared_state_ptr_t> unwrap_alloc(Allocator const& a, Future&& future, error_code& ec) { return unwrap_impl_alloc(a, HPX_FORWARD(Future, future), ec); } template - inline traits::detail::shared_state_ptr_t> - unwrap(Future&& future, error_code& ec) + traits::detail::shared_state_ptr_t> unwrap( + Future&& future, error_code& ec) { using allocator_type = hpx::util::thread_local_caching_allocator>; diff --git a/libs/core/init_runtime_local/src/init_runtime_local.cpp b/libs/core/init_runtime_local/src/init_runtime_local.cpp index ad669d393721..66907b6afd0b 100644 --- a/libs/core/init_runtime_local/src/init_runtime_local.cpp +++ b/libs/core/init_runtime_local/src/init_runtime_local.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -407,6 +408,9 @@ namespace hpx { hpx::parallel::execution::detail::set_get_os_thread_count( []() { return hpx::get_os_thread_count(); }); + // instantiate the interface function initialization objects + util::static_reinit_init(); + #if defined(HPX_NATIVE_MIC) || defined(__bgq__) || defined(__bgqion__) unsetenv("LANG"); unsetenv("LC_CTYPE"); diff --git a/libs/core/static_reinit/CMakeLists.txt b/libs/core/static_reinit/CMakeLists.txt index 598f3534b1c7..f3abd75ec536 100644 --- a/libs/core/static_reinit/CMakeLists.txt +++ b/libs/core/static_reinit/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2019 The STE||AR-Group +# Copyright (c) 2019-2024 The STE||AR-Group # # SPDX-License-Identifier: BSL-1.0 # Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -28,7 +28,6 @@ add_hpx_module( SOURCES ${static_reinit_sources} HEADERS ${static_reinit_headers} COMPAT_HEADERS ${static_reinit_compat_headers} - MODULE_DEPENDENCIES hpx_config hpx_assertion hpx_concurrency hpx_functional - hpx_type_support + MODULE_DEPENDENCIES hpx_config hpx_assertion hpx_concurrency hpx_type_support CMAKE_SUBDIRS examples tests ) diff --git a/libs/core/static_reinit/include/hpx/static_reinit/reinitializable_static.hpp b/libs/core/static_reinit/include/hpx/static_reinit/reinitializable_static.hpp index 3058bd06b5fb..692db6f70594 100644 --- a/libs/core/static_reinit/include/hpx/static_reinit/reinitializable_static.hpp +++ b/libs/core/static_reinit/include/hpx/static_reinit/reinitializable_static.hpp @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include #include // for placement new @@ -77,7 +77,7 @@ namespace hpx::util { static void default_constructor() { default_construct(); - reinit_register(&reinitializable_static::default_construct, + util::reinit_register(&reinitializable_static::default_construct, &reinitializable_static::destruct); } @@ -85,7 +85,7 @@ namespace hpx::util { static void value_constructor(U const* pv) { value_construct(*pv); - reinit_register( + util::reinit_register( hpx::bind_front( &reinitializable_static::value_construct, *pv), &reinitializable_static::destruct); diff --git a/libs/core/static_reinit/include/hpx/static_reinit/static_reinit.hpp b/libs/core/static_reinit/include/hpx/static_reinit/static_reinit.hpp index a55825da57c2..71d3d102335a 100644 --- a/libs/core/static_reinit/include/hpx/static_reinit/static_reinit.hpp +++ b/libs/core/static_reinit/include/hpx/static_reinit/static_reinit.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -7,21 +7,12 @@ #pragma once #include -#include +#include namespace hpx::util { /////////////////////////////////////////////////////////////////////////// - // This is a global API allowing to register functions to be called before - // the runtime system is about to start and after the runtime system has - // been terminated. This is used to initialize/reinitialize all - // singleton instances. - HPX_CORE_EXPORT void reinit_register(hpx::function const& construct, - hpx::function const& destruct); - - // Invoke all globally registered construction functions - HPX_CORE_EXPORT void reinit_construct(); - - // Invoke all globally registered destruction functions - HPX_CORE_EXPORT void reinit_destruct(); + // initialize static_reinit interface function wrappers + HPX_CORE_EXPORT struct static_reinit_interface_functions& + static_reinit_init(); } // namespace hpx::util diff --git a/libs/core/static_reinit/src/static_reinit.cpp b/libs/core/static_reinit/src/static_reinit.cpp index 0cac134523f1..b14cbceff025 100644 --- a/libs/core/static_reinit/src/static_reinit.cpp +++ b/libs/core/static_reinit/src/static_reinit.cpp @@ -1,20 +1,21 @@ -// Copyright (c) 2007-2023 Hartmut Kaiser +// Copyright (c) 2007-2024 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 #include #include -namespace hpx::util { +namespace hpx::util::detail { /////////////////////////////////////////////////////////////////////////// struct reinit_functions_storage @@ -24,8 +25,8 @@ namespace hpx::util { // register_functions function is called from within std::call_once using mutex_type = util::spinlock; - using construct_type = hpx::function; - using destruct_type = hpx::function; + using construct_type = std::function; + using destruct_type = std::function; using value_type = std::pair; using reinit_functions_type = std::vector; @@ -75,21 +76,41 @@ namespace hpx::util { // the runtime system is about to start and after the runtime system has // been terminated. This is used to initialize/reinitialize all singleton // instances. - void reinit_register(hpx::function const& construct, - hpx::function const& destruct) + void reinit_register_impl(std::function const& construct, + std::function const& destruct) { reinit_functions_storage::get().register_functions(construct, destruct); } // Invoke all globally registered construction functions - void reinit_construct() + void reinit_construct_impl() { reinit_functions_storage::get().construct_all(); } // Invoke all globally registered destruction functions - void reinit_destruct() + void reinit_destruct_impl() { reinit_functions_storage::get().destruct_all(); } +} // namespace hpx::util::detail + +namespace hpx::util { + + // initialize AGAS interface function pointers in components_base module + struct HPX_CORE_EXPORT static_reinit_interface_functions + { + static_reinit_interface_functions() + { + detail::reinit_register = &detail::reinit_register_impl; + detail::reinit_construct = &detail::reinit_construct_impl; + detail::reinit_destruct = &detail::reinit_destruct_impl; + } + }; + + static_reinit_interface_functions& static_reinit_init() + { + static static_reinit_interface_functions static_reinit_init_; + return static_reinit_init_; + } } // namespace hpx::util diff --git a/libs/core/type_support/CMakeLists.txt b/libs/core/type_support/CMakeLists.txt index 5aacf92de760..e4ba1ee8ac32 100644 --- a/libs/core/type_support/CMakeLists.txt +++ b/libs/core/type_support/CMakeLists.txt @@ -5,8 +5,10 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) set(type_support_headers + hpx/type_support/detail/static_reinit_functions.hpp hpx/type_support/detail/with_result_of.hpp hpx/type_support/detail/wrap_int.hpp + hpx/type_support/static_reinit_interface.hpp hpx/type_support/assert_owns_lock.hpp hpx/type_support/bit_cast.hpp hpx/type_support/construct_at.hpp @@ -56,7 +58,9 @@ set(type_support_compat_headers ) # cmake-format: on -set(type_support_sources) +set(type_support_sources detail/static_reinit_functions.cpp + static_reinit_interface.cpp +) include(HPX_AddModule) add_hpx_module( diff --git a/libs/core/type_support/include/hpx/type_support/detail/static_reinit_functions.hpp b/libs/core/type_support/include/hpx/type_support/detail/static_reinit_functions.hpp new file mode 100644 index 000000000000..763a58d3097d --- /dev/null +++ b/libs/core/type_support/include/hpx/type_support/detail/static_reinit_functions.hpp @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2024 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 + +namespace hpx::util::detail { + + extern HPX_CORE_EXPORT void (*reinit_register)( + std::function const& construct, + std::function const& destruct); + + // Invoke all globally registered construction functions + extern HPX_CORE_EXPORT void (*reinit_construct)(); + + // Invoke all globally registered destruction functions + extern HPX_CORE_EXPORT void (*reinit_destruct)(); +} // namespace hpx::util::detail diff --git a/libs/core/type_support/include/hpx/type_support/static_reinit_interface.hpp b/libs/core/type_support/include/hpx/type_support/static_reinit_interface.hpp new file mode 100644 index 000000000000..31e287f886e4 --- /dev/null +++ b/libs/core/type_support/include/hpx/type_support/static_reinit_interface.hpp @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2024 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 + +namespace hpx::util { + + /////////////////////////////////////////////////////////////////////////// + // This is a global API allowing to register functions to be called before + // the runtime system is about to start and after the runtime system has + // been terminated. This is used to initialize/reinitialize all + // singleton instances. + HPX_CORE_EXPORT void reinit_register(std::function const& construct, + std::function const& destruct); + + // Invoke all globally registered construction functions + HPX_CORE_EXPORT void reinit_construct(); + + // Invoke all globally registered destruction functions + HPX_CORE_EXPORT void reinit_destruct(); +} // namespace hpx::util diff --git a/libs/core/type_support/src/detail/static_reinit_functions.cpp b/libs/core/type_support/src/detail/static_reinit_functions.cpp new file mode 100644 index 000000000000..cfb642d379c8 --- /dev/null +++ b/libs/core/type_support/src/detail/static_reinit_functions.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2007-2024 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 + +namespace hpx::util::detail { + + void (*reinit_register)(std::function const& construct, + std::function const& destruct) = nullptr; + + // Invoke all globally registered construction functions + void (*reinit_construct)() = nullptr; + + // Invoke all globally registered destruction functions + void (*reinit_destruct)() = nullptr; +} // namespace hpx::util::detail diff --git a/libs/core/type_support/src/static_reinit_interface.cpp b/libs/core/type_support/src/static_reinit_interface.cpp new file mode 100644 index 000000000000..cadefddb18a4 --- /dev/null +++ b/libs/core/type_support/src/static_reinit_interface.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2007-2024 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 + +namespace hpx::util { + + // This is a global API allowing to register functions to be called before + // the runtime system is about to start and after the runtime system has + // been terminated. This is used to initialize/reinitialize all singleton + // instances. + void reinit_register(std::function const& construct, + std::function const& destruct) + { + detail::reinit_register(construct, destruct); + } + + // Invoke all globally registered construction functions + void reinit_construct() + { + detail::reinit_construct(); + } + + // Invoke all globally registered destruction functions + void reinit_destruct() + { + detail::reinit_destruct(); + } +} // namespace hpx::util diff --git a/libs/full/init_runtime/src/hpx_init.cpp b/libs/full/init_runtime/src/hpx_init.cpp index eb28a983f2f0..10a52b865611 100644 --- a/libs/full/init_runtime/src/hpx_init.cpp +++ b/libs/full/init_runtime/src/hpx_init.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -818,6 +819,7 @@ namespace hpx { agas::runtime_components_init(); components::counter_init(); #endif + util::static_reinit_init(); #if defined(HPX_NATIVE_MIC) || defined(__bgq__) || defined(__bgqion__) unsetenv("LANG");