From 673b484cdb3f9fe0f33184250ffe555e16728278 Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Mon, 13 Jan 2025 16:45:36 +0900 Subject: [PATCH 01/12] Add KokkosFFT::initialize and KokkosFFT::finalize --- fft/src/KokkosFFT_Core.cpp | 79 ++++++++++ fft/src/KokkosFFT_Core.hpp | 17 +++ fft/unit_test/Test_InitializeFinalize.cpp | 168 ++++++++++++++++++++++ fft/unit_test/Test_MainNoInit.cpp | 11 ++ 4 files changed, 275 insertions(+) create mode 100644 fft/src/KokkosFFT_Core.cpp create mode 100644 fft/src/KokkosFFT_Core.hpp create mode 100644 fft/unit_test/Test_InitializeFinalize.cpp create mode 100644 fft/unit_test/Test_MainNoInit.cpp diff --git a/fft/src/KokkosFFT_Core.cpp b/fft/src/KokkosFFT_Core.cpp new file mode 100644 index 00000000..36e5d63a --- /dev/null +++ b/fft/src/KokkosFFT_Core.cpp @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: (C) The kokkos-fft development team, see COPYRIGHT.md file +// +// SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception + +#include +#include "KokkosFFT_Core.hpp" +#include "KokkosFFT_default_types.hpp" + +namespace { +bool g_is_initialized = false; +bool g_is_finalized = false; + +bool kokkosfft_initialize_was_called() { + return KokkosFFT::is_initialized() || KokkosFFT::is_finalized(); +} +bool kokkosfft_finalize_was_called() { return KokkosFFT::is_finalized(); } + +void initialize_internal() { + KokkosFFT::Impl::initialize_host(); + KokkosFFT::Impl::initialize_device(); +} + +void finalize_internal() { + KokkosFFT::Impl::finalize_host(); + KokkosFFT::Impl::finalize_device(); +} +} // namespace + +[[nodiscard]] bool KokkosFFT::is_initialized() noexcept { + return g_is_initialized; +} + +[[nodiscard]] bool KokkosFFT::is_finalized() noexcept { return g_is_finalized; } + +void KokkosFFT::initialize() { + if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { + Kokkos::abort( + "Error: KokkosFFT::initialize() must not be called before initializing " + "Kokkos.\n"); + } + if (Kokkos::is_finalized()) { + Kokkos::abort( + "Error: KokkosFFT::initialize() must not be called after finalizing " + "Kokkos.\n"); + } + if (kokkosfft_initialize_was_called()) { + Kokkos::abort( + "Error: KokkosFFT::initialize() has already been called." + " KokkosFFT can be initialized at most once.\n"); + } + initialize_internal(); + g_is_initialized = true; +} + +void KokkosFFT::finalize() { + if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { + Kokkos::abort( + "Error: KokkosFFT::finalize() may only be called after Kokkos has been " + "initialized.\n"); + } + if (Kokkos::is_finalized()) { + Kokkos::abort( + "Error: KokkosFFT::finalize() must be called before finalizing " + "Kokkos.\n"); + } + + if (!kokkosfft_initialize_was_called()) { + Kokkos::abort( + "Error: KokkosFFT::finalize() may only be called after KokkosFFT has " + "been " + "initialized.\n"); + } + if (kokkosfft_finalize_was_called()) { + Kokkos::abort("Error: KokkosFFT::finalize() has already been called.\n"); + } + finalize_internal(); + g_is_initialized = false; + g_is_finalized = true; +} diff --git a/fft/src/KokkosFFT_Core.hpp b/fft/src/KokkosFFT_Core.hpp new file mode 100644 index 00000000..d1d5d60b --- /dev/null +++ b/fft/src/KokkosFFT_Core.hpp @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: (C) The kokkos-fft development team, see COPYRIGHT.md file +// +// SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception + +#ifndef KOKKOSFFT_CORE_HPP +#define KOKKOSFFT_CORE_HPP + +namespace KokkosFFT { +void initialize(); + +[[nodiscard]] bool is_initialized() noexcept; +[[nodiscard]] bool is_finalized() noexcept; + +void finalize(); +} // namespace KokkosFFT + +#endif diff --git a/fft/unit_test/Test_InitializeFinalize.cpp b/fft/unit_test/Test_InitializeFinalize.cpp new file mode 100644 index 00000000..e526516e --- /dev/null +++ b/fft/unit_test/Test_InitializeFinalize.cpp @@ -0,0 +1,168 @@ +#include +#include +#include "KokkosFFT_Core.hpp" + +/** + * Fixture that checks Kokkos is neither initialized nor finalized before and + * after each test. + */ +class KokkosFFTExecutionEnvironmentNeverInitialized : public ::testing::Test { + static void checkNeverInitialized() { + ASSERT_FALSE(Kokkos::is_initialized()); + ASSERT_FALSE(Kokkos::is_finalized()); + ASSERT_FALSE(KokkosFFT::is_initialized()); + ASSERT_FALSE(KokkosFFT::is_finalized()); + } + + protected: + void SetUp() override { checkNeverInitialized(); } + void TearDown() override { checkNeverInitialized(); } +}; + +namespace { +using InitializeFinalize_DeathTest = + KokkosFFTExecutionEnvironmentNeverInitialized; +using InitializeFinalize_Test = KokkosFFTExecutionEnvironmentNeverInitialized; + +TEST_F(InitializeFinalize_DeathTest, initialize) { + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + // Valid usage + EXPECT_EXIT( + { + Kokkos::initialize(); + KokkosFFT::initialize(); + KokkosFFT::finalize(); + Kokkos::finalize(); + std::exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); + + // KokkosFFT is initialized twice + EXPECT_DEATH( + { + Kokkos::initialize(); + KokkosFFT::initialize(); + KokkosFFT::initialize(); + Kokkos::finalize(); + }, + "Error: KokkosFFT::initialize\\(\\) has already been called. KokkosFFT " + "can be " + "initialized at most once\\."); + + // KokkosFFT is initialized twice after finalize + EXPECT_DEATH( + { + Kokkos::initialize(); + KokkosFFT::initialize(); + KokkosFFT::finalize(); + KokkosFFT::initialize(); + Kokkos::finalize(); + }, + "Error: KokkosFFT::initialize\\(\\) has already been called. KokkosFFT " + "can be " + "initialized at most once\\."); + + // KokkosFFT is initialized before Kokkos initialization + EXPECT_DEATH( + { + KokkosFFT::initialize(); + Kokkos::initialize(); + Kokkos::finalize(); + }, + "Error: KokkosFFT::initialize\\(\\) must not be called before " + "initializing Kokkos\\."); + + // KokkosFFT is initialized after Kokkos finalization + EXPECT_DEATH( + { + Kokkos::initialize(); + Kokkos::finalize(); + KokkosFFT::initialize(); + }, + "Error: KokkosFFT::initialize\\(\\) must not be called after finalizing " + "Kokkos\\."); +} + +TEST_F(InitializeFinalize_DeathTest, finalize) { + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + // KokkosFFT is not initialized + EXPECT_DEATH( + { + Kokkos::initialize(); + KokkosFFT::finalize(); + Kokkos::finalize(); + }, + "Error: KokkosFFT::finalize\\(\\) may only be called after KokkosFFT has " + "been initialized\\."); + + // KokkosFFT is finalized twice + EXPECT_DEATH( + { + Kokkos::initialize(); + KokkosFFT::initialize(); + KokkosFFT::finalize(); + KokkosFFT::finalize(); + Kokkos::finalize(); + }, + "Error: KokkosFFT::finalize\\(\\) has already been called\\."); + + // KokkosFFT is finalized before Kokkos initialization + EXPECT_DEATH( + { + KokkosFFT::finalize(); + Kokkos::initialize(); + Kokkos::finalize(); + }, + "Error: KokkosFFT::finalize\\(\\) may only be called after Kokkos has " + "been initialized\\."); + + // KokkosFFT is finalized after Kokkos finalization + EXPECT_DEATH( + { + Kokkos::initialize(); + KokkosFFT::initialize(); + Kokkos::finalize(); + KokkosFFT::finalize(); + }, + "Error: KokkosFFT::finalize\\(\\) must be called before finalizing " + "Kokkos\\."); +} + +TEST_F(InitializeFinalize_Test, is_initialized) { + EXPECT_EXIT( + { + Kokkos::initialize(); + bool success = true; + success &= !KokkosFFT::is_initialized(); + std::cout << "success" << success << std::endl; + KokkosFFT::initialize(); + success &= KokkosFFT::is_initialized(); + std::cout << "success" << success << std::endl; + KokkosFFT::finalize(); + success &= !KokkosFFT::is_initialized(); + std::cout << "success" << success << std::endl; + Kokkos::finalize(); + std::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(InitializeFinalize_Test, is_finalized) { + EXPECT_EXIT( + { + Kokkos::initialize(); + bool success = true; + success &= !KokkosFFT::is_finalized(); + KokkosFFT::initialize(); + success &= !KokkosFFT::is_finalized(); + KokkosFFT::finalize(); + success &= KokkosFFT::is_finalized(); + std::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); + Kokkos::finalize(); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +} // namespace diff --git a/fft/unit_test/Test_MainNoInit.cpp b/fft/unit_test/Test_MainNoInit.cpp new file mode 100644 index 00000000..8e9bb64c --- /dev/null +++ b/fft/unit_test/Test_MainNoInit.cpp @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: (C) 2022 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// SPDX-FileCopyrightText: Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights in this software. +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From e0abd00b480492641c9fe28a30a921de15543092 Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Mon, 13 Jan 2025 16:47:23 +0900 Subject: [PATCH 02/12] add device specific setup functions --- fft/src/CMakeLists.txt | 6 +++--- fft/src/KokkosFFT.hpp | 1 + fft/src/KokkosFFT_Cuda_types.hpp | 6 ++++++ fft/src/KokkosFFT_FFTW_Types.hpp | 22 ++++++++++++++++++++++ fft/src/KokkosFFT_HIP_types.hpp | 6 ++++++ fft/src/KokkosFFT_ROCM_types.hpp | 12 ++++++++++++ fft/src/KokkosFFT_SYCL_types.hpp | 6 ++++++ fft/unit_test/CMakeLists.txt | 10 +++++++++- fft/unit_test/Test_Main.cpp | 22 ++++++++-------------- 9 files changed, 73 insertions(+), 18 deletions(-) diff --git a/fft/src/CMakeLists.txt b/fft/src/CMakeLists.txt index c6d01e1c..1dc94d02 100644 --- a/fft/src/CMakeLists.txt +++ b/fft/src/CMakeLists.txt @@ -2,15 +2,15 @@ # # SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception -add_library(fft INTERFACE) +add_library(fft STATIC KokkosFFT_Core.cpp) target_link_libraries(fft - INTERFACE + PUBLIC common Kokkos::kokkos ) -target_include_directories(fft INTERFACE +target_include_directories(fft PUBLIC $ $ ) diff --git a/fft/src/KokkosFFT.hpp b/fft/src/KokkosFFT.hpp index 2df13dd8..6b035b56 100644 --- a/fft/src/KokkosFFT.hpp +++ b/fft/src/KokkosFFT.hpp @@ -10,5 +10,6 @@ #include "KokkosFFT_Helpers.hpp" #include "KokkosFFT_Plans.hpp" #include "KokkosFFT_Transform.hpp" +#include "KokkosFFT_Core.hpp" #endif diff --git a/fft/src/KokkosFFT_Cuda_types.hpp b/fft/src/KokkosFFT_Cuda_types.hpp index f5a1fe62..ac1d7cbd 100644 --- a/fft/src/KokkosFFT_Cuda_types.hpp +++ b/fft/src/KokkosFFT_Cuda_types.hpp @@ -238,7 +238,13 @@ template auto direction_type(Direction direction) { return direction == Direction::forward ? CUFFT_FORWARD : CUFFT_INVERSE; } + +static void initialize_host() {} +static void finalize_host() {} #endif + +static void initialize_device() {} +static void finalize_device() {} } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_FFTW_Types.hpp b/fft/src/KokkosFFT_FFTW_Types.hpp index 8f686577..b22efa91 100644 --- a/fft/src/KokkosFFT_FFTW_Types.hpp +++ b/fft/src/KokkosFFT_FFTW_Types.hpp @@ -138,6 +138,28 @@ struct ScopedFFTWPlan { } }; +#if defined(KOKKOS_ENABLE_OPENMP) || defined(KOKKOS_ENABLE_THREADS) +static void initialize_host() { + fftwf_init_threads(); + fftw_init_threads(); +} +static void finalize_host() { + fftwf_cleanup_threads(); + fftw_cleanup_threads(); +} +#else +static void initialize_host() {} +static void finalize_host() {} +#endif + +// If non of device backend is enabled, then FFTW is responsible +// for the device cleanup. Otherwise, device backend will cleanup +#if !(defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_HIP) || \ + defined(KOKKOS_ENABLE_SYCL)) +static void initialize_device() {} +static void finalize_device() {} +#endif + } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_HIP_types.hpp b/fft/src/KokkosFFT_HIP_types.hpp index 4be4d397..4a61b26b 100644 --- a/fft/src/KokkosFFT_HIP_types.hpp +++ b/fft/src/KokkosFFT_HIP_types.hpp @@ -238,7 +238,13 @@ template auto direction_type(Direction direction) { return direction == Direction::forward ? HIPFFT_FORWARD : HIPFFT_BACKWARD; } + +static void initialize_host() {} +static void finalize_host() {} #endif + +static void initialize_device() {} +static void finalize_device() {} } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_ROCM_types.hpp b/fft/src/KokkosFFT_ROCM_types.hpp index 8bf19c07..e08053dd 100644 --- a/fft/src/KokkosFFT_ROCM_types.hpp +++ b/fft/src/KokkosFFT_ROCM_types.hpp @@ -363,7 +363,19 @@ template auto direction_type(Direction direction) { return direction == Direction::forward ? ROCFFT_FORWARD : ROCFFT_BACKWARD; } + +static void initialize_host() {} +static void finalize_host() {} #endif + +static void initialize_device() { + rocfft_status status = rocfft_setup(); + if (status != rocfft_status_success) Kokkos::abort("rocfft_setup failed"); +} +static void finalize_device() { + rocfft_status status = rocfft_cleanup(); + if (status != rocfft_status_success) Kokkos::abort("rocfft_cleanup failed"); +} } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_SYCL_types.hpp b/fft/src/KokkosFFT_SYCL_types.hpp index 9c6cb86b..db4b2442 100644 --- a/fft/src/KokkosFFT_SYCL_types.hpp +++ b/fft/src/KokkosFFT_SYCL_types.hpp @@ -225,7 +225,13 @@ template auto direction_type(Direction direction) { return direction == Direction::forward ? MKL_FFT_FORWARD : MKL_FFT_BACKWARD; } + +static void initialize_host() {} +static void finalize_host() {} #endif + +static void initialize_device() {} +static void finalize_device() {} } // namespace Impl } // namespace KokkosFFT diff --git a/fft/unit_test/CMakeLists.txt b/fft/unit_test/CMakeLists.txt index 24e987e9..5ce15ad8 100644 --- a/fft/unit_test/CMakeLists.txt +++ b/fft/unit_test/CMakeLists.txt @@ -8,10 +8,18 @@ add_executable(unit-tests-kokkos-fft-core Test_Transform.cpp ) -target_compile_features(unit-tests-kokkos-fft-core PUBLIC cxx_std_17) +add_executable(unit-tests-kokkos-fft-core-no-init + Test_MainNoInit.cpp + Test_InitializeFinalize.cpp +) +target_compile_features(unit-tests-kokkos-fft-core PUBLIC cxx_std_17) target_link_libraries(unit-tests-kokkos-fft-core PUBLIC KokkosFFT::fft GTest::gtest) +target_compile_features(unit-tests-kokkos-fft-core-no-init PUBLIC cxx_std_17) +target_link_libraries(unit-tests-kokkos-fft-core-no-init PUBLIC KokkosFFT::fft GTest::gtest) + # Enable GoogleTest include(GoogleTest) gtest_discover_tests(unit-tests-kokkos-fft-core PROPERTIES DISCOVERY_TIMEOUT 600 DISCOVERY_MODE PRE_TEST) +gtest_discover_tests(unit-tests-kokkos-fft-core-no-init PROPERTIES DISCOVERY_TIMEOUT 600 DISCOVERY_MODE PRE_TEST) diff --git a/fft/unit_test/Test_Main.cpp b/fft/unit_test/Test_Main.cpp index b3086838..b26aba88 100644 --- a/fft/unit_test/Test_Main.cpp +++ b/fft/unit_test/Test_Main.cpp @@ -3,25 +3,19 @@ // // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include #include - -namespace testing::internal { -// accessing gtest internals is not very clean, but gtest provides no public -// access... -extern bool g_help_flag; -} // namespace testing::internal +#include +#include int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); + int result = 0; - if (::testing::GTEST_FLAG(list_tests) || ::testing::internal::g_help_flag) { - result = RUN_ALL_TESTS(); - } else { - Kokkos::initialize(argc, argv); - result = RUN_ALL_TESTS(); - Kokkos::finalize(); - } + Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); + result = RUN_ALL_TESTS(); + KokkosFFT::finalize(); + Kokkos::finalize(); return result; } From e9b3d8e2bda7f7fc6c7956c98d78ad277cba90a1 Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Mon, 13 Jan 2025 16:53:48 +0900 Subject: [PATCH 03/12] Add a missing LICENCE --- fft/unit_test/Test_InitializeFinalize.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fft/unit_test/Test_InitializeFinalize.cpp b/fft/unit_test/Test_InitializeFinalize.cpp index e526516e..244008c3 100644 --- a/fft/unit_test/Test_InitializeFinalize.cpp +++ b/fft/unit_test/Test_InitializeFinalize.cpp @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: (C) The kokkos-fft development team, see COPYRIGHT.md file +// +// SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception + #include #include #include "KokkosFFT_Core.hpp" From f92deb500d7341139a77dec6593de15ba0245bb2 Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Mon, 13 Jan 2025 17:10:36 +0900 Subject: [PATCH 04/12] unuse static functions --- fft/src/KokkosFFT_Cuda_types.hpp | 8 ++++---- fft/src/KokkosFFT_FFTW_Types.hpp | 12 ++++++------ fft/src/KokkosFFT_HIP_types.hpp | 8 ++++---- fft/src/KokkosFFT_ROCM_types.hpp | 8 ++++---- fft/src/KokkosFFT_SYCL_types.hpp | 8 ++++---- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/fft/src/KokkosFFT_Cuda_types.hpp b/fft/src/KokkosFFT_Cuda_types.hpp index ac1d7cbd..bf6eef20 100644 --- a/fft/src/KokkosFFT_Cuda_types.hpp +++ b/fft/src/KokkosFFT_Cuda_types.hpp @@ -239,12 +239,12 @@ auto direction_type(Direction direction) { return direction == Direction::forward ? CUFFT_FORWARD : CUFFT_INVERSE; } -static void initialize_host() {} -static void finalize_host() {} +inline void initialize_host() {} +inline void finalize_host() {} #endif -static void initialize_device() {} -static void finalize_device() {} +inline void initialize_device() {} +inline void finalize_device() {} } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_FFTW_Types.hpp b/fft/src/KokkosFFT_FFTW_Types.hpp index b22efa91..0243aefc 100644 --- a/fft/src/KokkosFFT_FFTW_Types.hpp +++ b/fft/src/KokkosFFT_FFTW_Types.hpp @@ -139,25 +139,25 @@ struct ScopedFFTWPlan { }; #if defined(KOKKOS_ENABLE_OPENMP) || defined(KOKKOS_ENABLE_THREADS) -static void initialize_host() { +inline void initialize_host() { fftwf_init_threads(); fftw_init_threads(); } -static void finalize_host() { +inline void finalize_host() { fftwf_cleanup_threads(); fftw_cleanup_threads(); } #else -static void initialize_host() {} -static void finalize_host() {} +inline void initialize_host() {} +inline void finalize_host() {} #endif // If non of device backend is enabled, then FFTW is responsible // for the device cleanup. Otherwise, device backend will cleanup #if !(defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_HIP) || \ defined(KOKKOS_ENABLE_SYCL)) -static void initialize_device() {} -static void finalize_device() {} +inline void initialize_device() {} +inline void finalize_device() {} #endif } // namespace Impl diff --git a/fft/src/KokkosFFT_HIP_types.hpp b/fft/src/KokkosFFT_HIP_types.hpp index 4a61b26b..d371e159 100644 --- a/fft/src/KokkosFFT_HIP_types.hpp +++ b/fft/src/KokkosFFT_HIP_types.hpp @@ -239,12 +239,12 @@ auto direction_type(Direction direction) { return direction == Direction::forward ? HIPFFT_FORWARD : HIPFFT_BACKWARD; } -static void initialize_host() {} -static void finalize_host() {} +inline void initialize_host() {} +inline void finalize_host() {} #endif -static void initialize_device() {} -static void finalize_device() {} +inline void initialize_device() {} +inline void finalize_device() {} } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_ROCM_types.hpp b/fft/src/KokkosFFT_ROCM_types.hpp index e08053dd..d2c25217 100644 --- a/fft/src/KokkosFFT_ROCM_types.hpp +++ b/fft/src/KokkosFFT_ROCM_types.hpp @@ -364,15 +364,15 @@ auto direction_type(Direction direction) { return direction == Direction::forward ? ROCFFT_FORWARD : ROCFFT_BACKWARD; } -static void initialize_host() {} -static void finalize_host() {} +inline void initialize_host() {} +inline void finalize_host() {} #endif -static void initialize_device() { +inline void initialize_device() { rocfft_status status = rocfft_setup(); if (status != rocfft_status_success) Kokkos::abort("rocfft_setup failed"); } -static void finalize_device() { +inline void finalize_device() { rocfft_status status = rocfft_cleanup(); if (status != rocfft_status_success) Kokkos::abort("rocfft_cleanup failed"); } diff --git a/fft/src/KokkosFFT_SYCL_types.hpp b/fft/src/KokkosFFT_SYCL_types.hpp index db4b2442..285574c8 100644 --- a/fft/src/KokkosFFT_SYCL_types.hpp +++ b/fft/src/KokkosFFT_SYCL_types.hpp @@ -226,12 +226,12 @@ auto direction_type(Direction direction) { return direction == Direction::forward ? MKL_FFT_FORWARD : MKL_FFT_BACKWARD; } -static void initialize_host() {} -static void finalize_host() {} +inline void initialize_host() {} +inline void finalize_host() {} #endif -static void initialize_device() {} -static void finalize_device() {} +inline void initialize_device() {} +inline void finalize_device() {} } // namespace Impl } // namespace KokkosFFT From 284a0fb18a8252f61d3e84063bffd256bc09ea60 Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Mon, 13 Jan 2025 18:46:35 +0900 Subject: [PATCH 05/12] Kokkos::finalize before exit --- fft/unit_test/Test_InitializeFinalize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fft/unit_test/Test_InitializeFinalize.cpp b/fft/unit_test/Test_InitializeFinalize.cpp index 244008c3..8ffbdaa7 100644 --- a/fft/unit_test/Test_InitializeFinalize.cpp +++ b/fft/unit_test/Test_InitializeFinalize.cpp @@ -163,8 +163,8 @@ TEST_F(InitializeFinalize_Test, is_finalized) { success &= !KokkosFFT::is_finalized(); KokkosFFT::finalize(); success &= KokkosFFT::is_finalized(); - std::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); Kokkos::finalize(); + std::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); }, ::testing::ExitedWithCode(EXIT_SUCCESS), ""); } From 19bd9631ec9c998c4376589aae6b3f49806fa8b0 Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Mon, 13 Jan 2025 18:53:15 +0900 Subject: [PATCH 06/12] Add initialization and finalization in examples --- examples/01_1DFFT/01_1DFFT.cpp | 2 ++ examples/02_2DFFT/02_2DFFT.cpp | 2 ++ examples/03_NDFFT/03_NDFFT.cpp | 2 ++ examples/04_batchedFFT/04_batchedFFT.cpp | 2 ++ examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp | 2 ++ examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp | 2 ++ examples/07_unmanaged_views/07_unmanaged_views.cpp | 2 ++ examples/08_inplace_FFT/08_inplace_FFT.cpp | 2 ++ install_test/as_library/hello.cpp | 4 +++- install_test/as_subdirectory/hello.cpp | 4 +++- 10 files changed, 22 insertions(+), 2 deletions(-) diff --git a/examples/01_1DFFT/01_1DFFT.cpp b/examples/01_1DFFT/01_1DFFT.cpp index 7eb92107..ec9f7c19 100644 --- a/examples/01_1DFFT/01_1DFFT.cpp +++ b/examples/01_1DFFT/01_1DFFT.cpp @@ -13,6 +13,7 @@ using View1D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { const int n0 = 128; const Kokkos::complex z(1.0, 1.0); @@ -44,6 +45,7 @@ int main(int argc, char* argv[]) { KokkosFFT::irfft(exec, xc2r, xc2r_hat); exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/02_2DFFT/02_2DFFT.cpp b/examples/02_2DFFT/02_2DFFT.cpp index fc01b4a8..94779fea 100644 --- a/examples/02_2DFFT/02_2DFFT.cpp +++ b/examples/02_2DFFT/02_2DFFT.cpp @@ -13,6 +13,7 @@ using View2D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { const int n0 = 128, n1 = 128; const Kokkos::complex z(1.0, 1.0); @@ -44,6 +45,7 @@ int main(int argc, char* argv[]) { KokkosFFT::irfft2(exec, xc2r, xc2r_hat); exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/03_NDFFT/03_NDFFT.cpp b/examples/03_NDFFT/03_NDFFT.cpp index 2c07ee84..72f9d013 100644 --- a/examples/03_NDFFT/03_NDFFT.cpp +++ b/examples/03_NDFFT/03_NDFFT.cpp @@ -15,6 +15,7 @@ using axis_type = KokkosFFT::axis_type; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { const int n0 = 128, n1 = 128, n2 = 16; const Kokkos::complex z(1.0, 1.0); @@ -46,6 +47,7 @@ int main(int argc, char* argv[]) { KokkosFFT::irfftn(exec, xc2r, xc2r_hat, axis_type<3>{-3, -2, -1}); exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/04_batchedFFT/04_batchedFFT.cpp b/examples/04_batchedFFT/04_batchedFFT.cpp index 7cad003d..9e5c53ff 100644 --- a/examples/04_batchedFFT/04_batchedFFT.cpp +++ b/examples/04_batchedFFT/04_batchedFFT.cpp @@ -13,6 +13,7 @@ using View3D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { const int n0 = 128, n1 = 128, n2 = 16; const Kokkos::complex z(1.0, 1.0); @@ -48,6 +49,7 @@ int main(int argc, char* argv[]) { /*axis=*/-1); exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp b/examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp index 76437db2..979a2d02 100644 --- a/examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp +++ b/examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp @@ -16,6 +16,7 @@ using HostView1D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { const int n0 = 128; const Kokkos::complex z(1.0, 1.0); @@ -79,6 +80,7 @@ int main(int argc, char* argv[]) { host_exec.fence(); #endif } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp b/examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp index 0542755f..457fad26 100644 --- a/examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp +++ b/examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp @@ -13,6 +13,7 @@ using View1D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { const int n0 = 128; const Kokkos::complex z(1.0, 1.0); @@ -54,6 +55,7 @@ int main(int argc, char* argv[]) { irfft_plan.execute(xc2r, xc2r_hat); exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/07_unmanaged_views/07_unmanaged_views.cpp b/examples/07_unmanaged_views/07_unmanaged_views.cpp index 9baf502d..6017a32e 100644 --- a/examples/07_unmanaged_views/07_unmanaged_views.cpp +++ b/examples/07_unmanaged_views/07_unmanaged_views.cpp @@ -25,6 +25,7 @@ using shape_type = KokkosFFT::shape_type; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { const int n0 = 128, n1 = 128, n2 = 16; const Kokkos::complex z(1.0, 1.0); @@ -63,6 +64,7 @@ int main(int argc, char* argv[]) { KokkosFFT::Normalization::backward, shape); exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/08_inplace_FFT/08_inplace_FFT.cpp b/examples/08_inplace_FFT/08_inplace_FFT.cpp index 7e17904d..1d5c6b1b 100644 --- a/examples/08_inplace_FFT/08_inplace_FFT.cpp +++ b/examples/08_inplace_FFT/08_inplace_FFT.cpp @@ -14,6 +14,7 @@ using RightView2D = Kokkos::View; int main(int argc, char *argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { const int n0 = 128, n1 = 128; const Kokkos::complex z(1.0, 1.0); @@ -69,6 +70,7 @@ int main(int argc, char *argv[]) { exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/install_test/as_library/hello.cpp b/install_test/as_library/hello.cpp index 9ef3ca8f..ec9f7c19 100644 --- a/install_test/as_library/hello.cpp +++ b/install_test/as_library/hello.cpp @@ -13,8 +13,9 @@ using View1D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { - constexpr int n0 = 128; + const int n0 = 128; const Kokkos::complex z(1.0, 1.0); // 1D C2C FFT (Forward and Backward) @@ -44,6 +45,7 @@ int main(int argc, char* argv[]) { KokkosFFT::irfft(exec, xc2r, xc2r_hat); exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/install_test/as_subdirectory/hello.cpp b/install_test/as_subdirectory/hello.cpp index 45b7d424..94779fea 100644 --- a/install_test/as_subdirectory/hello.cpp +++ b/install_test/as_subdirectory/hello.cpp @@ -13,8 +13,9 @@ using View2D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); + KokkosFFT::initialize(); { - constexpr int n0 = 128, n1 = 128; + const int n0 = 128, n1 = 128; const Kokkos::complex z(1.0, 1.0); // 2D C2C FFT (Forward and Backward) @@ -44,6 +45,7 @@ int main(int argc, char* argv[]) { KokkosFFT::irfft2(exec, xc2r, xc2r_hat); exec.fence(); } + KokkosFFT::finalize(); Kokkos::finalize(); return 0; From 2b59d1289cddc3a4d6f3838382fa0db76109798c Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Tue, 14 Jan 2025 17:29:25 +0900 Subject: [PATCH 07/12] Revert "Add initialization and finalization in examples" This reverts commit 19bd9631ec9c998c4376589aae6b3f49806fa8b0. --- examples/01_1DFFT/01_1DFFT.cpp | 2 -- examples/02_2DFFT/02_2DFFT.cpp | 2 -- examples/03_NDFFT/03_NDFFT.cpp | 2 -- examples/04_batchedFFT/04_batchedFFT.cpp | 2 -- examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp | 2 -- examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp | 2 -- examples/07_unmanaged_views/07_unmanaged_views.cpp | 2 -- examples/08_inplace_FFT/08_inplace_FFT.cpp | 2 -- install_test/as_library/hello.cpp | 4 +--- install_test/as_subdirectory/hello.cpp | 4 +--- 10 files changed, 2 insertions(+), 22 deletions(-) diff --git a/examples/01_1DFFT/01_1DFFT.cpp b/examples/01_1DFFT/01_1DFFT.cpp index ec9f7c19..7eb92107 100644 --- a/examples/01_1DFFT/01_1DFFT.cpp +++ b/examples/01_1DFFT/01_1DFFT.cpp @@ -13,7 +13,6 @@ using View1D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { const int n0 = 128; const Kokkos::complex z(1.0, 1.0); @@ -45,7 +44,6 @@ int main(int argc, char* argv[]) { KokkosFFT::irfft(exec, xc2r, xc2r_hat); exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/02_2DFFT/02_2DFFT.cpp b/examples/02_2DFFT/02_2DFFT.cpp index 94779fea..fc01b4a8 100644 --- a/examples/02_2DFFT/02_2DFFT.cpp +++ b/examples/02_2DFFT/02_2DFFT.cpp @@ -13,7 +13,6 @@ using View2D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { const int n0 = 128, n1 = 128; const Kokkos::complex z(1.0, 1.0); @@ -45,7 +44,6 @@ int main(int argc, char* argv[]) { KokkosFFT::irfft2(exec, xc2r, xc2r_hat); exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/03_NDFFT/03_NDFFT.cpp b/examples/03_NDFFT/03_NDFFT.cpp index 72f9d013..2c07ee84 100644 --- a/examples/03_NDFFT/03_NDFFT.cpp +++ b/examples/03_NDFFT/03_NDFFT.cpp @@ -15,7 +15,6 @@ using axis_type = KokkosFFT::axis_type; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { const int n0 = 128, n1 = 128, n2 = 16; const Kokkos::complex z(1.0, 1.0); @@ -47,7 +46,6 @@ int main(int argc, char* argv[]) { KokkosFFT::irfftn(exec, xc2r, xc2r_hat, axis_type<3>{-3, -2, -1}); exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/04_batchedFFT/04_batchedFFT.cpp b/examples/04_batchedFFT/04_batchedFFT.cpp index 9e5c53ff..7cad003d 100644 --- a/examples/04_batchedFFT/04_batchedFFT.cpp +++ b/examples/04_batchedFFT/04_batchedFFT.cpp @@ -13,7 +13,6 @@ using View3D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { const int n0 = 128, n1 = 128, n2 = 16; const Kokkos::complex z(1.0, 1.0); @@ -49,7 +48,6 @@ int main(int argc, char* argv[]) { /*axis=*/-1); exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp b/examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp index 979a2d02..76437db2 100644 --- a/examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp +++ b/examples/05_1DFFT_HOST_DEVICE/05_1DFFT_HOST_DEVICE.cpp @@ -16,7 +16,6 @@ using HostView1D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { const int n0 = 128; const Kokkos::complex z(1.0, 1.0); @@ -80,7 +79,6 @@ int main(int argc, char* argv[]) { host_exec.fence(); #endif } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp b/examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp index 457fad26..0542755f 100644 --- a/examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp +++ b/examples/06_1DFFT_reuse_plans/06_1DFFT_reuse_plans.cpp @@ -13,7 +13,6 @@ using View1D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { const int n0 = 128; const Kokkos::complex z(1.0, 1.0); @@ -55,7 +54,6 @@ int main(int argc, char* argv[]) { irfft_plan.execute(xc2r, xc2r_hat); exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/07_unmanaged_views/07_unmanaged_views.cpp b/examples/07_unmanaged_views/07_unmanaged_views.cpp index 6017a32e..9baf502d 100644 --- a/examples/07_unmanaged_views/07_unmanaged_views.cpp +++ b/examples/07_unmanaged_views/07_unmanaged_views.cpp @@ -25,7 +25,6 @@ using shape_type = KokkosFFT::shape_type; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { const int n0 = 128, n1 = 128, n2 = 16; const Kokkos::complex z(1.0, 1.0); @@ -64,7 +63,6 @@ int main(int argc, char* argv[]) { KokkosFFT::Normalization::backward, shape); exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/examples/08_inplace_FFT/08_inplace_FFT.cpp b/examples/08_inplace_FFT/08_inplace_FFT.cpp index 1d5c6b1b..7e17904d 100644 --- a/examples/08_inplace_FFT/08_inplace_FFT.cpp +++ b/examples/08_inplace_FFT/08_inplace_FFT.cpp @@ -14,7 +14,6 @@ using RightView2D = Kokkos::View; int main(int argc, char *argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { const int n0 = 128, n1 = 128; const Kokkos::complex z(1.0, 1.0); @@ -70,7 +69,6 @@ int main(int argc, char *argv[]) { exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/install_test/as_library/hello.cpp b/install_test/as_library/hello.cpp index ec9f7c19..9ef3ca8f 100644 --- a/install_test/as_library/hello.cpp +++ b/install_test/as_library/hello.cpp @@ -13,9 +13,8 @@ using View1D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { - const int n0 = 128; + constexpr int n0 = 128; const Kokkos::complex z(1.0, 1.0); // 1D C2C FFT (Forward and Backward) @@ -45,7 +44,6 @@ int main(int argc, char* argv[]) { KokkosFFT::irfft(exec, xc2r, xc2r_hat); exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; diff --git a/install_test/as_subdirectory/hello.cpp b/install_test/as_subdirectory/hello.cpp index 94779fea..45b7d424 100644 --- a/install_test/as_subdirectory/hello.cpp +++ b/install_test/as_subdirectory/hello.cpp @@ -13,9 +13,8 @@ using View2D = Kokkos::View; int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); { - const int n0 = 128, n1 = 128; + constexpr int n0 = 128, n1 = 128; const Kokkos::complex z(1.0, 1.0); // 2D C2C FFT (Forward and Backward) @@ -45,7 +44,6 @@ int main(int argc, char* argv[]) { KokkosFFT::irfft2(exec, xc2r, xc2r_hat); exec.fence(); } - KokkosFFT::finalize(); Kokkos::finalize(); return 0; From 7986dd2343ef59579e2771b18aaaef07dcabed71 Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Wed, 15 Jan 2025 17:26:29 +0900 Subject: [PATCH 08/12] use static lambda for initialization rather than KokkosFFT::initialize --- fft/src/CMakeLists.txt | 6 +- fft/src/KokkosFFT.hpp | 1 - fft/src/KokkosFFT_Cuda_plans.hpp | 20 +++ fft/src/KokkosFFT_Cuda_types.hpp | 4 - fft/src/KokkosFFT_FFTW_Types.hpp | 22 --- fft/src/KokkosFFT_HIP_plans.hpp | 20 +++ fft/src/KokkosFFT_HIP_types.hpp | 4 - fft/src/KokkosFFT_Host_plans.hpp | 39 +++++ fft/src/KokkosFFT_Plans.hpp | 2 + fft/src/KokkosFFT_ROCM_plans.hpp | 30 ++++ fft/src/KokkosFFT_ROCM_types.hpp | 10 -- fft/src/KokkosFFT_SYCL_plans.hpp | 21 +++ fft/src/KokkosFFT_SYCL_types.hpp | 4 - fft/unit_test/CMakeLists.txt | 9 -- fft/unit_test/Test_InitializeFinalize.cpp | 172 ---------------------- fft/unit_test/Test_Main.cpp | 3 - fft/unit_test/Test_MainNoInit.cpp | 11 -- 17 files changed, 135 insertions(+), 243 deletions(-) delete mode 100644 fft/unit_test/Test_InitializeFinalize.cpp delete mode 100644 fft/unit_test/Test_MainNoInit.cpp diff --git a/fft/src/CMakeLists.txt b/fft/src/CMakeLists.txt index 1dc94d02..3a7161ad 100644 --- a/fft/src/CMakeLists.txt +++ b/fft/src/CMakeLists.txt @@ -2,15 +2,15 @@ # # SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception -add_library(fft STATIC KokkosFFT_Core.cpp) +add_library(fft INTERFACE) target_link_libraries(fft - PUBLIC +INTERFACE common Kokkos::kokkos ) -target_include_directories(fft PUBLIC +target_include_directories(fft INTERFACE $ $ ) diff --git a/fft/src/KokkosFFT.hpp b/fft/src/KokkosFFT.hpp index 6b035b56..2df13dd8 100644 --- a/fft/src/KokkosFFT.hpp +++ b/fft/src/KokkosFFT.hpp @@ -10,6 +10,5 @@ #include "KokkosFFT_Helpers.hpp" #include "KokkosFFT_Plans.hpp" #include "KokkosFFT_Transform.hpp" -#include "KokkosFFT_Core.hpp" #endif diff --git a/fft/src/KokkosFFT_Cuda_plans.hpp b/fft/src/KokkosFFT_Cuda_plans.hpp index dc8423c8..9e50071c 100644 --- a/fft/src/KokkosFFT_Cuda_plans.hpp +++ b/fft/src/KokkosFFT_Cuda_plans.hpp @@ -13,6 +13,26 @@ namespace KokkosFFT { namespace Impl { + +template , + std::nullptr_t> = nullptr> +void setup() { + static bool once = [] { + if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called before initializing " + "Kokkos.\n"); + } + if (Kokkos::is_finalized()) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called after finalizing " + "Kokkos.\n"); + } + return true; + }(); +} + // 1D transform template , + std::nullptr_t> = nullptr> +void setup() { + static bool once = [] { + if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called before initializing " + "Kokkos.\n"); + } + if (Kokkos::is_finalized()) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called after finalizing " + "Kokkos.\n"); + } + return true; + }(); +} + // 1D transform template , std::nullptr_t> = + nullptr> +void setup() { + static bool once = [] { + if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called before initializing " + "Kokkos.\n"); + } + if (Kokkos::is_finalized()) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called after finalizing " + "Kokkos.\n"); + } +#if defined(KOKKOS_ENABLE_OPENMP) || defined(KOKKOS_ENABLE_THREADS) + if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + fftwf_init_threads(); + } else { + fftw_init_threads(); + } + + // Register cleanup function as a hook in Kokkos::finalize + Kokkos::push_finalize_hook([]() { + if constexpr (std::is_same_v) { + fftwf_cleanup_threads(); + } else { + fftw_cleanup_threads(); + } + }); + } +#endif + return true; + }(); +} + // batched transform, over ND Views template (); m_fft_size = KokkosFFT::Impl::create_plan( exec_space, m_plan, in, out, direction, m_axes, s, m_is_inplace); } @@ -260,6 +261,7 @@ class Plan { "In-place transform is not supported with reshape. " "Please use out-of-place transform."); + KokkosFFT::Impl::setup(); m_fft_size = KokkosFFT::Impl::create_plan(exec_space, m_plan, in, out, direction, axes, s, m_is_inplace); } diff --git a/fft/src/KokkosFFT_ROCM_plans.hpp b/fft/src/KokkosFFT_ROCM_plans.hpp index 56c1d6c3..68b45dc8 100644 --- a/fft/src/KokkosFFT_ROCM_plans.hpp +++ b/fft/src/KokkosFFT_ROCM_plans.hpp @@ -5,6 +5,7 @@ #ifndef KOKKOSFFT_ROCM_PLANS_HPP #define KOKKOSFFT_ROCM_PLANS_HPP +#include #include "KokkosFFT_ROCM_types.hpp" #include "KokkosFFT_Extents.hpp" #include "KokkosFFT_traits.hpp" @@ -14,6 +15,35 @@ namespace KokkosFFT { namespace Impl { +template , + std::nullptr_t> = nullptr> +void setup() { + static bool once = [] { + if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called before initializing " + "Kokkos.\n"); + } + if (Kokkos::is_finalized()) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called after finalizing " + "Kokkos.\n"); + } + + rocfft_status status = rocfft_setup(); + if (status != rocfft_status_success) Kokkos::abort("rocfft_setup failed"); + + // Register cleanup function as a hook in Kokkos::finalize + Kokkos::push_finalize_hook([]() { + rocfft_status status = rocfft_cleanup(); + if (status != rocfft_status_success) + Kokkos::abort("rocfft_cleanup failed"); + }); + return true; + }(); +} + // batched transform, over ND Views template , + std::nullptr_t> = nullptr> +void setup() { + static bool once = [] { + if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called before initializing " + "Kokkos.\n"); + } + if (Kokkos::is_finalized()) { + Kokkos::abort( + "Error: KokkosFFT APIs must not be called after finalizing " + "Kokkos.\n"); + } + return true; + }(); +} + // Helper to convert the integer type of vectors template auto convert_int_type(std::vector& in) -> std::vector { diff --git a/fft/src/KokkosFFT_SYCL_types.hpp b/fft/src/KokkosFFT_SYCL_types.hpp index 285574c8..05dfe6ec 100644 --- a/fft/src/KokkosFFT_SYCL_types.hpp +++ b/fft/src/KokkosFFT_SYCL_types.hpp @@ -226,12 +226,8 @@ auto direction_type(Direction direction) { return direction == Direction::forward ? MKL_FFT_FORWARD : MKL_FFT_BACKWARD; } -inline void initialize_host() {} -inline void finalize_host() {} #endif -inline void initialize_device() {} -inline void finalize_device() {} } // namespace Impl } // namespace KokkosFFT diff --git a/fft/unit_test/CMakeLists.txt b/fft/unit_test/CMakeLists.txt index 5ce15ad8..e173111a 100644 --- a/fft/unit_test/CMakeLists.txt +++ b/fft/unit_test/CMakeLists.txt @@ -8,18 +8,9 @@ add_executable(unit-tests-kokkos-fft-core Test_Transform.cpp ) -add_executable(unit-tests-kokkos-fft-core-no-init - Test_MainNoInit.cpp - Test_InitializeFinalize.cpp -) - target_compile_features(unit-tests-kokkos-fft-core PUBLIC cxx_std_17) target_link_libraries(unit-tests-kokkos-fft-core PUBLIC KokkosFFT::fft GTest::gtest) -target_compile_features(unit-tests-kokkos-fft-core-no-init PUBLIC cxx_std_17) -target_link_libraries(unit-tests-kokkos-fft-core-no-init PUBLIC KokkosFFT::fft GTest::gtest) - # Enable GoogleTest include(GoogleTest) gtest_discover_tests(unit-tests-kokkos-fft-core PROPERTIES DISCOVERY_TIMEOUT 600 DISCOVERY_MODE PRE_TEST) -gtest_discover_tests(unit-tests-kokkos-fft-core-no-init PROPERTIES DISCOVERY_TIMEOUT 600 DISCOVERY_MODE PRE_TEST) diff --git a/fft/unit_test/Test_InitializeFinalize.cpp b/fft/unit_test/Test_InitializeFinalize.cpp deleted file mode 100644 index 8ffbdaa7..00000000 --- a/fft/unit_test/Test_InitializeFinalize.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-FileCopyrightText: (C) The kokkos-fft development team, see COPYRIGHT.md file -// -// SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception - -#include -#include -#include "KokkosFFT_Core.hpp" - -/** - * Fixture that checks Kokkos is neither initialized nor finalized before and - * after each test. - */ -class KokkosFFTExecutionEnvironmentNeverInitialized : public ::testing::Test { - static void checkNeverInitialized() { - ASSERT_FALSE(Kokkos::is_initialized()); - ASSERT_FALSE(Kokkos::is_finalized()); - ASSERT_FALSE(KokkosFFT::is_initialized()); - ASSERT_FALSE(KokkosFFT::is_finalized()); - } - - protected: - void SetUp() override { checkNeverInitialized(); } - void TearDown() override { checkNeverInitialized(); } -}; - -namespace { -using InitializeFinalize_DeathTest = - KokkosFFTExecutionEnvironmentNeverInitialized; -using InitializeFinalize_Test = KokkosFFTExecutionEnvironmentNeverInitialized; - -TEST_F(InitializeFinalize_DeathTest, initialize) { - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - // Valid usage - EXPECT_EXIT( - { - Kokkos::initialize(); - KokkosFFT::initialize(); - KokkosFFT::finalize(); - Kokkos::finalize(); - std::exit(EXIT_SUCCESS); - }, - ::testing::ExitedWithCode(EXIT_SUCCESS), ""); - - // KokkosFFT is initialized twice - EXPECT_DEATH( - { - Kokkos::initialize(); - KokkosFFT::initialize(); - KokkosFFT::initialize(); - Kokkos::finalize(); - }, - "Error: KokkosFFT::initialize\\(\\) has already been called. KokkosFFT " - "can be " - "initialized at most once\\."); - - // KokkosFFT is initialized twice after finalize - EXPECT_DEATH( - { - Kokkos::initialize(); - KokkosFFT::initialize(); - KokkosFFT::finalize(); - KokkosFFT::initialize(); - Kokkos::finalize(); - }, - "Error: KokkosFFT::initialize\\(\\) has already been called. KokkosFFT " - "can be " - "initialized at most once\\."); - - // KokkosFFT is initialized before Kokkos initialization - EXPECT_DEATH( - { - KokkosFFT::initialize(); - Kokkos::initialize(); - Kokkos::finalize(); - }, - "Error: KokkosFFT::initialize\\(\\) must not be called before " - "initializing Kokkos\\."); - - // KokkosFFT is initialized after Kokkos finalization - EXPECT_DEATH( - { - Kokkos::initialize(); - Kokkos::finalize(); - KokkosFFT::initialize(); - }, - "Error: KokkosFFT::initialize\\(\\) must not be called after finalizing " - "Kokkos\\."); -} - -TEST_F(InitializeFinalize_DeathTest, finalize) { - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - // KokkosFFT is not initialized - EXPECT_DEATH( - { - Kokkos::initialize(); - KokkosFFT::finalize(); - Kokkos::finalize(); - }, - "Error: KokkosFFT::finalize\\(\\) may only be called after KokkosFFT has " - "been initialized\\."); - - // KokkosFFT is finalized twice - EXPECT_DEATH( - { - Kokkos::initialize(); - KokkosFFT::initialize(); - KokkosFFT::finalize(); - KokkosFFT::finalize(); - Kokkos::finalize(); - }, - "Error: KokkosFFT::finalize\\(\\) has already been called\\."); - - // KokkosFFT is finalized before Kokkos initialization - EXPECT_DEATH( - { - KokkosFFT::finalize(); - Kokkos::initialize(); - Kokkos::finalize(); - }, - "Error: KokkosFFT::finalize\\(\\) may only be called after Kokkos has " - "been initialized\\."); - - // KokkosFFT is finalized after Kokkos finalization - EXPECT_DEATH( - { - Kokkos::initialize(); - KokkosFFT::initialize(); - Kokkos::finalize(); - KokkosFFT::finalize(); - }, - "Error: KokkosFFT::finalize\\(\\) must be called before finalizing " - "Kokkos\\."); -} - -TEST_F(InitializeFinalize_Test, is_initialized) { - EXPECT_EXIT( - { - Kokkos::initialize(); - bool success = true; - success &= !KokkosFFT::is_initialized(); - std::cout << "success" << success << std::endl; - KokkosFFT::initialize(); - success &= KokkosFFT::is_initialized(); - std::cout << "success" << success << std::endl; - KokkosFFT::finalize(); - success &= !KokkosFFT::is_initialized(); - std::cout << "success" << success << std::endl; - Kokkos::finalize(); - std::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); - }, - ::testing::ExitedWithCode(EXIT_SUCCESS), ""); -} - -TEST_F(InitializeFinalize_Test, is_finalized) { - EXPECT_EXIT( - { - Kokkos::initialize(); - bool success = true; - success &= !KokkosFFT::is_finalized(); - KokkosFFT::initialize(); - success &= !KokkosFFT::is_finalized(); - KokkosFFT::finalize(); - success &= KokkosFFT::is_finalized(); - Kokkos::finalize(); - std::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); - }, - ::testing::ExitedWithCode(EXIT_SUCCESS), ""); -} - -} // namespace diff --git a/fft/unit_test/Test_Main.cpp b/fft/unit_test/Test_Main.cpp index b26aba88..6b6fda88 100644 --- a/fft/unit_test/Test_Main.cpp +++ b/fft/unit_test/Test_Main.cpp @@ -5,16 +5,13 @@ #include #include -#include int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); int result = 0; Kokkos::initialize(argc, argv); - KokkosFFT::initialize(); result = RUN_ALL_TESTS(); - KokkosFFT::finalize(); Kokkos::finalize(); return result; diff --git a/fft/unit_test/Test_MainNoInit.cpp b/fft/unit_test/Test_MainNoInit.cpp deleted file mode 100644 index 8e9bb64c..00000000 --- a/fft/unit_test/Test_MainNoInit.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-FileCopyrightText: (C) 2022 National Technology & Engineering Solutions of Sandia, LLC (NTESS). -// SPDX-FileCopyrightText: Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights in this software. -// -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -int main(int argc, char* argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} From fab2afb74f2d722e9c34eb2a92fb05a6a9066aac Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Wed, 15 Jan 2025 17:30:52 +0900 Subject: [PATCH 09/12] CMake format --- fft/src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fft/src/CMakeLists.txt b/fft/src/CMakeLists.txt index 3a7161ad..c6d01e1c 100644 --- a/fft/src/CMakeLists.txt +++ b/fft/src/CMakeLists.txt @@ -5,7 +5,7 @@ add_library(fft INTERFACE) target_link_libraries(fft -INTERFACE + INTERFACE common Kokkos::kokkos ) From a557b5a3e884729e2001aabbff85ea791a74bd7c Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Wed, 15 Jan 2025 17:40:11 +0900 Subject: [PATCH 10/12] Add maybe unused to once lambda function for AMD GPUs --- fft/src/KokkosFFT_HIP_plans.hpp | 2 +- fft/src/KokkosFFT_ROCM_plans.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fft/src/KokkosFFT_HIP_plans.hpp b/fft/src/KokkosFFT_HIP_plans.hpp index d59486a9..cff00ad7 100644 --- a/fft/src/KokkosFFT_HIP_plans.hpp +++ b/fft/src/KokkosFFT_HIP_plans.hpp @@ -18,7 +18,7 @@ template , std::nullptr_t> = nullptr> void setup() { - static bool once = [] { + [[maybe_unused]] static bool once = [] { if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { Kokkos::abort( "Error: KokkosFFT APIs must not be called before initializing " diff --git a/fft/src/KokkosFFT_ROCM_plans.hpp b/fft/src/KokkosFFT_ROCM_plans.hpp index 68b45dc8..876166dd 100644 --- a/fft/src/KokkosFFT_ROCM_plans.hpp +++ b/fft/src/KokkosFFT_ROCM_plans.hpp @@ -19,7 +19,7 @@ template , std::nullptr_t> = nullptr> void setup() { - static bool once = [] { + [[maybe_unused]] static bool once = [] { if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { Kokkos::abort( "Error: KokkosFFT APIs must not be called before initializing " From 45cc2951a8d83b34932fb26350f4e342e1c269f1 Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Wed, 15 Jan 2025 17:49:51 +0900 Subject: [PATCH 11/12] Add maybe unused for host plans --- fft/src/KokkosFFT_Host_plans.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fft/src/KokkosFFT_Host_plans.hpp b/fft/src/KokkosFFT_Host_plans.hpp index 12732098..5a0ae12b 100644 --- a/fft/src/KokkosFFT_Host_plans.hpp +++ b/fft/src/KokkosFFT_Host_plans.hpp @@ -17,7 +17,7 @@ template , std::nullptr_t> = nullptr> void setup() { - static bool once = [] { + [[maybe_unused]] static bool once = [] { if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { Kokkos::abort( "Error: KokkosFFT APIs must not be called before initializing " From 1d427ec44902b07fdb0b85c9f74ca1376c5a0f3e Mon Sep 17 00:00:00 2001 From: Yuuichi Asahi Date: Wed, 15 Jan 2025 18:26:38 +0900 Subject: [PATCH 12/12] remove unnecessary changes --- fft/src/KokkosFFT_Core.cpp | 79 -------------------------------- fft/src/KokkosFFT_Core.hpp | 17 ------- fft/src/KokkosFFT_Cuda_types.hpp | 2 - fft/src/KokkosFFT_HIP_types.hpp | 2 - fft/src/KokkosFFT_ROCM_types.hpp | 2 - fft/src/KokkosFFT_SYCL_types.hpp | 2 - 6 files changed, 104 deletions(-) delete mode 100644 fft/src/KokkosFFT_Core.cpp delete mode 100644 fft/src/KokkosFFT_Core.hpp diff --git a/fft/src/KokkosFFT_Core.cpp b/fft/src/KokkosFFT_Core.cpp deleted file mode 100644 index 36e5d63a..00000000 --- a/fft/src/KokkosFFT_Core.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-FileCopyrightText: (C) The kokkos-fft development team, see COPYRIGHT.md file -// -// SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception - -#include -#include "KokkosFFT_Core.hpp" -#include "KokkosFFT_default_types.hpp" - -namespace { -bool g_is_initialized = false; -bool g_is_finalized = false; - -bool kokkosfft_initialize_was_called() { - return KokkosFFT::is_initialized() || KokkosFFT::is_finalized(); -} -bool kokkosfft_finalize_was_called() { return KokkosFFT::is_finalized(); } - -void initialize_internal() { - KokkosFFT::Impl::initialize_host(); - KokkosFFT::Impl::initialize_device(); -} - -void finalize_internal() { - KokkosFFT::Impl::finalize_host(); - KokkosFFT::Impl::finalize_device(); -} -} // namespace - -[[nodiscard]] bool KokkosFFT::is_initialized() noexcept { - return g_is_initialized; -} - -[[nodiscard]] bool KokkosFFT::is_finalized() noexcept { return g_is_finalized; } - -void KokkosFFT::initialize() { - if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { - Kokkos::abort( - "Error: KokkosFFT::initialize() must not be called before initializing " - "Kokkos.\n"); - } - if (Kokkos::is_finalized()) { - Kokkos::abort( - "Error: KokkosFFT::initialize() must not be called after finalizing " - "Kokkos.\n"); - } - if (kokkosfft_initialize_was_called()) { - Kokkos::abort( - "Error: KokkosFFT::initialize() has already been called." - " KokkosFFT can be initialized at most once.\n"); - } - initialize_internal(); - g_is_initialized = true; -} - -void KokkosFFT::finalize() { - if (!(Kokkos::is_initialized() || Kokkos::is_finalized())) { - Kokkos::abort( - "Error: KokkosFFT::finalize() may only be called after Kokkos has been " - "initialized.\n"); - } - if (Kokkos::is_finalized()) { - Kokkos::abort( - "Error: KokkosFFT::finalize() must be called before finalizing " - "Kokkos.\n"); - } - - if (!kokkosfft_initialize_was_called()) { - Kokkos::abort( - "Error: KokkosFFT::finalize() may only be called after KokkosFFT has " - "been " - "initialized.\n"); - } - if (kokkosfft_finalize_was_called()) { - Kokkos::abort("Error: KokkosFFT::finalize() has already been called.\n"); - } - finalize_internal(); - g_is_initialized = false; - g_is_finalized = true; -} diff --git a/fft/src/KokkosFFT_Core.hpp b/fft/src/KokkosFFT_Core.hpp deleted file mode 100644 index d1d5d60b..00000000 --- a/fft/src/KokkosFFT_Core.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: (C) The kokkos-fft development team, see COPYRIGHT.md file -// -// SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception - -#ifndef KOKKOSFFT_CORE_HPP -#define KOKKOSFFT_CORE_HPP - -namespace KokkosFFT { -void initialize(); - -[[nodiscard]] bool is_initialized() noexcept; -[[nodiscard]] bool is_finalized() noexcept; - -void finalize(); -} // namespace KokkosFFT - -#endif diff --git a/fft/src/KokkosFFT_Cuda_types.hpp b/fft/src/KokkosFFT_Cuda_types.hpp index 88b5c9d7..f5a1fe62 100644 --- a/fft/src/KokkosFFT_Cuda_types.hpp +++ b/fft/src/KokkosFFT_Cuda_types.hpp @@ -238,9 +238,7 @@ template auto direction_type(Direction direction) { return direction == Direction::forward ? CUFFT_FORWARD : CUFFT_INVERSE; } - #endif - } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_HIP_types.hpp b/fft/src/KokkosFFT_HIP_types.hpp index cd233853..4be4d397 100644 --- a/fft/src/KokkosFFT_HIP_types.hpp +++ b/fft/src/KokkosFFT_HIP_types.hpp @@ -238,9 +238,7 @@ template auto direction_type(Direction direction) { return direction == Direction::forward ? HIPFFT_FORWARD : HIPFFT_BACKWARD; } - #endif - } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_ROCM_types.hpp b/fft/src/KokkosFFT_ROCM_types.hpp index b4b53aef..8bf19c07 100644 --- a/fft/src/KokkosFFT_ROCM_types.hpp +++ b/fft/src/KokkosFFT_ROCM_types.hpp @@ -363,9 +363,7 @@ template auto direction_type(Direction direction) { return direction == Direction::forward ? ROCFFT_FORWARD : ROCFFT_BACKWARD; } - #endif - } // namespace Impl } // namespace KokkosFFT diff --git a/fft/src/KokkosFFT_SYCL_types.hpp b/fft/src/KokkosFFT_SYCL_types.hpp index 05dfe6ec..9c6cb86b 100644 --- a/fft/src/KokkosFFT_SYCL_types.hpp +++ b/fft/src/KokkosFFT_SYCL_types.hpp @@ -225,9 +225,7 @@ template auto direction_type(Direction direction) { return direction == Direction::forward ? MKL_FFT_FORWARD : MKL_FFT_BACKWARD; } - #endif - } // namespace Impl } // namespace KokkosFFT