克服CUDA中的复制开销



我想使用CUDA在GPU上并行化图像操作,为图像的每个像素(或像素组(使用一个线程。操作非常简单:每个像素乘以一个值。

然而,如果我理解正确,为了将图像放在GPU上并进行并行处理,我必须将其复制到统一内存或其他GPU可访问的内存中,这基本上是一个双循环,就像在CPU上处理图像一样。我想知道是否有一种更有效的方法可以在GPU上复制图像(即1D或2D阵列(,而不需要开销,因此并行化毫无用处。

然而,如果我理解正确,为了将图像放在GPU上并进行并行处理,我必须将其复制到统一内存或其他GPU可访问的内存

您理解正确。

我想知道是否有一种更有效的方法可以在没有开销的GPU上复制图像(即1D或2D阵列(

没有。主机系统内存中的数据必须通过PCIE总线才能到达GPU内存。这受到PCIE总线带宽的限制(对于PCIE Gen3,约12GB/s(;固定开销";与之相关,每次传输至少在几微秒的数量级上,因此从性能(字节/秒(的角度来看,非常小的传输似乎更差。

,使得并行化毫无用处。

如果你想执行的唯一操作是拍摄一张图像,并将每个像素乘以一个值,而由于某种原因,图像还没有在GPU上,那么头脑正常的人都不会为此使用GPU(可能是出于学习目的(。在性能开始变得有趣之前,你需要为GPU找到更多的相关工作

操作非常简单

这通常不是GPU加速带来性能优势的好指标。

当你说"其基本上是类似于将在CPU上处理图像的循环的双循环";,我希望你不是指在每一行,然后每一列上逐个像素地复制。您可以使用memcpy来复制整个图像。然而,正如其他人所说,在CPU和GPU之间移动数据仍然有相当大的开销,除非你在GPU上的计算足够复杂,足以证明开销是合理的。

您可以隐藏一些复制延迟。当您复制图像输入的补丁时,您可以同时从GPU上的先前计算中复制回结果补丁。在重叠的双向副本之上,可以运行第三个补丁的计算。这可以缩短单个图像处理或多个图像处理的总延迟(但这次隐藏了整个图像处理的延迟(。

对于一个非常简单的处理,只有阅读和写作才能相互隐藏。简单的计算没有隐藏任何其他内容的有意义的延迟。因此,通过流水线操作,您可以将性能提高100%(假设输入1个图像,输出1个相同大小的图像,并且pcie/驱动程序在两个方向上执行相同的操作(。

如果每个像素只乘以一个值,那么它是令人尴尬的并行,并且可以通过使用任意大小的块进行流水线操作来隐藏延迟。例如,

  • 将N行像素复制到vram
  • 计算N条线并同时将N条新线复制到vram
  • 将N个结果复制回ram,(并发(计算N个新行,(并发/异步(将最新的N行复制到vram
  • 将最后一个结果复制回ram

您可以为每个飞行中的N条扫描线使用1个流(进行读取+计算+写入(,并让驱动程序选择扫描线计算的最佳重叠,也可以为每个操作类型使用1个数据流(1个用于所有写入,1个用于全部读取,1个适用于所有计算(,并使用事件显式地保持重叠行为。

如果每个像素进行更多的计算,比如等于复制的延迟,那么流水线将为您提供3倍的性能(1后面隐藏着2个其他操作(。

最新更新