while-loop - 在迭代循环中避免 CudaMemcpy

标签 while-loop cuda

我想知道在 Cuda 中执行以下操作的最佳方法是什么:假设*您有一个长数组并希望所有元素的总和小于 1。如果总和大于 1,则将每个元素除以 2并再次计算总和。除以二并计算总和是在 gpu 上完成的。我现在的问题是:在 cpu 端检查总和是否低于 1 的最佳方法是什么?我可以在每次迭代中执行 cudaMemcpy,但我也读到(并且已经看到)最好在两个内存之间进行尽可能少的传输。我发现了动态并行,我想也许我用一个 block 和一个执行 while 循环并调用求和和除法内核的线程启动内核,但不幸的是我的硬件只有计算能力 3.2 和动态并行仅从 3.5 开始。那么除了每次迭代都执行 cudaMemcpy 来告诉 cpu 它可以停止执行 while 循环之外,还有其他方法吗?

*上面的算法只是一个用来解释情况的玩具问题(希望如此)。实际算法是 newton-raphson 方法,但我的问题对于任何迭代方法仍然有效,我必须决定是否停止或不给出在 gpu 上计算的值。

最佳答案

对于 >= 3.5 的计算能力,正如您正确识别的那样,答案可能是动态并行性。

对于 < 3.5 的计算能力,事情不太清楚。有两种选择:第一种是查看 memcpy 和内核启动的延迟成本。第二个是使用更高级的技术来更好地控制您的 block 。

延迟优化

如果使用 memcpy,请确保在启动 memcpy 之前不进行同步。如果您不同步,那么与副本相关的大部分开销都可以被内核隐藏。

也就是说,这种情况下的最低延迟路径可能是使用映射内存找到的:http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#mapped-memory .通过使用映射内存,内核将直接写入主机内存,而无需显式启动 cudaMemcpy。

block 控制

对于这个问题,我们实际上并不需要全局同步,因此通过聪明的做法,我们可以避免对主机的一些访问。在这种情况下,我会考虑超额订阅 GPU。如果您知道需要 x block 来完成问题的迭代,请考虑启动,例如 5x block 。因为启动 block 的顺序是未定义的,所以您需要使用原子创建一个顺序(每个 block 以原子方式递增一个全局整数一次)。

通过此 block 排序,您现在知道哪些 block 将参与迭代的第一步。任何未参与第一次迭代的 block 都可以通过在标志上旋转来等待:

do {
  locked = volatileLoad(flag); // Make sure this is volatile
}
while (locked);

一旦第一批 block 完成其操作,并且输出被写入全局内存,您可以设置标志(确保您正确使用 threadfence!)允许下一步的 block 开始。如果您的条件已经满足,那么这些 block 可以执行下一步,或者立即返回(在允许依赖于它们的 block 继续之后)。

这样做的最终结果是我们已经在 GPU 上准备好 block 等待启动。通过管理我们的 block 排序,我们知道每次迭代总是会有足够的 block 来完成,所以旋转 block 总是会被释放。您需要确保正确的三件事是:

  1. 您使用原子管理您自己的 block ID。
  2. 您使用 volatile 关键字加载标志以确保读取正确的值。
  3. 在允许相关 block 继续之前,您应用线程防护以确保输出可见。

显然,启动正确数量的 block 是不太可能的,因此您将不得不不时返回主机以启动更多 block 。启动太多 block 的开销应该不会太糟糕,但也会有风险。

在您实现此操作之前,请确保您的副本的延迟成本确实导致了显着的减速。复制到主机并有条件地启动另一个内核的开销应该是每次迭代 20 微秒的量级。这种方法会给您的代码增加相当多的复杂性,因此请确保您需要节省这些微秒!

关于while-loop - 在迭代循环中避免 CudaMemcpy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30119155/

相关文章:

c - 在 C 中用 scanf 循环

c - 为什么“while(!feof(file))”总是错误的?

cuda - 在 CUDA 中求解一般稀疏线性系统

optimization - CUDA:同步线程

java - 1-10 之间的正整数的阶乘。问题: Works only if valid input is greater than previous input

javascript - 我无法理解我的 If 陈述如何被视为真实

c++ - 为什么 C++ 中的分号似乎隐式处理错误? [tldr : they don't]

c++ - CUDA 设备代码支持哪些真正的 C++ 语言结构?

visual-studio-2010 - VS 2010 中的 .cu 文件没有颜色

c++ - CUDA推力库中的函数是否隐式同步?