2

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

但是,如果我理解正确,为了将图像放在 GPU 上并对其进行并行处理,我必须将其复制到统一内存或其他一些 GPU 可访问的内存,这基本上是一个双循环,就像一个这将在 CPU 上处理图像。我想知道是否有一种更有效的方法可以在 GPU 上复制图像(即 1D 或 2D 数组)而没有开销,从而导致并行化毫无用处。

4

3 回答 3

3

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

你理解正确。

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

没有。主机系统内存中的数据必须通过 PCIE 总线才能到达 GPU 内存。这受 PCIE 总线带宽(PCIE Gen3 约为 12GB/s)的限制,并且还有一些与之相关的“固定开销”,至少每次传输大约几微秒,因此非常小的传输似乎更糟从性能(字节/秒)的角度来看。

这样并行化就没有用了。

如果您想要执行的唯一操作是获取图像并将每个像素乘以一个值,并且由于某种原因该图像尚未在 GPU 上,那么正常思维中的任何人都不会为此使用 GPU(可能出于学习目的除外) )。在性能开始变得有趣之前,您需要为 GPU 找到更多涉及的工作

操作非常简单

对于 GPU 加速带来的性能优势,这通常不是一个很好的指标。

于 2021-05-26T21:15:49.793 回答
1

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

于 2021-05-27T15:27:47.250 回答
0

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

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

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

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

您可以为每个飞行中的 N 扫描线使用 1 个流(进行读取+计算+写入)并让驱动程序选择扫描线计算的最佳重叠,或者每种操作类型有 1 个流(1 个用于所有写入,1 个用于所有写入) reads,1 用于所有计算)并使用事件显式地维护重叠行为。

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

于 2021-05-27T20:32:35.550 回答