#include #include #include #include #include static const char *kernelSource = "#pragma OPENCL EXTENSION cl_khr_fp64 : enable \n" \ "__kernel void mult(__global double *v) { \n" \ " int id, v_re, v_im; \n" \ " id = get_global_id(0); \n" \ " v_re = 2*id; \n" \ " v_im = v_re + 1; \n" \ " \n" \ " v[v_re] = 2*v[v_re]; \n" \ " v[v_im] = 4*v[v_im]; \n" \ "} \n" \ "\n" ; int roundUpToNearest(int x, int n) { /* Rounds x UP to nearest multiple of n. */ int x_rem = x % n; if (x_rem == 0) return x; return x + (n - x_rem); } void checkIfArraysEqual(double *h_v, double *v, int N, double epsilon) { int arrays_equal = 1; int i; for (i=0; i epsilon) arrays_equal = 0; } if (arrays_equal) printf("Arrays are equal!\n"); else printf("Arrays are NOT equal!\n"); } int main( int argc, char* argv[] ) { /* This setup is a bit tricky. Since we're doing a real transform, CLFFT * requires N+2 elements in the array. This is because only N/2 + 1 numbers * are calculated, and since each number is complex, it requires 2 elements * for space. * * To avoid warp divergence, we want to avoid any conditionals in the * kernel. Thus we cannot check to see if the thread ID is even or odd to * act on a real number or imaginary number. To do this, one thread should * handle one complex number (one real, one imag), i.e. ID_j should handle * array elements j, j+1. * * But we also need the number of global items to be a multiple of 32 (warp * size). What we can do, for example, N = 128, is pad it by 2 (130), * divide it by 2 (65), round that UP to the nearest 32 (96), multiply that * by 2 (192). The kernel will operate on zeros, but it should be faster * than the scenario with warp divergence. */ unsigned int N = 4096; unsigned int N_pad = 2*roundUpToNearest( (N+2)/2, 32 ); size_t N_bytes = N_pad * sizeof(double); // openCL declarations cl_platform_id platform; cl_device_id device_id; cl_context context; cl_command_queue queue; cl_program program; cl_kernel k_mult; // clFFT declarations clfftPlanHandle planHandleForward, planHandleBackward; clfftDim dim = CLFFT_1D; size_t clLengths[1] = {N}; clfftSetupData fftSetup; clfftInitSetupData(&fftSetup); clfftSetup(&fftSetup); // host version of v double *h_v; h_v = (double*) malloc(N_bytes); // initialize v on host (GPU and CPU) int i; for (i = 0; i < N; i++) h_v[i] = i; // CPU TRANSFORM ---------------------------------------------------------- double *v; fftw_complex *V; int N_COMPLEX = N/2 + 1; int REAL = 0; int IMAG = 1; v = (double*) malloc(N * sizeof(double)); V = (fftw_complex*) malloc(N_COMPLEX * sizeof(fftw_complex)); fftw_plan fft = fftw_plan_dft_r2c_1d(N, v, V, FFTW_MEASURE); fftw_plan ifft = fftw_plan_dft_c2r_1d(N, V, v, FFTW_MEASURE); // initialize v here because otherwise fftw_execute will run before we // initialize the plan... for some reason. for (i=0; i