【问题标题】:Pycuda ConcurrencyPycuda 并发
【发布时间】:2016-08-27 23:46:46
【问题描述】:

为什么PyCuda KernelConcurrency Example 中的代码在“并发”模式下不能运行得更快?我的 GPU 上似乎应该有足够的资源......我错过了什么?

这是“并发”版本的输出,第 63 行未注释:

=== Device attributes
Name: GeForce GTX 980
Compute capability: (5, 2)
Concurrent Kernels: True

=== Checking answers
Dataset 0 : passed.
Dataset 1 : passed.

=== Timing info (for last set of kernel launches)
Dataset 0
kernel_begin : 1.68524801731
kernel_end : 1.77305603027
Dataset 1
kernel_begin : 1.7144639492
kernel_end : 1.80246400833

这是第 63 行注释掉的版本。这应该不再同时运行,并且应该明显变慢。它在我看来几乎相同(两种情况下大约为 0.08 - 0.09):

=== Device attributes
Name: GeForce GTX 980
Compute capability: (5, 2)
Concurrent Kernels: True

=== Checking answers
Dataset 0 : passed.
Dataset 1 : passed.

=== Timing info (for last set of kernel launches)
Dataset 0
kernel_begin : 1.20230400562
kernel_end : 1.28966403008
Dataset 1
kernel_begin : 1.21827197075
kernel_end : 1.30672001839

这里有什么我遗漏的吗?还有其他测试并发的方法吗?

【问题讨论】:

  • 我不明白你想在这里问什么。第一段与问题的其余部分有什么关系?你真的只是在问那个 PyCUDA 例子吗?如果是这样,它想知道什么?为什么非并发版本要慢得多?你知道并发执行是否曾经发生过?你看过任何探查器痕迹吗?
  • @DmitriBudnikov - 我正在运行链接中写的代码。
  • @talonmies - 第一部分并不真正相关,只是为了说明我为什么要为此工作。我的基于 CUDA 的直方图代码的运行速度明显慢于在 CPU 上运行的 OpenCV 的 calcHist() 函数。为了找出原因,我试图检查我的代码是否没有同时运行。我运行了上面链接的示例代码;我预计第一次运行(并发)比第二次(非并发)快,但事实并非如此。为什么会这样?我应该直接发布一个针对我的内核的问题吗?
  • 如果它不相关,那么它不应该在问题中。因此,为了清楚起见,也许您应该将其删除。你明白在这种情况下“并发”是什么意思吗?这意味着使用流 API 启动和运行多个内核,并且在资源允许的情况下可能在 GPU 上同时运行。这不会自动推断出任何性能优势。

标签: python cuda gpu pycuda


【解决方案1】:

真正了解并发内核执行情况的唯一方法是分析代码。

使用 wiki 上发布的内部内核启动循环:

# Run kernels many times, we will only keep data from last loop iteration.
for j in range(10):
    for k in range(n):
        event[k]['kernel_begin'].record(stream[k])
        my_kernel(d_data[k], block=(N,1,1), stream=stream[k]) 
    for k in range(n): # Commenting out this line should break concurrency.
        event[k]['kernel_end'].record(stream[k])

配置文件跟踪如下所示:

使用这样的内部内核启动循环(即内核结束事件未在其自己的循环内推送到流中:

# Run kernels many times, we will only keep data from last loop iteration.
for j in range(10):
    for k in range(n):
        event[k]['kernel_begin'].record(stream[k])
        my_kernel(d_data[k], block=(N,1,1), stream=stream[k]) 
#    for k in range(n): # Commenting out this line should break concurrency.
        event[k]['kernel_end'].record(stream[k])

我得到了这个个人资料:

即两个执行流中的内核仍然重叠。

所以两个示例之间的执行时间没有变化的原因是因为您所依赖的注释是错误的。这两种情况都会产生内核执行重叠(“并发”)。

我没有兴趣理解为什么会这样,但这是你困惑的根源。您需要在其他地方寻找 your code 中性能不佳的根源(显然它无论如何都不使用流,所以整个问题都是稻草人)。

【讨论】:

  • 感谢您的详细解释。知道评论是错误的会很有帮助。我假设您正在查看我的另一个问题,声称我的代码没有使用流。您是正确的,我在另一个问题中发布的代码不使用流。早期版本的代码试图使用流。他们似乎没有什么不同。为了确保我正确使用和理解流,我尝试设置该示例代码。当它没有按描述工作时,我寻求帮助。我将改进我未来的 Stack Overflow 请求。
猜你喜欢
  • 1970-01-01
  • 2018-07-11
  • 2017-09-27
  • 1970-01-01
  • 2013-08-27
  • 1970-01-01
  • 2021-01-24
  • 2014-11-11
相关资源
最近更新 更多