From dbbfdd4e4b7f09c045e938e8bfc930d9207c8605 Mon Sep 17 00:00:00 2001 From: Peter Boyle Date: Tue, 19 May 2026 21:48:23 -0400 Subject: [PATCH] tests/debug: add minimal hipfft ordering bug fail/pass pair Co-Authored-By: Claude Sonnet 4.6 --- tests/debug/Test_hipfft_bug_fail.cc | 53 +++++++++++++++++++++++++ tests/debug/Test_hipfft_bug_pass.cc | 61 +++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 tests/debug/Test_hipfft_bug_fail.cc create mode 100644 tests/debug/Test_hipfft_bug_pass.cc diff --git a/tests/debug/Test_hipfft_bug_fail.cc b/tests/debug/Test_hipfft_bug_fail.cc new file mode 100644 index 00000000..e88c05ac --- /dev/null +++ b/tests/debug/Test_hipfft_bug_fail.cc @@ -0,0 +1,53 @@ +/* + * Minimal program demonstrating hipfft HIPFFT_PARSE_ERROR on ROCm 7 / hipFFT 1.0.20. + * + * Bug: hipfftMakePlanMany returns HIPFFT_PARSE_ERROR (12) for transform sizes + * smaller than 32 when a hipMalloc is issued before plan creation. + * + * Compile: + * hipcc -o Test_hipfft_bug_fail Test_hipfft_bug_fail.cc -lhipfft + * + * Run with empty rocFFT cache: + * rm -rf ~/.cache/rocfft + * ./Test_hipfft_bug_fail + * + * Expected (broken): hipfftMakePlanMany returns 12 (HIPFFT_PARSE_ERROR) for G < 32. + * See Test_hipfft_bug_pass.cc for the workaround. + */ + +#include +#include +#include + +int main(void) { + hipDeviceProp_t prop; + hipGetDeviceProperties(&prop, 0); + printf("Device: %s\n", prop.name); +#ifdef hipfftVersionMinor + printf("hipFFT version: %d.%d.%d\n\n", + hipfftVersionMajor, hipfftVersionMinor, hipfftVersionPatch); +#endif + + for (int G : {8, 16, 32}) { + int howmany = 512; + int n[] = {G}; + long nelems = (long)G * howmany; + + // hipMalloc BEFORE plan creation — triggers HIPFFT_PARSE_ERROR for G < 32 + hipfftDoubleComplex *buf = nullptr; + hipMalloc(&buf, nelems * sizeof(hipfftDoubleComplex)); + + hipfftHandle p; + size_t workSize = 0; + hipfftCreate(&p); + hipfftResult rv = hipfftMakePlanMany(p, 1, n, + nullptr, 1, G, nullptr, 1, G, + HIPFFT_Z2Z, howmany, &workSize); + printf("G=%-4d hipMalloc-then-plan: %d (%s)\n", + G, (int)rv, rv == HIPFFT_SUCCESS ? "HIPFFT_SUCCESS" : "HIPFFT_PARSE_ERROR"); + hipfftDestroy(p); + hipFree(buf); + } + + return 0; +} diff --git a/tests/debug/Test_hipfft_bug_pass.cc b/tests/debug/Test_hipfft_bug_pass.cc new file mode 100644 index 00000000..3cd7c210 --- /dev/null +++ b/tests/debug/Test_hipfft_bug_pass.cc @@ -0,0 +1,61 @@ +/* + * Minimal program demonstrating the workaround for the hipfft ROCm 7 bug. + * + * Workaround: create the hipfft plan BEFORE any hipMalloc. Plan creation + * for G < 32 then succeeds even with an empty rocFFT cache. + * + * Compile: + * hipcc -o Test_hipfft_bug_pass Test_hipfft_bug_pass.cc -lhipfft + * + * Run: + * rm -rf ~/.cache/rocfft + * ./Test_hipfft_bug_pass + * + * Expected: all G values succeed. + * Compare with Test_hipfft_bug_fail.cc which uses the opposite ordering. + */ + +#include +#include +#include + +int main(void) { + hipDeviceProp_t prop; + hipGetDeviceProperties(&prop, 0); + printf("Device: %s\n", prop.name); +#ifdef hipfftVersionMinor + printf("hipFFT version: %d.%d.%d\n\n", + hipfftVersionMajor, hipfftVersionMinor, hipfftVersionPatch); +#endif + + for (int G : {8, 16, 32}) { + int howmany = 512; + int n[] = {G}; + long nelems = (long)G * howmany; + + // Plan created BEFORE hipMalloc — succeeds for all G + hipfftHandle p; + size_t workSize = 0; + hipfftCreate(&p); + hipfftResult rv = hipfftMakePlanMany(p, 1, n, + nullptr, 1, G, nullptr, 1, G, + HIPFFT_Z2Z, howmany, &workSize); + printf("G=%-4d plan-then-hipMalloc: %d (%s)\n", + G, (int)rv, rv == HIPFFT_SUCCESS ? "HIPFFT_SUCCESS" : "HIPFFT_PARSE_ERROR"); + + if (rv == HIPFFT_SUCCESS) { + hipfftDoubleComplex *buf = nullptr; + hipMalloc(&buf, nelems * sizeof(hipfftDoubleComplex)); + hipMemset(buf, 0, nelems * sizeof(hipfftDoubleComplex)); + rv = hipfftExecZ2Z(p, buf, buf, HIPFFT_FORWARD); + hipDeviceSynchronize(); + printf("G=%-4d execFwd: %d (%s)\n", + G, (int)rv, rv == HIPFFT_SUCCESS ? "HIPFFT_SUCCESS" : "FAILED"); + hipFree(buf); + } + + hipfftDestroy(p); + } + + return 0; +}