Вызовы подпрограмм cufft могут быть асинхронными
Это означает, что вызов может вернуться до завершения работы .
Это может толькопроизойти до определенного предела.Есть асинхронная очередь запуска.После заполнения очереди новые слоты в очереди открываются только при отправке элемента очереди.Это означает, что процесс запуска больше не является асинхронным.
Это искажает ваши результаты синхронизации.
Чтобы "исправить" это, добавьте вызов cudaDeviceSynchronize();
перед окончанием каждой области синхронизации (т. Е.непосредственно перед каждым оператором printf
).Это значительно выровняет результаты.Это заставляет всю работу графического процессора завершаться до того, как вы закончите измерение времени.
$ cat t37.cu
#include <cufft.h>
#include <omp.h>
#include <cuda_runtime_api.h>
#include <cstdio>
int main(){
const int NX = 2048;
const int BATCH = 96;
cufftHandle plan;
cufftHandle rev_plan;
cufftDoubleReal *idata;
cufftDoubleComplex *odata;
//int BLOCKSIZE = 1024;
//int gridSize = (NX * BATCH)/BLOCKSIZE;
cufftPlan1d(&plan, NX, CUFFT_D2Z, BATCH);
cufftPlan1d(&rev_plan, NX, CUFFT_Z2D, BATCH);
cudaMalloc((void **) &idata, sizeof(cufftDoubleReal) * NX * BATCH);
cudaMalloc((void **) &odata, sizeof(cufftDoubleComplex) * (NX / 2 + 1) * BATCH);
//inputData << < gridSize, BLOCKSIZE >> > (idata, NX * BATCH);
double sT = omp_get_wtime();
for (int i = 0; i < 500; ++i) {
cufftExecD2Z(plan, idata, odata);
cufftExecZ2D(plan, odata, idata);
}
#ifdef FIX
cudaDeviceSynchronize();
#endif
printf("Time taken: %f\n", omp_get_wtime() - sT);
sT = omp_get_wtime();
for (int i = 0; i < 500; ++i) {
cufftExecD2Z(plan, idata, odata);
cufftExecZ2D(plan, odata, idata);
}
#ifdef FIX
cudaDeviceSynchronize();
#endif
printf("Time taken: %f\n", omp_get_wtime() - sT);
sT = omp_get_wtime();
for (int i = 0; i < 500; ++i) {
cufftExecD2Z(plan, idata, odata);
cufftExecZ2D(plan, odata, idata);
}
#ifdef FIX
cudaDeviceSynchronize();
#endif
printf("Time taken: %f\n", omp_get_wtime() - sT);
sT = omp_get_wtime();
for (int i = 0; i < 500; ++i) {
cufftExecD2Z(plan, idata, odata);
cufftExecZ2D(plan, odata, idata);
}
#ifdef FIX
cudaDeviceSynchronize();
#endif
printf("Time taken: %f\n", omp_get_wtime() - sT);
cudaFree(idata);
cudaFree(odata);
}
$ nvcc -o t37 t37.cu -lcufft -lgomp
$ ./t37
Time taken: 0.007373
Time taken: 0.185308
Time taken: 0.196998
Time taken: 0.196857
$ nvcc -o t37 t37.cu -lcufft -lgomp -DFIX
$ ./t37
Time taken: 0.197076
Time taken: 0.196994
Time taken: 0.196937
Time taken: 0.196916
$
Кто-то может спросить: «Почему общее время без вызова cudaDeviceSynchronize()
явно меньше, чем общее время с ним?»Это в основном по той же причине.Очередь асинхронного запуска полна незавершенной работы, но программа завершает работу (без окончательного cudaDeviceSynchronize()
), прежде чем вся работа в очереди запускается.Это приводит к очевидному расхождению между суммарным общим временем выполнения в каждом случае.Добавляя только последний cudaDeviceSynchronize()
вызов, можно наблюдать этот эффект.