Cuda 为什么以下程序的同一个袖口代码需要不同的时间?

Cuda 为什么以下程序的同一个袖口代码需要不同的时间?,cuda,cufft,Cuda,Cufft,我在cuft(cuda9)(nvidia1080)中运行了以下代码。所有执行的代码都是相同的。但是,执行时间(代码下方)变化很大。有谁能描述一下如何始终获得最短时间以及这种行为背后的原因吗 int NX 2048 int BATCH 96 cufftHandle plan; cufftHandle rev_plan; cufftDoubleReal *idata; cufftDoubleComplex *odata; int BLOCKSIZE = 1024; int gridSize =

我在cuft(cuda9)(nvidia1080)中运行了以下代码。所有执行的代码都是相同的。但是,执行时间(代码下方)变化很大。有谁能描述一下如何始终获得最短时间以及这种行为背后的原因吗

int NX 2048
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);
}
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);
}
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);
}
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);
}
printf("Time taken: %f\n", omp_get_wtime() - sT);

cudaFree(idata);
cudaFree(odata);
intnx 2048
int第96批
卡夫坦德尔计划;
卡夫坦德尔修订计划;
袖口双耳*伊达塔;
袖套双复体*odata;
int BLOCKSIZE=1024;
int gridSize=(NX*批处理)/BLOCKSIZE;
袖口平面1D(和平面,NX,袖口D2Z,批次);
袖口平面1D(和修订平面,NX,袖口平面Z2D,批次);
Cudamaloc((空隙**)和idata,尺寸(袖口双耳)*NX*批次);
cudaMalloc((void**)和odata,尺寸为(Cuftdoublecomplex)*(NX/2+1)*批次);
输入数据>>(idata,NX*批次);
double sT=omp_get_wtime();
对于(int i=0;i<500;++i){
cufftExecD2Z(平面图、idata、odata);
cufftExecZ2D(平面图、odata、idata);
}
printf(“所用时间:%f\n”,omp\u get\u wtime()-sT);
sT=omp_get_wtime();
对于(int i=0;i<500;++i){
cufftExecD2Z(平面图、idata、odata);
cufftExecZ2D(平面图、odata、idata);
}
printf(“所用时间:%f\n”,omp\u get\u wtime()-sT);
sT=omp_get_wtime();
对于(int i=0;i<500;++i){
cufftExecD2Z(平面图、idata、odata);
cufftExecZ2D(平面图、odata、idata);
}
printf(“所用时间:%f\n”,omp\u get\u wtime()-sT);
sT=omp_get_wtime();
对于(int i=0;i<500;++i){
cufftExecD2Z(平面图、idata、odata);
cufftExecZ2D(平面图、odata、idata);
}
printf(“所用时间:%f\n”,omp\u get\u wtime()-sT);
郁金香;
cudaFree(odata);
所用时间:0.004334 所用时间:0.022906 所用时间:0.027820
所用时间:0.027786

对cufft例程的调用可以是异步的

这意味着在工作完成之前,呼叫可能会返回

这只能在一定限度内发生。有一个异步启动队列。填充队列后,队列中的新插槽仅在调度队列项目时打开。这意味着启动过程不再是异步的

这会扭曲你的计时结果

要“修复”此问题,请添加一个
cudaDeviceSynchronize()在每个计时区域结束之前调用(即在每个
printf
语句之前)。这将大大平衡结果。这将强制所有GPU工作在完成计时测量之前完成

$ 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
$
$cat t37.cu
#包括
#包括
#包括
#包括
int main(){
常数int NX=2048;
常数int批=96;
卡夫坦德尔计划;
卡夫坦德尔修订计划;
袖口双耳*伊达塔;
袖套双复体*odata;
//int BLOCKSIZE=1024;
//int gridSize=(NX*批处理)/BLOCKSIZE;
袖口平面1D(和平面,NX,袖口D2Z,批次);
袖口平面1D(和修订平面,NX,袖口平面Z2D,批次);
Cudamaloc((空隙**)和idata,尺寸(袖口双耳)*NX*批次);
cudaMalloc((void**)和odata,尺寸为(Cuftdoublecomplex)*(NX/2+1)*批次);
//输入数据>>(idata,NX*批次);
double sT=omp_get_wtime();
对于(int i=0;i<500;++i){
cufftExecD2Z(平面图、idata、odata);
cufftExecZ2D(平面图、odata、idata);
}
#ifdef修复
cudaDeviceSynchronize();
#恩迪夫
printf(“所用时间:%f\n”,omp\u get\u wtime()-sT);
sT=omp_get_wtime();
对于(int i=0;i<500;++i){
cufftExecD2Z(平面图、idata、odata);
cufftExecZ2D(平面图、odata、idata);
}
#ifdef修复
cudaDeviceSynchronize();
#恩迪夫
printf(“所用时间:%f\n”,omp\u get\u wtime()-sT);
sT=omp_get_wtime();
对于(int i=0;i<500;++i){
cufftExecD2Z(平面图、idata、odata);
cufftExecZ2D(平面图、odata、idata);
}
#ifdef修复
cudaDeviceSynchronize();
#恩迪夫
printf(“所用时间:%f\n”,omp\u get\u wtime()-sT);
sT=omp_get_wtime();
对于(int i=0;i<500;++i){
cufftExecD2Z(平面图、idata、odata);
cufftExecZ2D(平面图、odata、idata);
}
#ifdef修复
cudaDeviceSynchronize();
#恩迪夫
printf(“所用时间:%f\n”,omp\u get\u wtime()-sT);
郁金香;
cudaFree(odata);
}
$nvcc-o t37 t37.cu-lcufft-lgomp
美元/t37
所用时间:0.007373
所用时间:0.185308
所用时间:0.196998
所用时间:0.196857
$nvcc-o t37 t37.cu-lcufft-lgomp-DFIX
美元/t37
所用时间:0.197076
所用时间:0.196994
所用时间:0.196937
所用时间:0.196916
$

有人可能会问,“为什么不调用
cudaDeviceSynchronize()
的总时间明显低于使用它的总时间?”这基本上是由于相同的原因。异步启动队列中充满了挂起的工作,但程序在队列中的所有工作启动之前终止(没有最终的
cudaDeviceSynchronize()
)。这导致在每种情况下,总执行时间之和之间存在明显差异。通过只添加最后一个
cudaDeviceSynchronize()
调用,可以观察到这种效果。

我明白了。您可以参考文档吗?文档中指出,在某些情况下可能会发生“异步计算”。这是我能提供的最好的答案。在你的最后一段中,你可能是指“没有”而不是“有”。