Migrating a Fast Fourier Transform (FFT) Library
Replaceability
The KML_FFT and MKL interfaces are different. Therefore, you need to replace the code based on the code logic. For details, see Kunpeng Math Library Developer Guide in Kunpeng HPCKit 26.1.RC1 Developer Guide.
Table 1 shows the mapping between replaceable interfaces and MKL interfaces.
MKL Interface |
KML Interface |
Description |
|---|---|---|
DftiCreateDescriptor DftiSetValue DftiCommitDescriptor |
kml_fft_plan_dft kml_fft_plan_dft_1d kml_fft_plan_dft_2d kml_fft_plan_dft_3d kml_fft_plan_dft_c2r kml_fft_plan_dft_c2r_1d kml_fft_plan_dft_c2r_2d kml_fft_plan_dft_c2r_3d kml_fft_plan_dft_r2c kml_fft_plan_dft_r2c_1d kml_fft_plan_dft_r2c_2d kml_fft_plan_dft_r2c_3d kml_fft_plan_guru64_dft kml_fft_plan_guru64_dft_c2r kml_fft_plan_guru64_dft_r2c kml_fft_plan_guru64_r2r kml_fft_plan_guru64_split_dft kml_fft_plan_guru64_split_dft_c2r kml_fft_plan_guru64_split_dft_r2c kml_fft_plan_guru_dft kml_fft_plan_guru_dft_c2r kml_fft_plan_guru_dft_r2c kml_fft_plan_guru_r2r kml_fft_plan_guru_split_dft kml_fft_plan_guru_split_dft_c2r kml_fft_plan_guru_split_dft_r2c kml_fft_plan_many_dft kml_fft_plan_many_dft_c2r kml_fft_plan_many_dft_r2c kml_fft_plan_many_r2r kml_fft_plan_r2r kml_fft_plan_r2r_1d kml_fft_plan_r2r_2d kml_fft_plan_r2r_3d kml_fft_plan_with_nthreads kml_fft_init_threads kml_fft_cleanup_threads |
MKL builds an FFT model in three steps:
KML uses different plan interfaces based on the problem type. Different plan interfaces require different parameter configurations, which are transferred to plan interfaces through parameters. You need to replace them separately during the migration. For details, see the three code samples provided in Migrating the C-based Library. |
DftiFreeDescriptor |
kml_fft_destroy_plan kml_fft_free |
This interface is used to release resources associated with a model. |
DftiCopyDescriptor |
N/A |
- |
DftiComputeForward |
kml_fft_execute kml_fft_execute_dft kml_fft_execute_split_dft kml_fft_execute_dft_r2c kml_fft_execute_split_dft_r2c |
DftiComputeForward is used for the C2C and R2C problems in MKL, while the execution functions related to C2C and R2C in KML are used. |
DftiComputeBackward |
kml_fft_execute kml_fft_execute_dft kml_fft_execute_split_dft kml_fft_execute_dft_c2r kml_fft_execute_split_dft_c2r |
DftiComputeBackward is used for the C2C and C2R problems in MKL while the execution functions related to C2C and C2R in KML are used. |
DftiGetValue |
N/A |
- |
DftiErrorClass |
N/A |
- |
DftiErrorMessage |
N/A |
- |
Migrating the C-based Library
- Example: C2C transformBefore the migration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#include "mkl_cdft.h" #include "mkl_cdft_types.h" DFTI_DESCRIPTOR_HANDLE desc_handle = NULL; MKL_LONG rank = 2; MKL_LONG length[2] = {2, 3}; MKL_LONG istrides[3] = {0, 3, 1}; MKL_LONG ostrides[3] = {0, 3, 1}; MKL_LONG nthreads = 1; MKL_LONG howmany = 2; MKL_LONG idistance = 2 * 3; MKL_LONG odistance = 2 * 3; double init[12][2] = {{120, 0}, {8, 8}, {0, 0}, {0, 16}, {0, 16}, {-8, 8}, {-8, 0}, {-8, 8}, {-16, 0}, {0, -16}, {-40, 8}, {-8, -8}}; double *ri; ri = (double*)malloc(sizeof(double) * 12); double *ii; ii = (double*)malloc(sizeof(double) * 12); for (int i = 0; i < 12; i++) { ri[i] = init[i][0]; ii[i] = init[i][1]; } MKL_LONG s = DftiCreateDescriptor(&desc_handle, DFTI_DOUBLE, DFTI_COMPLEX, rank, length); s = DftiSetValue(desc_handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE); s = DftiSetValue(desc_handle, DFTI_INPUT_STRIDES, istrides); s = DftiSetValue(desc_handle, DFTI_OUTPUT_STRIDES, ostrides); s = DftiSetValue(desc_handle, DFTI_THREAD_LIMIT, nthreads); s = DftiSetValue(desc_handle, DFTI_COMPLEX_STORAGE, DFTI_REAL_REAL); s = DftiSetValue(desc_handle, DFTI_NUMBER_OF_TRANSFORMS, howmany); s = DftiSetValue(desc_handle, DFTI_INPUT_DISTANCE, idistance); s = DftiSetValue(desc_handle, DFTI_OUTPUT_DISTANCE, odistance); s = DftiCommitDescriptor(desc_handle); double *ro; ro = (double*)malloc(sizeof(double) * 12); double *io; io = (double*)malloc(sizeof(double) * 12); DftiComputeForward(desc_handle, ri, ii, ro, io); DftiFreeDescriptor(&desc_handle); free(ri); free(ii); free(ro); free(io);
After the migration:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
#include "kfft.h" int rank = 2; kml_fft_iodim64 *dims; dims = (kml_fft_iodim64*)kml_fft_malloc(sizeof(kml_fft_iodim64) * rank); dims[0].n = 2; dims[0].is = 3; dims[0].os = 3; dims[1].n = 3; dims[1].is = 1; dims[1].os = 1; int howmany_rank = 1; kml_fft_iodim64 *howmany_dims; howmany_dims = (kml_fft_iodim64*)kml_fft_malloc(sizeof(kml_fft_iodim64) * howmany_rank); howmany_dims[0].n = 2; howmany_dims[0].is = 2 * 3; howmany_dims[0].os = 2 * 3; double init[12][2] = {{120, 0}, {8, 8}, {0, 0}, {0, 16}, {0, 16}, {-8, 8}, {-8, 0}, {-8, 8}, {-16, 0}, {0, -16}, {-40, 8}, {-8, -8}}; double *ri; ri = (double*)kml_fft_malloc(sizeof(double) * 12); double *ii; ii = (double*)kml_fft_malloc(sizeof(double) * 12); for (int i = 0; i < 12; i++) { ri[i] = init[i][0]; ii[i] = init[i][1]; } double *ro; ro = (double*)kml_fft_malloc(sizeof(double) * 12); double *io; io = (double*)kml_fft_malloc(sizeof(double) * 12); kml_fft_plan plan; plan = kml_fft_plan_guru64_split_dft(rank, dims, howmany_rank, howmany_dims, ri, ii, ro, io, KML_FFT_ESTIMATE); kml_fft_execute_split_dft(plan, ri, ii, ro, io); kml_fft_destroy_plan(plan); kml_fft_free(howmany_dims); kml_fft_free(dims); kml_fft_free(ri); kml_fft_free(ii); kml_fft_free(ro); kml_fft_free(io); /* * ro = {1.200000e+02, 1.338564e+02, 1.061436e+02, 1.360000e+02, * 1.120000e+02, 1.120000e+02, -8.000000e+01, 4.878461e+01, * 7.215390e+00, 1.600000e+01, -2.692820e+01, -1.307180e+01} */ /* * io = {4.800000e+01, -1.385641e+01, 1.385641e+01, -3.200000e+01, * -8.000000e+00, -8.000000e+00, -8.000000e+00, 7.846097e-01, * -4.078461e+01, 2.400000e+01, -2.264102e+01, 4.664102e+01} */
- Example: R2C transformBefore the migration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include "mkl_cdft.h" #include "mkl_cdft_types.h" DFTI_DESCRIPTOR_HANDLE desc_handle = NULL; MKL_LONG rank = 2; MKL_LONG length[2] = {2, 3}; MKL_LONG istrides[3] = {0, 3, 1}; MKL_LONG ostrides[3] = {0, 2, 1}; MKL_LONG nthreads = 1; MKL_LONG howmany = 2; MKL_LONG idistance = 2 * 3; MKL_LONG odistance = 2 * 2; double init[12] = {120, 8, 0, 0, 0, -8, -8, -8, -16, 0, -40, -8}; double *in; in = (double*)malloc(sizeof(double) * 12); for (int i = 0; i < 12; i++) { in[i] = init[i]; } MKL_LONG s = DftiCreateDescriptor(&desc_handle, DFTI_DOUBLE, DFTI_REAL, rank, length); s = DftiSetValue(desc_handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE); s = DftiSetValue(desc_handle, DFTI_INPUT_STRIDES, istrides); s = DftiSetValue(desc_handle, DFTI_OUTPUT_STRIDES, ostrides); s = DftiSetValue(desc_handle, DFTI_THREAD_LIMIT, nthreads); s = DftiSetValue(desc_handle, DFTI_COMPLEX_STORAGE, DFTI_COMPLEX_COMPLEX); s = DftiSetValue(desc_handle, DFTI_NUMBER_OF_TRANSFORMS, howmany); s = DftiSetValue(desc_handle, DFTI_INPUT_DISTANCE, idistance); s = DftiSetValue(desc_handle, DFTI_OUTPUT_DISTANCE, odistance); s = DftiSetValue(desc_handle, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX); s = DftiCommitDescriptor(desc_handle); MKL_Complex16 *out; out = (MKL_Complex16*)malloc(sizeof(MKL_Complex16) * 2 * 2 * howmany); DftiComputeForward(desc_handle, in, out); DftiFreeDescriptor(&desc_handle); free(in); free(out);
After the migration:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include "kfft.h" int rank = 2; kml_fft_iodim64 *dims; dims = (kml_fft_iodim64*)kml_fft_malloc(sizeof(kml_fft_iodim64) * rank); dims[0].n = 2; dims[0].is = 3; dims[0].os = 2; dims[1].n = 3; dims[1].is = 1; dims[1].os = 1; int howmany_rank = 1; kml_fft_iodim64 *howmany_dims; howmany_dims = (kml_fft_iodim64*)kml_fft_malloc(sizeof(kml_fft_iodim64) * howmany_rank); howmany_dims[0].n = 2; howmany_dims[0].is = 2 * 3; howmany_dims[0].os = 2 * 2; double init[12] = {120, 8, 0, 0, 0, -8, -8, -8, -16, 0, -40, -8}; double *in; in = (double*)kml_fft_malloc(sizeof(double) * 12); for (int i = 0; i < 12; i++) { in[i] = init[i]; } kml_fft_complex *out; out = (kml_fft_complex*)kml_fft_malloc(sizeof(kml_fft_complex) * 8); kml_fft_plan plan; plan = kml_fft_plan_guru64_dft_r2c(rank, dims, howmany_rank, howmany_dims, in, out, KML_FFT_ESTIMATE); kml_fft_execute_dft_r2c(plan, in, out); kml_fft_destroy_plan(plan); kml_fft_free(howmany_dims); kml_fft_free(dims); kml_fft_free(in); kml_fft_free(out); /* * out = {{1.200000e+02, 0.000000e+00}, {1.200000e+02, -1.385641e+01}, * {1.360000e+02, 0.000000e+00}, {1.120000e+02, 0.000000e+00}, * {-8.000000e+01, 0.000000e+00}, {2.800000e+01, 2.078461e+01}, * {1.600000e+01, 0.000000e+00}, {-2.000000e+01, -3.464102e+01}} */
- Example: C2R transformBefore the migration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
#include "mkl_cdft.h" #include "mkl_cdft_types.h" DFTI_DESCRIPTOR_HANDLE desc_handle = NULL; MKL_LONG rank = 2; MKL_LONG length[2] = {2, 3}; MKL_LONG istrides[3] = {0, 2, 1}; MKL_LONG ostrides[3] = {0, 3, 1}; MKL_LONG nthreads = 1; MKL_LONG howmany = 2; MKL_LONG idistance = 2 * 2; MKL_LONG odistance = 2 * 3; double init[8][2] = {{120, 0}, {8, 8}, {0, 0}, {0, 16}, {0, 16}, {-8, 8}, {-8, 0}, {-8, 8}}; MKL_Complex16 *in; in = (MKL_Complex16*)malloc(sizeof(MKL_Complex16) * 8); for (int i = 0; i < 8; i++) { in[i].real = init[i][0]; in[i].imag = init[i][1]; } MKL_LONG s = DftiCreateDescriptor(&desc_handle, DFTI_DOUBLE, DFTI_REAL, rank, length); s = DftiSetValue(desc_handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE); s = DftiSetValue(desc_handle, DFTI_INPUT_STRIDES, istrides); s = DftiSetValue(desc_handle, DFTI_OUTPUT_STRIDES, ostrides); s = DftiSetValue(desc_handle, DFTI_THREAD_LIMIT, nthreads); s = DftiSetValue(desc_handle, DFTI_COMPLEX_STORAGE, DFTI_COMPLEX_COMPLEX); s = DftiSetValue(desc_handle, DFTI_NUMBER_OF_TRANSFORMS, howmany); s = DftiSetValue(desc_handle, DFTI_INPUT_DISTANCE, idistance); s = DftiSetValue(desc_handle, DFTI_OUTPUT_DISTANCE, odistance); s = DftiSetValue(desc_handle, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX); s = DftiCommitDescriptor(desc_handle); double *out; out = (double*)malloc(sizeof(double) * 12); DftiComputeBackward(desc_handle, in, out); DftiFreeDescriptor(&desc_handle); free(in); free(out);
After the migration:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include "kfft.h" int rank = 2; kml_fft_iodim64 *dims; dims = (kml_fft_iodim64*)kml_fft_malloc(sizeof(kml_fft_iodim64) * rank); dims[0].n = 2; dims[0].is = 2; dims[0].os = 3; dims[1].n = 3; dims[1].is = 1; dims[1].os = 1; int howmany_rank = 1; kml_fft_iodim64 *howmany_dims; howmany_dims = (kml_fft_iodim64*)kml_fft_malloc(sizeof(kml_fft_iodim64) * howmany_rank); howmany_dims[0].n = 2; howmany_dims[0].is = 2 * 2; howmany_dims[0].os = 2 * 3; double init[8][2] = {{120, 0}, {8, 8}, {0, 0}, {0, 16}, {0, 16}, {-8, 8}, {-8, 0}, {-8, 8}}; kml_fft_complex *in; in = (kml_fft_complex*)kml_fft_malloc(sizeof(kml_fft_complex) * 8); for (int i = 0; i < 8; i++) { in[i].r = init[i][0]; in[i].i = init[i][1]; } double *out; out = (double*)kml_fft_malloc(sizeof(double) * 12); kml_fft_plan plan; plan = kml_fft_plan_guru64_dft_c2r(rank, dims, howmany_rank, howmany_dims, in, out, KML_FFT_ESTIMATE); kml_fft_execute_dft_c2r(plan, in, out); kml_fft_destroy_plan(plan); kml_fft_free(howmany_dims); kml_fft_free(dims); kml_fft_free(in); kml_fft_free(out); /* * out = {1.360000e+02, 7.043078e+01, 1.535692e+02, 1.360000e+02, * 1.258564e+02, 9.814359e+01, -4.000000e+01, -1.971281e+01, * 3.571281e+01, 8.000000e+00, 8.000000e+00, 8.000000e+00} */
Due to the software architecture, different plans are required for calculating different types of Fourier transforms for multiple times in the service code. Similar to MKL, a plan constructed based on the same type of transform can be used for multiple times.