- added out-of-place real transform to example05
- makefile now uses system-installed version of clFFT
This commit is contained in:
10
Makefile
10
Makefile
@@ -1,14 +1,19 @@
|
|||||||
CXX = gcc
|
CXX = gcc
|
||||||
|
|
||||||
# clFFT lib & inc
|
# clFFT lib & inc
|
||||||
CLFFT_LIB = -lOpenCL -L./usr/local/lib64 -lclFFT
|
CLFFT_LIB = -L/usr/local/cuda-7.0/targets/x86_64-linux/lib -lOpenCL -L./usr/local/lib64 -lclFFT
|
||||||
CLFFT_INCLUDE = -I./clFFT/build/package/include
|
|
||||||
|
|
||||||
# standard math library
|
# standard math library
|
||||||
CXXFLAGS = -c $(CLFFT_INCLUDE)
|
CXXFLAGS = -c $(CLFFT_INCLUDE)
|
||||||
LDFLAGS = -lm $(CLFFT_LIB) -lfftw3 -lm
|
LDFLAGS = -lm $(CLFFT_LIB) -lfftw3 -lm
|
||||||
EXE = Example
|
EXE = Example
|
||||||
|
|
||||||
|
# ignore warnings when compiling if warn=0
|
||||||
|
ifeq ($(warn), 0)
|
||||||
|
CXXFLAGS += -w
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
all: ex04 ex05
|
all: ex04 ex05
|
||||||
|
|
||||||
ex04: example04/build/main.o
|
ex04: example04/build/main.o
|
||||||
@@ -24,7 +29,6 @@ ex05: example05/build/main.o
|
|||||||
@if [ ! -d "./example05/bin" ]; then mkdir ./example05/bin; fi
|
@if [ ! -d "./example05/bin" ]; then mkdir ./example05/bin; fi
|
||||||
$(CXX) $< $(LDFLAGS) -o example05/bin/$(EXE)
|
$(CXX) $< $(LDFLAGS) -o example05/bin/$(EXE)
|
||||||
|
|
||||||
# create object file (compile without linking)
|
|
||||||
example05/build/main.o: example05/main.c
|
example05/build/main.o: example05/main.c
|
||||||
@if [ ! -d "./example05/build" ]; then mkdir ./example05/build; fi
|
@if [ ! -d "./example05/build" ]; then mkdir ./example05/build; fi
|
||||||
$(CXX) $(CXXFLAGS) $< -o $@
|
$(CXX) $(CXXFLAGS) $< -o $@
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ An example of the CLFFT library for an in-place complex-planar transform. There
|
|||||||
- for Python, numpy and scipy are required
|
- for Python, numpy and scipy are required
|
||||||
|
|
||||||
## example 05
|
## example 05
|
||||||
Another CLFFT example where an in-place real transform is performed. There's also FFTW code and Python code for checking the answer.
|
Another CLFFT example where an in-place real transform and an out-of-place real transform are performed. There's also FFTW code and Python code for checking the answer.
|
||||||
|
|
||||||
- clFFT is required; installation instructions can be found inside example04/README.md
|
- clFFT is required; installation instructions can be found inside example04/README.md
|
||||||
- FFTW is required; installation is as simple as extracting FFTW's tar file, then running `./configure && sudo make && sudo make install`
|
- FFTW is required; installation is as simple as extracting FFTW's tar file, then running `./configure && sudo make && sudo make install`
|
||||||
|
|||||||
138
example05/main.c
138
example05/main.c
@@ -4,7 +4,8 @@
|
|||||||
#include <clFFT.h>
|
#include <clFFT.h>
|
||||||
#include <fftw3.h>
|
#include <fftw3.h>
|
||||||
|
|
||||||
const char *kernelSource =
|
|
||||||
|
static const char *kernelSource =
|
||||||
"#pragma OPENCL EXTENSION cl_khr_fp64 : enable \n" \
|
"#pragma OPENCL EXTENSION cl_khr_fp64 : enable \n" \
|
||||||
"__kernel void mult(__global double *v) { \n" \
|
"__kernel void mult(__global double *v) { \n" \
|
||||||
" int id, v_re, v_im; \n" \
|
" int id, v_re, v_im; \n" \
|
||||||
@@ -28,6 +29,23 @@ int roundUpToNearest(int x, int n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void checkIfArraysEqual(double *h_v, double *v, int N, double epsilon) {
|
||||||
|
int arrays_equal = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<N; i++) {
|
||||||
|
// printf("[%f %f] ", h_v[i], v[i]);
|
||||||
|
if (abs(v[i] - h_v[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[] ) {
|
int main( int argc, char* argv[] ) {
|
||||||
/* This setup is a bit tricky. Since we're doing a real transform, CLFFT
|
/* 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
|
* requires N+2 elements in the array. This is because only N/2 + 1 numbers
|
||||||
@@ -46,7 +64,7 @@ int main( int argc, char* argv[] ) {
|
|||||||
* by 2 (192). The kernel will operate on zeros, but it should be faster
|
* by 2 (192). The kernel will operate on zeros, but it should be faster
|
||||||
* than the scenario with warp divergence. */
|
* than the scenario with warp divergence. */
|
||||||
|
|
||||||
unsigned int N = 2048;
|
unsigned int N = 4096;
|
||||||
unsigned int N_pad = 2*roundUpToNearest( (N+2)/2, 32 );
|
unsigned int N_pad = 2*roundUpToNearest( (N+2)/2, 32 );
|
||||||
size_t N_bytes = N_pad * sizeof(double);
|
size_t N_bytes = N_pad * sizeof(double);
|
||||||
|
|
||||||
@@ -75,6 +93,37 @@ int main( int argc, char* argv[] ) {
|
|||||||
for (i = 0; i < N; i++)
|
for (i = 0; i < N; i++)
|
||||||
h_v[i] = 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<N; i++)
|
||||||
|
v[i] = i;
|
||||||
|
|
||||||
|
fftw_execute(fft);
|
||||||
|
for (i=0; i<N_COMPLEX; i++) {
|
||||||
|
V[i][REAL] = 2 * V[i][REAL];
|
||||||
|
V[i][IMAG] = 4 * V[i][IMAG];
|
||||||
|
}
|
||||||
|
fftw_execute(ifft);
|
||||||
|
|
||||||
|
// scale array as FFTW doesn't automatically do this for back transform
|
||||||
|
for (i=0; i<N; i++)
|
||||||
|
v[i] = v[i]/N;
|
||||||
|
|
||||||
|
|
||||||
|
// GPU STUFF --------------------------------------------------------------
|
||||||
// global & local number of threads
|
// global & local number of threads
|
||||||
size_t globalSize, localSize;
|
size_t globalSize, localSize;
|
||||||
globalSize = N_pad / 2;
|
globalSize = N_pad / 2;
|
||||||
@@ -103,10 +152,11 @@ int main( int argc, char* argv[] ) {
|
|||||||
k_mult = clCreateKernel(program, "mult", &err);
|
k_mult = clCreateKernel(program, "mult", &err);
|
||||||
|
|
||||||
// create arrays on host and write them
|
// create arrays on host and write them
|
||||||
cl_mem d_v;
|
cl_mem d_v, d_V;
|
||||||
d_v = clCreateBuffer(context, CL_MEM_READ_WRITE, N_bytes, NULL, NULL);
|
d_v = clCreateBuffer(context, CL_MEM_READ_WRITE, N_bytes, NULL, NULL);
|
||||||
err = clEnqueueWriteBuffer(queue, d_v, CL_TRUE, 0, N_bytes, h_v, 0, NULL, NULL);
|
err = clEnqueueWriteBuffer(queue, d_v, CL_TRUE, 0, N_bytes, h_v, 0, NULL, NULL);
|
||||||
|
|
||||||
|
// REAL IN-PLACE TRANSFORM ------------------------------------------------
|
||||||
// create forward plan and set its params
|
// create forward plan and set its params
|
||||||
clfftCreateDefaultPlan(&planHandleForward, context, dim, clLengths);
|
clfftCreateDefaultPlan(&planHandleForward, context, dim, clLengths);
|
||||||
clfftSetPlanPrecision(planHandleForward, CLFFT_DOUBLE);
|
clfftSetPlanPrecision(planHandleForward, CLFFT_DOUBLE);
|
||||||
@@ -126,59 +176,55 @@ int main( int argc, char* argv[] ) {
|
|||||||
// FFT data, multiply elements, IFFT data
|
// FFT data, multiply elements, IFFT data
|
||||||
clfftEnqueueTransform(planHandleForward, CLFFT_FORWARD, 1, &queue, 0, NULL, NULL, &d_v, NULL, NULL);
|
clfftEnqueueTransform(planHandleForward, CLFFT_FORWARD, 1, &queue, 0, NULL, NULL, &d_v, NULL, NULL);
|
||||||
clFinish(queue);
|
clFinish(queue);
|
||||||
|
|
||||||
err = clEnqueueNDRangeKernel(queue, k_mult, 1, NULL, &globalSize, &localSize, 0, NULL, NULL);
|
err = clEnqueueNDRangeKernel(queue, k_mult, 1, NULL, &globalSize, &localSize, 0, NULL, NULL);
|
||||||
clFinish(queue);
|
clFinish(queue);
|
||||||
|
|
||||||
clfftEnqueueTransform(planHandleBackward, CLFFT_BACKWARD, 1, &queue, 0, NULL, NULL, &d_v, NULL, NULL);
|
clfftEnqueueTransform(planHandleBackward, CLFFT_BACKWARD, 1, &queue, 0, NULL, NULL, &d_v, NULL, NULL);
|
||||||
clFinish(queue);
|
clFinish(queue);
|
||||||
|
|
||||||
// transfer back
|
|
||||||
clEnqueueReadBuffer(queue, d_v, CL_TRUE, 0, N_bytes, h_v, 0, NULL, NULL );
|
clEnqueueReadBuffer(queue, d_v, CL_TRUE, 0, N_bytes, h_v, 0, NULL, NULL );
|
||||||
clFinish(queue);
|
clFinish(queue);
|
||||||
|
|
||||||
// do CPU equivalent
|
clfftDestroyPlan( &planHandleForward );
|
||||||
double *v;
|
clfftDestroyPlan( &planHandleBackward );
|
||||||
fftw_complex *V;
|
printf("Testing in-place real transform... ");
|
||||||
int N_COMPLEX = N/2 + 1;
|
checkIfArraysEqual(h_v, v, N, 0.0);
|
||||||
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<N; i++)
|
|
||||||
v[i] = i;
|
|
||||||
|
|
||||||
fftw_execute(fft);
|
|
||||||
for (i=0; i<N_COMPLEX; i++) {
|
|
||||||
V[i][REAL] = 2 * V[i][REAL];
|
|
||||||
V[i][IMAG] = 4 * V[i][IMAG];
|
|
||||||
}
|
|
||||||
fftw_execute(ifft);
|
|
||||||
|
|
||||||
// scale array as FFTW doesn't automatically do this for back transform
|
|
||||||
for (i=0; i<N; i++)
|
|
||||||
v[i] = v[i]/N;
|
|
||||||
|
|
||||||
|
|
||||||
double epsilon = 0.0;
|
|
||||||
int arrays_equal = 1;
|
|
||||||
for (i=0; i<N; i++) {
|
|
||||||
printf("[%f %f] ", h_v[i], v[i]);
|
|
||||||
if (abs(v[i] - h_v[i]) > epsilon)
|
|
||||||
arrays_equal = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arrays_equal)
|
// REAL OUT-OF-PLACE TRANSFORM --------------------------------------------
|
||||||
printf("Arrays are equal!\n");
|
// reset array
|
||||||
else
|
d_v = clCreateBuffer(context, CL_MEM_READ_WRITE, N_bytes, NULL, NULL);
|
||||||
printf("Arrays are NOT equal!\n");
|
d_V = clCreateBuffer(context, CL_MEM_READ_WRITE, N_bytes, NULL, NULL);
|
||||||
|
|
||||||
|
cl_mem inputBuffers[1] = {0}, outputBuffers[1] = {0};
|
||||||
|
inputBuffers[0] = d_v;
|
||||||
|
outputBuffers[0] = d_V;
|
||||||
|
|
||||||
|
err = clEnqueueWriteBuffer(queue, d_v, CL_TRUE, 0, N_bytes, h_v, 0, NULL, NULL);
|
||||||
|
|
||||||
|
clfftCreateDefaultPlan(&planHandleForward, context, dim, clLengths);
|
||||||
|
clfftSetPlanPrecision(planHandleForward, CLFFT_DOUBLE);
|
||||||
|
clfftSetLayout(planHandleForward, CLFFT_REAL, CLFFT_HERMITIAN_INTERLEAVED);
|
||||||
|
clfftSetResultLocation(planHandleForward, CLFFT_OUTOFPLACE);
|
||||||
|
clfftBakePlan(planHandleForward, 1, &queue, NULL, NULL);
|
||||||
|
|
||||||
|
clfftCreateDefaultPlan(&planHandleBackward, context, dim, clLengths);
|
||||||
|
clfftSetPlanPrecision(planHandleBackward, CLFFT_DOUBLE);
|
||||||
|
clfftSetLayout(planHandleBackward, CLFFT_HERMITIAN_INTERLEAVED, CLFFT_REAL);
|
||||||
|
clfftSetResultLocation(planHandleBackward, CLFFT_OUTOFPLACE);
|
||||||
|
clfftBakePlan(planHandleBackward, 1, &queue, NULL, NULL);
|
||||||
|
|
||||||
|
clfftEnqueueTransform(planHandleForward, CLFFT_FORWARD, 1, &queue, 0, NULL, NULL, &inputBuffers, &outputBuffers, NULL);
|
||||||
|
clFinish(queue);
|
||||||
|
err = clEnqueueNDRangeKernel(queue, k_mult, 1, NULL, &globalSize, &localSize, 0, NULL, NULL);
|
||||||
|
clFinish(queue);
|
||||||
|
clfftEnqueueTransform(planHandleBackward, CLFFT_BACKWARD, 1, &queue, 0, NULL, NULL, &inputBuffers, &outputBuffers, NULL);
|
||||||
|
clFinish(queue);
|
||||||
|
clEnqueueReadBuffer(queue, d_v, CL_TRUE, 0, N_bytes, h_v, 0, NULL, NULL );
|
||||||
|
clFinish(queue);
|
||||||
|
|
||||||
|
printf("Testing out-of-place transform... ");
|
||||||
|
checkIfArraysEqual(h_v, v, N, 0.0);
|
||||||
|
|
||||||
|
|
||||||
// release FFT stuff
|
// release FFT stuff
|
||||||
fftw_free(V);
|
fftw_free(V);
|
||||||
|
|||||||
Reference in New Issue
Block a user