我正在尝试分别使用FFTW和clFFT来测量和比较CPU和GPU上fft的性能。
对于一次迭代或一次转换,GPU似乎可以更快地进行计算。数据在大小和大小上都是相同的。我正在尝试仅计算计算fft所需的时间。对于CPU和FFTW,我使用clock()C函数来测量时间;对于GPU和clFFT,我使用OpenCL API提供的事件分析工具。
当我尝试多次进行相同的转换时,就会出现问题。当我进行多次迭代时,clFFT性能似乎迅速下降。随着变换重复次数的增加,最终CPU和GPU花费相同的时间来完成计算,而CPU和FFTW的性能稍好一些。
我的系统是: CPU:Intel i3 4690, GPU:Nvidia GTX 960 2gb, 作业系统:Linux, 设备OpenCL版本:1.2, 对于CPU,我使用FFTW库, 对于GPU和OpenCL,我使用clFFT库。
单一转换方案:
fftw.c
...
fftw_plan plan_signal_fft = fftw_plan_dft_1d(SAMPLES_PER_CODE, signalComplex, signalComplex_freq, FFTW_FORWARD, FFTW_ESTIMATE);
clock_t start, end;
// execute it once in case there is any initialization by the fftw library
fftw_execute(plan_signal_fft);
start = clock();
fftw_execute(plan_signal_fft);
end = clock();
double t = ((double)(end - start)) / CLOCKS_PER_SEC;
...
t = 0.000100秒
clFFT.c
...
ctx = clCreateContext(NULL, 1, &device_id, NULL, NULL, &return_val);
queue = clCreateCommandQueue(ctx, device_id, CL_QUEUE_PROFILING_ENABLE, &return_val);
clfftPlanHandle planHandle;
clfftDim dim = CLFFT_1D;
size_t clLengths[1] = {SAMPLES_PER_CODE};
clfftSetupData fftSetup;
return_val = clfftInitSetupData(&fftSetup);
return_val = clfftSetup(&fftSetup);
buff = clCreateBuffer(ctx, CL_MEM_READ_WRITE, SAMPLES_PER_CODE*2*sizeof(double), NULL, &return_val);
buff_results = clCreateBuffer(ctx, CL_MEM_READ_WRITE, SAMPLES_PER_CODE*2*sizeof(double), NULL, &return_val);
return_val = clEnqueueWriteBuffer(queue, buff, CL_TRUE, 0, SAMPLES_PER_CODE*2*sizeof(double), signalComplex, 0, NULL, NULL);
// read buffer
clFinish(queue);
return_val = clfftCreateDefaultPlan(&planHandle, ctx, dim, clLengths);
return_val = clfftSetPlanPrecision(planHandle, CLFFT_DOUBLE);
return_val = clfftSetResultLocation(planHandle, CLFFT_OUTOFPLACE);
return_val = clfftBakePlan(planHandle, 1, &queue, NULL, NULL);
return_val = clfftEnqueueTransform(planHandle, CLFFT_FORWARD, 1, &queue, 0, NULL, &event, &buff, &buff_results, NULL);
clWaitForEvents(1, &event);
return_val = clFinish(queue);
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(time_start), &time_start, NULL);
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(time_end), &time_end, NULL);
double nanoSeconds = time_end - time_start;
double t = nanoSeconds*pow(10,-9) // get seconds
...
t = 0.000010秒
循环场景:
fftw.c
...
start = clock();
for(i = 0; i < 20000; i++){
fftw_execute(plan_signal_fft);
}
end = clock();
...
t = 1.614688秒
clfft.c
...
return_val = clfftEnqueueTransform(planHandle, CLFFT_FORWARD, 1, &queue, 0, NULL, &event, &buff, &buff_results, NULL);
clWaitForEvents(1, &event);
return_val = clFinish(queue);
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(time_start), &time_start, NULL);
for(i = 0; i < 19998; i++){
return_val = clfftEnqueueTransform(planHandle, CLFFT_FORWARD, 1, &queue, 0, NULL, NULL, &buff, &buff_results, NULL);
return_val = clFinish(queue);
}
return_val = clfftEnqueueTransform(planHandle, CLFFT_FORWARD, 1, &queue, 0, NULL, &event, &buff, &buff_results, NULL);
clWaitForEvents(1, &event);
return_val = clFinish(queue);
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(time_end), &time_end, NULL);
double nanoSeconds = time_end - time_start;
...
t = 1.945254秒
在两种情况下我都得到相同的结果,因此变换是正确的。但是我不知道我是否在OpenCL和clFFT中执行正确的迭代。为什么对于一次变换而言,clFFT比FFTW快,而一旦我重复相同的变换,clFFT的性能就会大大下降?
谢谢。