我正在运行一个大型数值模拟,我设计使用CUDA在GPU设备上运行。我不想在每个时间步将整个数据传输到CPU,我只是希望它在前一个步骤完成后立即计算每个新的时间步长。此外,有两种更新方法需要串联实现,我发现最好以异步方式实现。
示意图,它看起来像这样:
#define NSTREAMS 7
#define ITEMS 1000000 // ITEMS is of the order 10^5 -- 10^7
__global__ void updateDomain1(float* domain, float* start, unsigned int nItems);
__global__ void updateDomain2(float* domain, float* start, unsigned int nItems);
main(int argc, char* argv [])
{
cudaStream_t streams [NSTREAMS];
float* domain_cpu = new float [ITEMS];
float* domain_gpu;
/* ... Set up everything here... */
// Run the whole simulation:
while (continueRunning)
{
for(int ii = 0; ii < NSTREAMS; ++ii)
{
updateDomain1<<<threads, blocks, 0, streams[ii]>>>(domain_gpu, domain_gpu + ITEMS / NSTREAMS * ii, ITEMS / NSTREAMS);
updateDomain2<<<threads, blocks, 0, streams[ii]>>>(domain_gpu, domain_gpu + ITEMS / NSTREAMS * ii, ITEMS / NSTREAMS);
}
}
// In the end, transfer everything back to the CPU
cudaMemcpy(domain_cpu, domain_gpu, sizeof(float) * ITEMS, cudaMemcpyDeviceToHost)
}
这很有效。但是,现在我想在每个时间步记录域中一个点的单个值。我真的只对一个值感兴趣,所以我写了以下内容并在for
- 循环后插入:
float getValueAtIndex(const float* const domain_gpu, const unsigned int index) {
float temp;
cudaMemcpy(&temp, domain_gpu + index, sizeof(float), cudaMemcpyDeviceToHost) );
return temp;
}
并将每个值存储在一个数组中。但是,这会使模拟速度变慢。特别是对于相对较小的ITEMS
值,它可以减慢2倍。原因似乎是所有异步更新方法需要在内存传输发生之前完成,然后必须等待这也完成了。但是,我不能将内存传输放在异步内存传输中,因为它可能会记录一个尚未更新的值。
有没有更好的方法来记录这个值而不会减慢整个过程?