为啥允许我运行块数超过 GPU 的 CUDA 核心数的 CUDA 内核?

Posted

技术标签:

【中文标题】为啥允许我运行块数超过 GPU 的 CUDA 核心数的 CUDA 内核?【英文标题】:Why am I allowed to run a CUDA kernel with more blocks than my GPU's CUDA core count?为什么允许我运行块数超过 GPU 的 CUDA 核心数的 CUDA 内核? 【发布时间】:2016-01-16 20:28:35 【问题描述】:

评论/注释

线程块是否可以超过 CUDA 内核的最大数量? 经纱尺寸与我正在做什么有什么关系?

开始

我正在使用以下代码运行一个 cuda 程序来启动 cuda 内核:

cuda_kernel_func<<<960, 1>>> (... arguments ...)

我认为这将是我被允许做的事情的限制,因为我的笔记本电脑上有一个 GTX670MX 图形处理器,根据 Nvidia 的网站,它有 960 个 CUDA 内核。

所以我尝试将960 更改为961,假设程序会崩溃。它没有……

这是怎么回事?

这是deviceQuery的输出:

./deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 1 CUDA Capable device(s)

Device 0: "GeForce GTX 670MX"
  CUDA Driver Version / Runtime Version          7.5 / 7.5
  CUDA Capability Major/Minor version number:    3.0
  Total amount of global memory:                 3072 MBytes (3221028864 bytes)
  ( 5) Multiprocessors, (192) CUDA Cores/MP:     960 CUDA Cores
  GPU Max Clock rate:                            601 MHz (0.60 GHz)
  Memory Clock rate:                             1400 Mhz
  Memory Bus Width:                              192-bit
  L2 Cache Size:                                 393216 bytes
  Maximum Texture Dimension Size (x,y,z)         1D=(65536), 2D=(65536, 65536), 3D=(4096, 4096, 4096)
  Maximum Layered 1D Texture Size, (num) layers  1D=(16384), 2048 layers
  Maximum Layered 2D Texture Size, (num) layers  2D=(16384, 16384), 2048 layers
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       49152 bytes
  Total number of registers available per block: 65536
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  2048
  Maximum number of threads per block:           1024
  Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
  Max dimension size of a grid size    (x,y,z): (2147483647, 65535, 65535)
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             512 bytes
  Concurrent copy and kernel execution:          Yes with 1 copy engine(s)
  Run time limit on kernels:                     Yes
  Integrated GPU sharing Host Memory:            No
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Disabled
  Device supports Unified Addressing (UVA):      Yes
  Device PCI Domain ID / Bus ID / location ID:   0 / 1 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 7.5, CUDA Runtime Version = 7.5, NumDevs = 1, Device0 = GeForce GTX 670MX
Result = PASS

我不知道如何解释这些信息。这里说“960 个 CUDA 内核”,然后是“每个多处理器 2048 个线程”和“每个块 1024 个线程”。

我对这些东西的含义有些困惑,因此 cuda_kernel_func>> 参数的局限性是什么。 (以及如何让我的设备发挥最大性能。)

我想您也可以将此问题解释为“关于我的设备的所有统计信息是什么意思”。例如,CUDA 核心/线程/多处理器/纹理维度大小究竟是多少?

【问题讨论】:

阅读 CUDA 编程指南的first five pages 可以很容易地回答这个问题 谢谢,这不是一个有用的评论,我当然读过这个文件。 @talonmies 无论如何,它的所有副本都应该从互联网上删除——它不是无用的资源。 说真的,请看图 5。它是您问题的准确答案。你甚至不需要阅读。看看就好 @user3728501:您问“我的线程块可以超过 CUDA 内核的最大数量吗?”。图 5 是该问题的答案。 【参考方案1】:

它没有崩溃,因为“CUDA 核心”的数量与块的数量无关。并非所有块都必须并行执行。 CUDA 只是将你的一些块安排在其他块之后,在所有块执行完成后返回。

您知道,NVIDIA 错误地说明了其 GPU 中的内核数量,以便与单线程非矢量化 CPU 执行进行更简单的比较。你的 GPU 实际上是 has 6 cores 在 proper sense of the word;但是它们中的每一个都可以在大量数据上并行执行大量指令。请注意,Kepler GPU 上的真正核心被称为“SMx”es(并在 here 简要描述)。

所以:

[实际核心数] x [单个核心可以并行执行的最大指令数] = [“CUDA 核心数”]

例如6 x 160 = 960 用于您的卡。

即使这是对事物的粗略描述,在 SMx 中发生的事情并不总是允许我们每个周期并行执行 160 条指令。例如,当每个块只有 1 个线程时,该数字会下降 32 倍(!)

因此,即使您使用 960 而不是 961 块,您的执行也不会像您希望的那样并行化。并且 - 你真的应该在每个块中使用更多线程来利用 GPU 的并行执行功能。更重要的是,你应该找到一本关于 CUDA/GPU 编程的好书。

【讨论】:

@user3728501:答案重写,我希望这更清楚。 好的,谢谢 - 我明白这一点......除了我认为我有“5 * 192 CUDA 核心” - 但这只是一个细节问题。 顺便说一句,我进行了编辑,因为我认为您漏掉了一个字 - 如果我编辑不正确,请随时再次更改。【参考方案2】:

一个更简单的答案:

块不会同时执行。有些块可能在其他块开始之前就完成了。 GPU 一次执行 X 个块,完成这些块,抓取更多块,然后继续,直到所有块都完成。

旁白:这就是为什么 thread_sync 只同步块内的线程,而不是整个内核内的线程。

【讨论】:

以上是关于为啥允许我运行块数超过 GPU 的 CUDA 核心数的 CUDA 内核?的主要内容,如果未能解决你的问题,请参考以下文章

GPU/CUDA:网格的最大块数和每个多处理器的最大驻留块数

你能以编程方式知道 GPU 中每个块的最大块数和线程数吗?

为啥在使用 cudaMallocManaged 时 NVIDIA Pascal GPU 运行 CUDA 内核速度很慢

为啥 OpenCV GPU CUDA 模板匹配比 CPU 慢很多?

CUDA:为啥会有大量的 GPU 空闲时间?

为啥我的简单 pytorch 网络不能在 GPU 设备上运行?