Other Methods#
Runtime Database Query#
cufftdx::experimental::utils::query_database(...) and cufftdx::experimental::utils::get_all_implementations(...) provide runtime access to the cuFFTDx internal database.
Both methods are useful when FFT configuration is selected dynamically, for example based on user inputs, including
checking whether a given configuration requires a workspace. To better understand the difference between non-workspace
and workspace-required FFTs please check Supported Functionality.
cufftdx::experimental::utils::query_database(...) returns the optimal implementation as std::optional<cufftdx::experimental::utils::frontend_impl_traits>.
If no implementation is found for the provided configuration, it returns std::nullopt.
frontend_impl_traits describes the selected implementation:
Field |
Description |
|---|---|
|
Same as FFT::elements_per_thread and FFT::ffts_per_block. |
|
Same as FFT::suggested_elements_per_thread, FFT::suggested_ffts_per_block, and FFT::suggested_block_dim. |
|
Same as FFT::block_dim. Launch the kernel with these dimensions. They are |
|
Same as FFT::shared_memory_size. |
|
Same as FFT::storage_size and FFT::stride. |
|
Same as FFT::input_ept and FFT::output_ept. |
|
Bytes of global memory the FFT reads; |
|
The Transposition layout used by the selected implementation, or
|
|
The size the selected implementation actually runs at: halved under |
|
Which database answered: |
The code_type parameter is of type cufftdx::experimental::query_code_type and selects which database
backend the call dispatches to:
experimental::query_code_type::ptx– query the built-in offline PTX database that ships with cuFFTDx (default).experimental::query_code_type::ltoir_offline– query an offline LTO database that has been generated ahead of time with the LTO helper (see Custom LTO Helper) and included in the translation unit.experimental::query_code_type::ltoir_online– forward the request to the cuFFT Device API at runtime via query_all_cufft_implementations. This mode additionally requiresCUFFTDX_ENABLE_CUFFT_DEPENDENCYto be defined and the application to be linked against cuFFT.
std::optional<cufftdx::experimental::utils::frontend_impl_traits>
cufftdx::experimental::utils::query_database(
unsigned int fft_size,
cufftdx::fft_direction dir,
cufftdx::fft_type type,
unsigned int sm,
cufftdx::utils::execution_type execution,
cufftdx::precision prec =
cufftdx::precision::f32,
unsigned int fft_ept = 0,
unsigned int ffts_per_block = 0,
std::tuple<unsigned int, unsigned int, unsigned int>
block_dim = {0, 0, 0},
cufftdx::complex_layout layout =
cufftdx::complex_layout::natural,
cufftdx::real_mode rmode =
cufftdx::real_mode::normal,
cufftdx::experimental::query_code_type code_type =
cufftdx::experimental::query_code_type::ptx,
bool has_thread_linearization = false,
cufftdx::experimental::transposition trp =
cufftdx::experimental::transposition::any,
cufftdx::experimental::thread_layout thread_layout =
cufftdx::experimental::thread_layout::regular);
cufftdx::experimental::utils::get_all_implementations(...) returns all matching implementations as std::vector<cufftdx::experimental::utils::frontend_impl_traits>.
If no implementation is found, it returns an empty vector.
std::vector<cufftdx::experimental::utils::frontend_impl_traits>
cufftdx::experimental::utils::get_all_implementations(
unsigned int fft_size,
cufftdx::fft_direction dir,
cufftdx::fft_type type,
unsigned int sm,
cufftdx::utils::execution_type execution,
cufftdx::precision prec =
cufftdx::precision::f32,
unsigned int fft_ept = 0,
unsigned int ffts_per_block = 0,
std::tuple<unsigned int, unsigned int, unsigned int>
block_dim = {0, 0, 0},
cufftdx::complex_layout layout =
cufftdx::complex_layout::natural,
cufftdx::real_mode rmode =
cufftdx::real_mode::normal,
cufftdx::experimental::query_code_type code_type =
cufftdx::experimental::query_code_type::ptx,
bool has_thread_linearization = false,
cufftdx::experimental::transposition trp =
cufftdx::experimental::transposition::any,
cufftdx::experimental::thread_layout thread_layout =
cufftdx::experimental::thread_layout::regular);
has_thread_linearization and trp select, respectively, whether the returned implementation uses
Thread Linearization and which Transposition
shared-memory layout it uses. Both default to the values of a descriptor with neither operator applied.
thread_layout selects the thread-to-data mapping of the returned
implementation and must match cufftdx::experimental::thread_layout_of<FFT>::value for the descriptor used
to execute the FFT. It defaults to cufftdx::experimental::thread_layout::regular and determines the returned
block_dim_x and block_dim_y. Both LTO query modes return no implementation when
cufftdx::experimental::thread_layout::transposed is requested.
For an example on how to use these APIs, please check the nvrtc_query_database_fft_block example.
Note
These APIs are available only in host (non-NVRTC) code when CUFFTDX_ENABLE_RUNTIME_DATABASE is defined.
The default experimental::query_code_type::ptx mode sees FFT sizes present in the PTX database that ships with
cuFFTDx, including sizes with no direct (Cooley-Tukey) implementation: for block execution with real_mode::normal,
if the size is covered by the built-in Bluestein padding table, the query transparently falls back to a Bluestein
implementation instead of returning nothing. Thread execution and real_mode::folded never fall back to Bluestein.
Check the returned implementation’s workspace_size field and create a workspace on the host with
cufftdx::make_workspace before calling execute(...) when it is nonzero. In
NVRTC-compiled code, which cannot use a workspace, treat a nonzero workspace_size as an unsupported configuration. The
fallback applies to query_database and get_all_implementations in every query mode.
get_database_and_ltoir and
query_all_cufft_implementations resolve the implementation with the
same logic (in ltoir_online mode) but only report what the cuFFT online LTOIR database provides. If the resolved
implementation is a PTX record because cuFFT has no matching function, query_all_cufft_implementations returns an
empty vector, and get_database_and_ltoir returns an empty database string and no LTOIR, with the traits (including
workspace_size) of the PTX record.
To extend the queryable set of non-Bluestein sizes, use one of the
LTO modes: experimental::query_code_type::ltoir_offline (after generating an offline LTO database with the LTO helper,
see Custom LTO Helper) or experimental::query_code_type::ltoir_online (which delegates to the cuFFT
Device API at runtime and additionally requires CUFFTDX_ENABLE_CUFFT_DEPENDENCY).
The LTO query modes are only supported for LTO databases generated with cuFFT 12.3 or later
(from CUDA Toolkit 13.3). Requesting a trp other than transposition::any in ltoir_online mode additionally
requires a cuFFT runtime 12.5 or later. On an older runtime the call does not fail: query_database and get_all_implementations return PTX
implementations (check code), get_database_and_ltoir returns an empty database and no LTOIR, and query_all_cufft_implementations returns an empty vector.
Warning
Compilation time can significantly increase when using these APIs.
(online) LTO Database Creation#
cufftdx::utils::get_database_and_ltoir() returns a tuple containing:
Database string (
std::string) to be inserted into the cuFFTDx headers.Vector of LTOIRs (
std::vector<std::vector<char>>) for building device functions for the specified FFT operation.cufftdx::experimental::utils::frontend_impl_traitsdescribing the selected implementation (block dimensions, shared memory size, whether a workspace is required, and so on) – see the field table in Runtime Database Query. The string and the LTOIR vector are empty, andcodeis notltoir, when cuFFT has no LTO function for the configuration.
std::tuple<std::string, std::vector<std::vector<char>>,
cufftdx::experimental::utils::frontend_impl_traits>
cufftdx::utils::get_database_and_ltoir(
unsigned int fft_size,
cufftdx::fft_direction dir,
cufftdx::fft_type type,
unsigned int sm,
cufftdx::utils::execution_type execution,
cufftdx::precision prec =
cufftdx::precision::f32,
cufftdx::complex_layout layout =
cufftdx::complex_layout::natural,
cufftdx::real_mode rmode =
cufftdx::real_mode::normal,
unsigned int fft_ept = 0
/* use heuristic */,
unsigned int ffts_per_block = 1
/* 0: use suggested ffts_per_block */,
dim3 block_dim = dim3(0, 0, 0)
/* 0: use suggested block_dim */,
bool has_thread_linearization = false,
cufftdx::experimental::transposition trp =
cufftdx::experimental::transposition::any);
Example
// Assuming the following FFT operator is defined in the NVRTC-compiled code:
// using FFT = decltype(cufftdx::Block() +
// cufftdx::Size<128>() +
// cufftdx::Type<cufftdx::fft_type::c2c>() +
// cufftdx::Direction<cufftdx::fft_direction::forward>() +
// cufftdx::Precision<float>() +
// cufftdx::ElementsPerThread<8>() +
// cufftdx::FFTsPerBlock<2>() +
// cufftdx::SM<750>());
// You can get the database string and LTOIRs for the FFT operation by calling:
auto [lto_db, ltoirs, impl_traits] =
cufftdx::utils::get_database_and_ltoir(128,
cufftdx::fft_direction::forward,
cufftdx::fft_type::c2c,
750,
cufftdx::utils::execution_type::block,
cufftdx::precision::f32,
cufftdx::complex_layout::natural,
cufftdx::real_mode::normal,
8,
2);
// impl_traits.block_dim_x/y/z and impl_traits.shared_memory_size describe how to
// launch the kernel; impl_traits.workspace_size is nonzero if a workspace is required.
After obtaining the database string and LTOIRs, you can insert the database string into the cuFFTDx header file and link the LTOIRs to the user code as shown in Use Case II: Online Kernel Generation.
Note
The cufftdx::utils::get_database_and_ltoir() function is a wrapper around cuFFT Device APIs (see cuFFT Device API Reference). To use this function:
This function is available only in host (non-NVRTC) code.
Define
CUFFTDX_ENABLE_CUFFT_DEPENDENCYbefore including the cuFFTDx headers.Define
CUFFTDX_ENABLE_RUNTIME_DATABASEbefore including the cuFFTDx headers.Define
CUFFT_ENABLE_EXPERIMENTAL_API(required by the cuFFT Device API headers).Link against the cuFFT library.
Querying All cuFFT Online LTO Implementations#
cufftdx::utils::query_all_cufft_implementations() is the “list all candidates” counterpart to get_database_and_ltoir.
It returns all matching cuFFT LTOIR implementations using the same algorithm selection as
query_database, or an empty vector if none are available.
std::vector<cufftdx::experimental::utils::frontend_impl_traits>
cufftdx::utils::query_all_cufft_implementations(
unsigned int fft_size,
cufftdx::fft_direction dir,
cufftdx::fft_type type,
unsigned int sm,
cufftdx::utils::execution_type execution,
cufftdx::precision prec =
cufftdx::precision::f32,
cufftdx::complex_layout layout =
cufftdx::complex_layout::natural,
cufftdx::real_mode rmode =
cufftdx::real_mode::normal,
unsigned int fft_ept = 0
/* use heuristic */,
unsigned int ffts_per_block = 1
/* 0: use suggested ffts_per_block */,
std::tuple<unsigned int, unsigned int, unsigned int>
block_dim = {0, 0, 0},
bool has_thread_linearization = false,
cufftdx::experimental::transposition trp =
cufftdx::experimental::transposition::any);
For a complete autotuning example that enumerates all implementations, benchmarks each one, and then calls get_database_and_ltoir() for the
selected configuration, see example/cufftdx/04_nvrtc_fft/nvrtc_query_autotune_lto.cu.
has_thread_linearization and trp on both get_database_and_ltoir() and query_all_cufft_implementations() select,
respectively, whether the returned implementation uses Thread Linearization
and which Transposition shared-memory layout it uses.
Note
Like get_database_and_ltoir(), this function is available only in host (non-NVRTC) code.
It is a wrapper around the cuFFT Device API and requires
CUFFTDX_ENABLE_RUNTIME_DATABASE and CUFFTDX_ENABLE_CUFFT_DEPENDENCY to be defined before including
cuFFTDx headers, CUFFT_ENABLE_EXPERIMENTAL_API to be defined, and the application to be linked against cuFFT.
Frontend to Backend Traits Conversion#
cufftdx::experimental::utils::frontend_to_backend(...) converts a frontend FFT description to a effective backend traits that
is used to query the cuFFTDx databases.
In combination with cuFFT Device API, this function can be used to generate the LTO database containing both device function code and metadata (a C++ header file) for a specified FFT operation. See Custom LTO Helper for an example.
#include "cufftdx/utils.hpp"
namespace cufftdx {
namespace utils {
enum class algorithm {
ct,
bluestein,
};
enum class execution_type {
thread,
block,
};
} // namespace utils
namespace experimental {
namespace utils {
struct backend_impl_traits {
unsigned int size;
fft_type type;
fft_direction direction;
unsigned int sm;
unsigned int elements_per_thread;
unsigned int min_elements_per_thread;
};
backend_impl_traits
frontend_to_backend(
cufftdx::utils::algorithm algo,
cufftdx::utils::execution_type exec_type,
unsigned int fft_size
/* size_of<FFT>::value */,
fft_type type
/* type_of<FFT>::value */,
fft_direction direction
/* direction_of<FFT>::value */,
cufftdx::precision precision
/* the cufftdx::precision value matching
* precision_of_t<FFT> */,
unsigned int ffts_per_block
/* the value of the FFTsPerBlock operator,
* or 0 if not set */,
unsigned int sm
/* sm_of<FFT>::value */,
real_mode real_mode
/* real_fft_mode_of<FFT>::value */,
unsigned int elements_per_thread
/* the value of the ElementsPerThread
* operator, or 0 if not set */,
bool has_thread_linearization
/* experimental::is_thread_linearization_enabled_v<FFT> */,
unsigned int block_dim_x
/* x of the BlockDim operator, or 0 if not set */,
unsigned int block_dim_y
/* y of the BlockDim operator, or 0 if not set */,
unsigned int block_dim_z
/* z of the BlockDim operator, or 0 if not set */,
experimental::code_type code_type
/* experimental::code_type_of<FFT>::value */,
experimental::thread_layout thread_layout =
experimental::thread_layout::regular
/* experimental::thread_layout_of<FFT>::value */
);
} // namespace utils
} // namespace experimental
} // namespace cufftdx