繁体   English   中英

将 for 循环放入 CUDA Kernel

[英]Putting a for loop in a CUDA Kernel

在 kernel 中放置 for 循环是一个坏主意吗?
或者这是一件常见的事情?

将循环放入内核是很常见的。 这并不意味着它总是一个好主意,但也不意味着它不是。

确定如何有效分配任务和数据以及利用相关并行性的一般问题是一个非常困难且未解决的问题,尤其是涉及 CUDA 时。 正在进行积极的研究以有效地确定(即,不盲目地探索参数空间)如何为给定的内核实现最佳结果。

有时,将循环放入内核会很有意义。 例如,对表现出强数据独立性的大型常规数据结构的许多元素进行迭代计算非常适合包含循环的内核。 其他时候,您可能决定让每个线程处理许多数据点,例如,如果您没有足够的共享 memory 来为每个任务分配一个线程(这在大量线程共享大量数据时并不少见,并且通过增加每个线程完成的工作量,您可以将所有线程的共享数据放入共享内存中)。

您最好的选择是根据需要进行有根据的猜测、测试、分析和修改。 优化的空间很大...启动参数,全局与常量与共享 memory,保持寄存器数量冷却,确保合并并避免 memory 银行冲突等。如果您对性能感兴趣,您应该在 CUDA 4.0 文档页面上查看 NVIDIA 提供的“CUDA C 最佳实践”和“CUDA 占用计算器”(如果您还没有的话)。

如果您注意您的 memory 访问模式,通常没问题。 如果 for 循环将随机访问 memory 导致许多未合并的 memory 读取它可能会非常慢。

事实上,我曾经用 CUDA 让一段代码运行得更慢,因为我天真地在 kernel 中插入了一个 for 循环。 但是,一旦我考虑过 memory 访问,例如通过一次将一个块加载到 shared 中,这样每个线程块都可以同时从 shared 执行 for 循环的一部分,它会快得多。

  • 处理大数据的基本模式是使用平铺方法,其中输入数据被拆分,每个线程在其数据平铺上工作,其中明确需要循环。
    示例 1:如果输入数据是 2D 矩阵,已知其行数超过其列数,我将使用唯一的网格块索引访问该行,并使用平铺线程索引方法访问该列,该方法使用在平铺大小上的循环。
    示例 2:如果您的线程需要处理进一步计算所需的单个值。 (以向量归一化为例)您需要一种平铺方法,因为只有在块内线程才能有效地同步。

只要它不在顶层,你应该没问题。 在顶层这样做会否定 CUDA 的所有优势。

正如 Dan 指出的,memory 访问成为一个问题。 解决此问题的一种方法是将引用的 memory 加载到共享 memory 或纹理 memory 中(如果它不适合共享)。 原因是未合并的全局 memory 访问非常慢(约 400 个时钟周期而不是约 40 个共享内存)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM