模拟循环GPU利用率

时间:2015-01-30 12:23:03

标签: cuda utilization

我正在努力利用模拟循环。 每个周期都有3个内核启动。 下一步的步长由第二个内核计算。

while (time < end)
{
  kernel_Flux<<<>>>(...);
  kernel_Timestep<<<>>>(d_timestep);
  memcpy(&h_timestep, d_timestep, sizeof(float), ...);  
  kernel_Integrate<<<>>>(d_timestep);
  time += h_timestep;
}

我只需要复制一个浮动。什么是避免不必要同步的最有效方法?

提前谢谢你。 : - )

3 个答案:

答案 0 :(得分:1)

在CUDA中,从默认流运行的所有操作都是同步的。所以在你发布的代码中,内核会一个接一个地运行。从我所看到的内核 kernel_integrate() 取决于内核的结果 kernel_Timestep() ,所以无法避免同步。无论如何,如果内核 kernel_Flux() kernel_Timestep() 处理独立数据,您可以尝试执行它们并行地,在两个不同的流中。

答案 1 :(得分:1)

如果你非常关心迭代时间,你可以设置一个专门用于h_timestep的memcpy的新流(在这种情况下你需要使用cudaMemcpyAsync)。然后使用类似推测执行的东西,在你计算出时间之前循环继续。为此,您必须为接下来的几次迭代设置GPU内存缓冲区。您可以使用循环缓冲区来完成此操作。您还需要使用cudaEventRecordcudaStreamWaitEvent来同步不同的流,这样只有当时间对应于您要覆盖的缓冲区时,才允许下一次迭代继续进行( memcpy流已经完成了这项工作),因为否则你将失去该迭代的状态。

另一个我没有尝试但我怀疑会起作用的潜在解决方案是利用动态并行性。如果您的卡支持,您可以将整个循环放在GPU中。

编辑:

抱歉,我刚才意识到你有第三个内核。您因同步而导致的延迟可能是因为您没有cudaMemcpyAsync?很可能第三个内核的运行时间比memcpy要长。你应该能够毫不拖延地继续前进。唯一需要的同步是在每次迭代之后。

答案 2 :(得分:0)

理想的解决方案是将所有内容移至GPU。但是,我不能这样做,因为我需要在每几次迭代后启动CUDPP compact,它不支持CUDA流,也不支持动态并行。我知道Thrust 1.8库有copy_if方法,它做同样的事情,它正在使用动态并行。问题是它无法使用单独的编译进行编译。

总结一下,现在我使用以下代码:

while (time < end)
{
  kernel_Flux<<<gs,bs, 0, stream1>>>();
  kernel_Timestep<<<gs,bs, 0, stream1>>>(d_timestep);
  cudaEventRecord(event, stream1);
  cudaStreamWaitEvent(mStream2, event, 0);
  memcpyasync(&h_timestep, d_timestep, sizeof(float), ..., stream2);  
  kernel_Integrate<<<>>>(d_timestep);
  cudaStreamSynchronize(stream2);
  time += h_timestep;
}