Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions projects/hipfft/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ Documentation for hipFFT is available at

* Added amdgcnspirv architecture to client programs, so that they are functional even on gfx architectures that they have not been explicitly compiled in.

* Implemented `hipfftXtSetJITCallback` API, to allow for user-defined device functions to be called when loading
input or storing output of a transform. These callback functions are specified after a plan is allocated with
`hipfftCreate` but before the plan is initialized with one of the `MakePlan` functions. The backend FFT library
will Just-In-Time (JIT) compile the code into its own kernels.

On AMD platforms, the device function is provided as SPIR-V. On CUDA platforms, the device function is provided as
LTO-IR fatbin.

These APIs are not currently compatible with multi-GPU transforms. This
support will be added in a future release of hipFFT.

### Changed

* Modified the rocFFT backend's implementation details of hipFFT so that cuFFT backend's
Expand All @@ -19,6 +30,13 @@ Documentation for hipFFT is available at
Multi-device, unbatched one-dimensional transforms remain unimplemented pending
further analyses of the exact behavior(s) to be matched.

Comment thread
evetsso marked this conversation as resolved.
Resolved
### Deprecations

* The `hipfftXtSetCallback` and `hipfftXtClearCallback` APIs are now deprecated and will be removed in a future
release. They allow for specifying callbacks as device function pointers at plan execution time, but rocFFT cannot
optimize the combined code. Instead, users should specify JIT callbacks with `hipfftXtSetJITCallback` before
initializing the plan.

### Resolved issues

* Fixed a hang when creating a plan with a zero length or zero batch. These now return `HIPFFT_INVALID_SIZE`.
Expand Down
22 changes: 11 additions & 11 deletions projects/hipfft/clients/hipfft_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ class hipfft_params : public fft_params
// will be provided with externally-managed work area(s):
static std::vector<gpubuf> externally_managed_workareas;

// JIT callback data pointers, stored in a params-level vector so
// that they live as long as the plan
std::vector<void*> load_jit_cb_data_ptrs;
std::vector<void*> store_jit_cb_data_ptrs;

static std::vector<size_t> externally_managed_extra_vram_footprint()
{
std::vector<size_t> footprint;
Expand Down Expand Up @@ -1256,8 +1261,6 @@ class hipfft_params : public fft_params
{
return HIPFFT_SUCCESS;
}
throw unimplemented_exception("jit callbacks not implemented");
#if 0
hipfftResult_t ret{HIPFFT_INVALID_PLAN};
hipfftXtCallbackType cbtype = HIPFFT_CB_UNDEFINED;
switch(itype)
Expand Down Expand Up @@ -1302,14 +1305,13 @@ class hipfft_params : public fft_params
}

check_jit_callback_state();
ret = hipfftXtSetJITCallback(plan,
load_jit_cb_data_ptrs = load_jit_cb_state->get_raw_data_ptrs();
ret = hipfftXtSetJITCallback(plan,
load_jit_cb_state->symbol,
load_jit_cb_state->func.data(),
load_jit_cb_state->func.size(),
cbtype,
load_jit_cb_state->data.empty()
? nullptr
: load_jit_cb_state->get_raw_data_ptrs().data());
load_jit_cb_data_ptrs.data());
if(ret != HIPFFT_SUCCESS)
return ret;

Expand Down Expand Up @@ -1353,16 +1355,14 @@ class hipfft_params : public fft_params
throw std::runtime_error("unsupported data type for store callback");
}
}
ret = hipfftXtSetJITCallback(plan,
store_jit_cb_data_ptrs = store_jit_cb_state->get_raw_data_ptrs();
ret = hipfftXtSetJITCallback(plan,
store_jit_cb_state->symbol,
store_jit_cb_state->func.data(),
store_jit_cb_state->func.size(),
cbtype,
store_jit_cb_state->data.empty()
? nullptr
: store_jit_cb_state->get_raw_data_ptrs().data());
store_jit_cb_data_ptrs.data());
return ret;
#endif
}

// call hipfftCreate + hipfftMake* functions, inserting calls to
Expand Down
4 changes: 2 additions & 2 deletions projects/hipfft/clients/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -423,15 +423,15 @@ if (WIN32)
endif()

option(BUILD_CODE_COVERAGE "Build with code coverage flags (clang only)" OFF)
set(COVERAGE_TEST_OPTIONS "--smoketest;--gtest_filter=-*call*" CACHE STRING "Command line arguments for hipfft-test when generating a code coverage report (Note: an additional run of hipfft-test targeting multi_gpu* and callback* tests is always executed and coverage results are aggregated)")
set(COVERAGE_TEST_OPTIONS "--smoketest;--gtest_filter=-*call*" CACHE STRING "Command line arguments for hipfft-test when generating a code coverage report (Note: an additional run of hipfft-test targeting multi_gpu* is always executed and coverage results are aggregated)")
Comment thread
evetsso marked this conversation as resolved.
Resolved
if (BUILD_CODE_COVERAGE)
add_custom_target(
code_cov_tests
DEPENDS hipfft-test
COMMAND ${CMAKE_COMMAND} -E rm -rf ./coverage-report
COMMAND ${CMAKE_COMMAND} -E make_directory ./coverage-report/profraw
COMMAND ${CMAKE_COMMAND} -E env LLVM_PROFILE_FILE="./coverage-report/profraw/hipfft-coverage_%p.profraw" GTEST_LISTENER=NO_PASS_LINE_IN_LOG $<TARGET_FILE:hipfft-test> --precompile=./clients/staging/hipfft-test-precompile.db ${COVERAGE_TEST_OPTIONS}
COMMAND ${CMAKE_COMMAND} -E env LLVM_PROFILE_FILE="./coverage-report/profraw/hipfft-coverage_%p.profraw" GTEST_LISTENER=NO_PASS_LINE_IN_LOG $<TARGET_FILE:hipfft-test> --precompile=./clients/staging/hipfft-test-precompile-multi_gpu-plus-callback.db --gtest_filter=multi_gpu*:callback*
COMMAND ${CMAKE_COMMAND} -E env LLVM_PROFILE_FILE="./coverage-report/profraw/hipfft-coverage_%p.profraw" GTEST_LISTENER=NO_PASS_LINE_IN_LOG $<TARGET_FILE:hipfft-test> --precompile=./clients/staging/hipfft-test-precompile.db --gtest_filter=multi_gpu*
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

Expand Down
2 changes: 1 addition & 1 deletion projects/hipfft/clients/tests/accuracy_test_callback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const static std::vector<std::vector<size_t>> ooffset_range = {{0, 0}, {1, 1}};
auto transform_types = {fft_transform_type_complex_forward, fft_transform_type_real_forward};

#ifdef __HIP__
INSTANTIATE_TEST_SUITE_P(DISABLED_callback_no_offset,
INSTANTIATE_TEST_SUITE_P(callback_no_offset,
accuracy_test,
::testing::ValuesIn(param_generator_base(test_prob,
transform_types,
Expand Down
8 changes: 7 additions & 1 deletion projects/hipfft/clients/tests/gtest_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@ void precompile_test_kernels(const std::string& precompile_file)
{
hipfft_params params;
params.from_token(token);

// JIT callbacks would require JIT state to be
// specified which we're not doing here
Comment thread
evetsso marked this conversation as resolved.
Resolved
if(params.run_callbacks == fft_callback_type_jit)
continue;

params.validate();
params.create_plan();
if(params.is_forward())
Expand Down Expand Up @@ -387,7 +393,7 @@ int main(int argc, char* argv[])
app.add_option("--callback_prob",
callback_prob_factor,
"Probability multiplier for running individual callback transforms")
->default_val(0.0)
->default_val(0.1)
->check(CLI::NonNegativeNumber);
constexpr auto emulation_quick = "quick";
constexpr auto emulation_smoke = "smoke";
Expand Down
6 changes: 4 additions & 2 deletions projects/hipfft/clients/tests/multi_device_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ std::vector<fft_params> param_generator_multi_gpu(const std::optional<SplitType>
static const std::vector<std::vector<size_t>> stride_range = {{1}};

// function pointer callbacks need -fgpu-rdc, but that causes build
// nondeterminism in kpack
auto multi_device_callbacks = {fft_callback_type_none, /*fft_callback_type_funcptr, */};
// nondeterminism in kpack.
// JIT callbacks are not yet supported on multi-GPU transforms
auto multi_device_callbacks
= {fft_callback_type_none, /*fft_callback_type_funcptr, fft_callback_type_jit*/};

// gather cases to test as single-device params, then distribute
// to multiple GPUs
Expand Down
1 change: 1 addition & 0 deletions projects/hipfft/docs/reference/hipfft-api-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ Callbacks
.. doxygenfunction:: hipfftXtSetCallback
.. doxygenfunction:: hipfftXtClearCallback
.. doxygenfunction:: hipfftXtSetCallbackSharedSize
.. doxygenfunction:: hipfftXtSetJITCallback


Single-process multi-GPU transforms
Expand Down
12 changes: 11 additions & 1 deletion projects/hipfft/library/include/hipfft/hipfft.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2016 - 2022 Advanced Micro Devices, Inc. All rights
* Copyright (C) 2016 - 2026 Advanced Micro Devices, Inc. All rights
* reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down Expand Up @@ -59,6 +59,16 @@ DISABLE_WARNING_IGNORED_ATTRIBUTES
#include <hip/hip_runtime_api.h>
DISABLE_WARNING_POP

#if defined(__cplusplus) && __cplusplus >= 201402L
#define HIPFFT_DEPRECATED_MSG(msg) [[deprecated(msg)]]
#elif defined(__GNUC__)
#define HIPFFT_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
#elif defined(_MSC_VER)
#define HIPFFT_DEPRECATED_MSG(msg) __declspec(deprecated(msg))
#else // no-op
#define HIPFFT_DEPRECATED_MSG(msg)
#endif

#ifdef __cplusplus
#include <cstddef>
extern "C" {
Expand Down
97 changes: 89 additions & 8 deletions projects/hipfft/library/include/hipfft/hipfftXt.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (C) 2021 - 2023 Advanced Micro Devices, Inc. All rights
* Copyright (C) 2021 - 2026 Advanced Micro Devices, Inc. All rights
* reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down Expand Up @@ -85,30 +85,38 @@ typedef void (*hipfftCallbackStoreR)(
typedef void (*hipfftCallbackStoreD)(
void* dataOut, size_t offset, hipfftDoubleReal element, void* callerInfo, void* sharedPointer);

/*! @brief Set a callback on a plan
/*! @brief Set a function pointer callback on a plan (deprecated)
*
* @details Set either a load or store callback to run with a plan.
* The type of callback is specified with the 'cbtype' parameter.
* An array ofcallback and callback data pointers must be given -
* one per device executing the plan.
* @details Set either a load or store callback to run with a plan,
* specified as a device function pointer. The type of callback is
* specified with the 'cbtype' parameter. An array of callback and
* callback data pointers must be given - one per device executing
* the plan.
*
* The specified arrays must remain valid until either the plan is
* destroyed or callbacks are cleared from the plan.
*
* @param[in] plan The FFT plan.
* @param[in] callbacks Array of callback function pointers.
* @param[in] cbtype Type of callback being set.
* @param[in] callbackData Array of callback function data pointers
*/
HIPFFT_DEPRECATED_MSG(
"Function pointer callbacks are deprecated; use hipfftXtSetJITCallback for JIT callbacks.")
HIPFFT_EXPORT hipfftResult hipfftXtSetCallback(hipfftHandle plan,
void** callbacks,
hipfftXtCallbackType cbtype,
void** callbackData);

/*! @brief Remove a callback from a plan
/*! @brief Remove a function pointer callback from a plan (deprecated)
*
* @details Remove a previously-set callback from a plan.
* @details Remove a previously-set function pointer callback from a plan.
*
* @param[in] plan The FFT plan.
* @param[in] cbtype Type of callback being removed.
*/
HIPFFT_DEPRECATED_MSG(
"Function pointer callbacks are deprecated; use hipfftXtSetJITCallback for JIT callbacks.")
HIPFFT_EXPORT hipfftResult hipfftXtClearCallback(hipfftHandle plan, hipfftXtCallbackType cbtype);

/*! @brief Set shared memory size for callback.
Expand All @@ -125,6 +133,79 @@ HIPFFT_EXPORT hipfftResult hipfftXtSetCallbackSharedSize(hipfftHandle pl
hipfftXtCallbackType cbtype,
size_t sharedSize);

typedef hipfftComplex (*hipfftJITCallbackLoadC)(void* data,
unsigned long long offset,
void* cbdata,
void* sharedMem);
typedef hipfftDoubleComplex (*hipfftJITCallbackLoadZ)(void* data,
unsigned long long offset,
void* cbdata,
void* sharedMem);
typedef hipfftReal (*hipfftJITCallbackLoadR)(void* data,
unsigned long long offset,
void* cbdata,
void* sharedMem);
typedef hipfftDoubleReal (*hipfftJITCallbackLoadD)(void* data,
unsigned long long offset,
void* cbdata,
void* sharedMem);

typedef void (*hipfftJITCallbackStoreC)(
void* data, unsigned long long offset, hipfftComplex element, void* cbdata, void* sharedMem);
typedef void (*hipfftJITCallbackStoreZ)(void* data,
unsigned long long offset,
hipfftDoubleComplex element,
void* cbdata,
void* sharedMem);
typedef void (*hipfftJITCallbackStoreR)(
void* data, unsigned long long offset, hipfftReal element, void* cbdata, void* sharedMem);
typedef void (*hipfftJITCallbackStoreD)(
void* data, unsigned long long offset, hipfftDoubleReal element, void* cbdata, void* sharedMem);

/*! @brief Set a JIT callback on a plan
*
* @details Set either a load or store callback to run with a plan.
* The type of callback is specified with the `cbtype` parameter.
* The callback is provided as SPIR-V on AMD platforms and as
* LTO-IR fatbin on CUDA platforms.
*
* Note: JIT callbacks cannot currently be used on multi-GPU transforms.
* This support will be added in a future release of hipFFT.
*
* JIT callbacks can be cleared from the plan by passing nullptr
* for `symbol_name` and `bitcode_data`, and 0 for
* `bitcode_len_bytes`.
*
* `cbdata` is an optional array of pointers of data that is passed
Comment thread
evetsso marked this conversation as resolved.
Resolved
* to the callback function. As JIT callbacks are currently only
* supported for single-device transforms, this array must have one
* pointer element in it if it is specified. The pointer will be
* passed to the callback function's `cbdata` parameter when it is
* executed on that device.
*
* If specified, the `cbdata` array must remain valid until either
* the plan is destroyed or callbacks are cleared from the plan.
*
* This function must be called after the plan is allocated using
* ::hipfftCreate, but before the plan is initialized by any of the
* "MakePlan" functions. Therefore, API functions that combine
* creation and initialization (::hipfftPlan1d, ::hipfftPlan2d,
* ::hipfftPlan3d, and ::hipfftPlanMany) cannot set a JIT callback.
*
* @param[in] plan The FFT plan.
* @param[in] symbol_name Name of the symbol in the compiled bitcode.
* @param[in] bitcode_data Pointer to bitcode data.
* @param[in] bitcode_len_bytes Number of bytes in the bitcode data.
* @param[in] cbtype Type of callback function.
* @param[in] cbdata Array of callback function data pointers.
*/
HIPFFT_EXPORT hipfftResult hipfftXtSetJITCallback(hipfftHandle plan,
const char* symbol_name,
const void* bitcode_data,
size_t bitcode_len_bytes,
hipfftXtCallbackType cbtype,
void** cbdata);

/*! @brief Initialize a batched rank-dimensional FFT plan with
advanced data layout and specified input, output, execution data
types.
Expand Down
Loading
Loading