【问题标题】:Questions about cuda关于 cuda 的问题
【发布时间】:2010-12-31 03:55:22
【问题描述】:

我正在研究有关 GPU 编程的信息,并希望了解有关 CUDA 的更多信息。我已经阅读了很多关于它的内容(来自 Wikipedia、Nvidia 和其他参考资料),但我仍然有一些问题:

  1. 以下对架构的描述准确吗?:GPU 有多个处理器,每个多处理器都有流处理器,每个流处理器可以同时运行线程块。

  2. 所有参考资料都表明在一个块内创建的最小线程数是 32...这是为什么呢?

  3. 我有一个 ATI Radeon 视频卡。我能够在没有仿真模式的情况下编译一个简单的 CUDA 程序!!。我以为我只能在支持的 Nvidia VGA 上编译和运行 CUDA 程序。谁能解释一下?

【问题讨论】:

    标签: architecture cuda gpu


    【解决方案1】:

    1 - NVIDIA gpus 也是如此。

    2 - 这是硬件设计的约束。

    3 - 编译在 CPU 上完成,因此您可以像在 x86 上为 PPC 交叉编译一样编译程序。

    如果你想在 ATI 卡上运行 gpu 程序,我建议你看看 OpenCL 或 AMD Stream。

    【讨论】:

    • 这是硬件设计的一个约束。那么如果我创建了 2 个块,每个块只有 10 个线程,会发生什么?我有 ATI 卡,我能够在不使用 -deviceemu 的情况下编译和“运行”用 cuda 和 c 编写的代码,这怎么能工作?我还有一个问题:gpu线程和cuda线程有什么区别?这个答案是否正确:cpu 按顺序运行线程,除非它有 1 个以上的核心。所以双核cpu只能同时运行2个线程。一个 gpu 并行运行一个线程块,因为它有许多流处理器。
    • > 2 个块 / 10 个线程,这些将低效运行。你只是不能在 ATI 上运行 CUDA。如果要运行 CUDA,则需要 NVIDIA 卡。您正确地描述了 cpu/gpu 线程。
    • (1) 每个 SM 执行一个块,而不是每个 SP。 (2) 这不是一个约束 - 每个块的最小线程数是 1,在这种情况下您的程序可以正常运行,但是为了有效利用,您应该每个块有 32 个线程的倍数(并且为了获得最大效率,您需要合理的“占用”来隐藏内存延迟,GT200 处理器上 50% 是合理的)。 (3) 代码实际上是在仿真模式下执行的。
    【解决方案2】:

    CUDA 线程非常轻量级,可以调度/停止而几乎没有损失。这与 CPU 线程不同,它有很多开销来切换执行和退出执行。因此,CPU 非常适合任务并行,而 GPU 则擅长数据并行。

    1. 在 CUDA 架构中,(NVIDIA) GPU 具有“流式多处理器”(SM),每个处理器都将执行一个线程块。每个 SM 都有一组流处理器 (SP),每个流处理器 (SP) 将在任何给定时刻(周期)为一个线程执行指令。

    2. 实际上一个块内的最小线程数是1。如果每个块只有一个线程,您的代码将正确执行。但是,将块设置为具有 32 个线程的倍数会更有效。这是由于硬件在 32 个线程的“warp”中调度操作的方式。

    3. 您可以交叉编译您的程序。您可以在仿真模式下运行它,即 CPU 正在“仿真”一个 CUDA GPU,但要在硬件上运行,您需要一个 NVIDIA GPU(启用 CUDA,任何最近的东西,2006 年左右之后都可以)。

    当前一代高端 GPU 有 240 个内核 (SP),您可以将其视为在任何给定时刻执行 240 个线程,但将 GPU 视为执行 数千个 线程很有用同时加载多个线程的状态(上下文)。

    我认为认识到 CPU 线程和 GPU 线程之间存在差异很重要。它们确实具有相同的名称,但 GPU 线程是轻量级的,通常在一小部分数据上运行。也许考虑一个(一组)CPU线程做非并行工作会有所帮助,然后每个CPU线程分叉成数千个GPU线程以进行数据并行工作,然后它们加入回CPU线程。显然,如果你能让 CPU 线程与 GPU 同时工作,那就更好了。

    请记住,与 CPU 不同,GPU 是一种吞吐量架构,这意味着程序应该创建许多线程,而不是缓存来隐藏延迟,这样当一些线程等待数据从内存返回时,其他线程可以执行.我建议您观看来自GPU Technology Conference 的“Advanced C for CUDA”讲座以了解更多信息。

    【讨论】:

    • 所以块的数量(网格大小)应该等于 SM 的数量,而线程的数量应该等于 SP 的数量以获得最佳性能。是这样吗?
    • 不完全。块中的线程数应该是 warp 大小的倍数,即 32(SP 的数量为 8),理想情况下这更像是 128,但这取决于您的应用程序。一般来说,特别是刚开始的时候,块的数量应该是数百(或数千)。这是因为如果资源可用,硬件可以在一个 SM 上调度多个块,这反过来意味着有更多的线程在 SM 上运行。这也意味着您的代码将在现在和将来在不同的设备上顺利扩展。
    • 您提供的链接非常有帮助,谢谢。我还有一个问题:SM 中的每个 SP 是否都有自己的寄存器和本地内存作为硬件?或者当内核午餐时,每个 SP 分配 1 个寄存器和 1 个本地内存?和共享内存的相同问题。每个 SM 中是否有 1 个共享内存。或者所有gpu都有1个共享内存,内核午餐时逻辑划分?
    • 每个 SM 都有一个寄存器文件和一个共享内存,这些是离散的单元。寄存器文件在线程(而不是SP)之间进行逻辑划分,共享内存在SM上运行的之间进行逻辑划分。本地内存有点不同,因为它主要用于寄存器文件溢出/填充;它实际上存在于片外内存中,但每个线程都保留(并受保护)。
    【解决方案3】:
    1. 是的。每个 GPU 都是一组 矢量处理器SIMD(单指令多数据)处理器。在单个线程向量中——可以是 32、64 或其他数量,具体取决于 GPU——每个线程在锁步中执行内核的相同指令。这个基本单位有时被称为“扭曲”或“波前”,有时也被称为“SIMD”。

      32 似乎是 NVidia 芯片的典型值,64 是 ATI 的典型值。 IIRC,Itel 的 Larrabee 芯片的数量应该会更高,如果该芯片曾经被制造出来的话。

    2. 在硬件级别,线程在这些单元中执行,但编程模型允许您拥有任意数量的线程。如果您的硬件实现了 32 宽的波前并且您的程序仅请求 1 个线程,则该硬件单元的 31/32 将处于空闲状态。因此,以 32 的倍数(或其他)创建线程是最有效的做事方式(假设您可以对其进行编程,以便所有线程都可以进行有用的工作)。

      硬件中实际发生的是每个线程至少有一个位。这表明线程是否“活着”。波前 32 中多余的未使用线程实际上会进行计算,但无法将任何结果写入任何内存位置,因此就好像它们从未执行过一样。

      当 GPU 为某些游戏渲染图形时,每个线程都在计算单个像素(如果启用了抗锯齿,则为子像素),并且每个被渲染的三角形都可以有任意数量的像素,对吗?如果 GPU 只能渲染包含 32 像素的精确倍数的三角形,它就不能很好地工作。

    3. goger 的回答说明了一切。

    4. 虽然您没有特别询问,但您的 GPU 内核避免分支也很重要。由于波前中的所有 32 个线程都必须同时执行相同的指令,当代码中有和 if .. then .. else 时会发生什么?如果warp中的一些线程想要执行“then”部分而一些想要执行“else”部分?答案是所有 32 个线程都执行这两个部分!这显然需要两倍的时间,因此您的内核将以一半的速度运行。

    【讨论】:

      猜你喜欢
      • 2016-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      • 2014-04-10
      • 2011-07-05
      相关资源
      最近更新 更多