所以我使用cuFFT结合CUDA流功能。我遇到的问题是我似乎无法使cuFFT内核以完全并发运行。以下是我从nvvp获得的结果。每个流在128个大小为128x128的图像上运行2D批量FFT的内核。我设置了3个流来运行3个独立的FFT批量计划。
从图中可以看出,一些内存副本(黄色条)与一些内核计算(紫色,棕色和粉红色条)同时发生。但内核运行根本不是并发的。正如您所注意到的,每个内核都严格遵循彼此。以下是我用于内存复制到设备和内核启动的代码。
for (unsigned int j = 0; j < NUM_IMAGES; j++ ) {
gpuErrchk( cudaMemcpyAsync( dev_pointers_in[j],
image_vector[j],
NX*NY*NZ*sizeof(SimPixelType),
cudaMemcpyHostToDevice,
streams_fft[j]) );
gpuErrchk( cudaMemcpyAsync( dev_pointers_out[j],
out,
NX*NY*NZ*sizeof(cufftDoubleComplex),
cudaMemcpyHostToDevice,
streams_fft[j] ) );
cufftExecD2Z( planr2c[j],
(SimPixelType*)dev_pointers_in[j],
(cufftDoubleComplex*)dev_pointers_out[j]);
}
然后我更改了我的代码,以便我完成所有内存副本(同步)并立即将所有内核发送到流,我得到了以下分析结果:
然后我确认内核没有以并发方式运行。
我查看了一个link,它详细解释了如何通过在#include或代码之前传递“-default-stream per-thread”命令行参数或#define CUDA_API_PER_THREAD_DEFAULT_STREAM来设置利用完全并发性。这是CUDA 7中引入的一个功能。我在MacBook Pro Retina 15'的上面链接中使用GeForce GT750M运行了示例代码(与上面链接中使用的机器相同),并且我能够获得并发内核运行。但我无法让我的cuFFT内核并行运行。
然后我发现这个link有人说cuFFT内核将占用整个GPU,因此没有两个cuFFT内核并行运行。然后我被卡住了。因为我没有找到任何正式的文档来解决CUFFT是否支持并发内核。这是真的吗?有办法解决这个问题吗?
答案 0 :(得分:2)
我假设您在显示的代码之前调用了cufftSetStream()
,适用于每个planr2c[j]
,因此每个计划都与一个单独的流相关联。我在你发布的代码中看不到它。如果您确实希望cufft内核与其他cufft内核重叠,那么将这些内核启动到单独的流是必要的。因此,例如,cufft exec对图像0的调用必须启动到与cufft exec调用图像1不同的流中。
为了让任意两个CUDA操作有可能重叠,他们必须启动到不同的流中。
话虽如此,具有内核执行但不是并发内核的并发内存副本与我对合理大小的FFT的期望大致相同。
128x128 FFT到一阶近似将旋转~15,000个线程,所以如果我的线程块每个约500个线程,那将是30个线程块,这将使GPU保持相当占用,留下不多的&#34;房间&#34;用于其他内核。 (您实际上可以在探查器本身中发现内核的总块数和线程数。)您的GT750m probably has 2 Kepler SMs带a maximum of 16 blocks per SM,因此最大瞬时容量为32个块。由于共享内存使用,寄存器使用或其他因素,特定内核的容量数可能会减少。
您运行的任何GPU的瞬时容量(每SM的最大块数* SM数量)将决定内核重叠(并发)的可能性。如果你通过单个内核启动超过了这个容量,那么它将填充&#34; GPU,防止内核并发一段时间。
理论上,CUFFT内核可以同时运行。但就像任何内核并发场景,CUFFT或其他情况一样,这些内核的资源使用量必须非常低才能真正见证并发性。通常,当您的资源使用率较低时,它意味着内核具有相对较少的线程/线程块。这些内核通常需要很长时间才能执行,这使得实际见证并发性变得更加困难(因为启动延迟和其他延迟因素可能会妨碍)。目击并发内核的最简单方法是让内核具有异常低的资源需求以及异常长的运行时间。对于CUFFT内核或任何其他内核,这通常不是典型情况。
复制和计算的重叠仍然是使用CUFFT的流的有用特性。并行思想在没有理解机器容量和资源限制的基础上,本身就有些不合理。例如,如果内核并发是任意可实现的(&#34;我应该能够使任何2个内核同时运行&#34;),而不考虑容量或资源细节,那么在你同时运行两个内核之后,下一个逻辑步骤是同时转到4,8,16内核。但实际情况是,机器无法同时处理这么多工作。一旦你在单个内核启动中暴露了足够的并行性(松散地翻译为&#34;足够的线程&#34;),通过额外的内核启动暴露额外的工作并行性通常不能使机器运行得更快,或者处理工作更快。