把 GPU 想象成一家大型连锁餐厅的后厨。每家分店都有一个灶台区(SM),灶台前站着很多厨师(CUDA 核心)。客人不是一个人一个人进门的,而是 32 人一桌地被服务员带进来,这一桌就是一个 Warp。占用率(Occupancy)就是此刻一个灶台区里坐了多少桌客人。如果只坐了两桌,其中一桌在等食材(读显存),灶台就可能空转;如果坐了八桌,一桌等菜时,其他桌还能继续翻炒。这个“上座率”就是 GPU 性能优化里最常用的一把尺子。

岗位关联

懂得占用率,就懂得为什么同一个 Kernel 换个块大小就能快一倍,是 GPU 性能优化中绕不开的诊断指标。

目录
  1. 可视化演示
  2. 1. 核心概念:先看懂“上座率”
  3. 2. 硬件资源限制:四张板凳决定能坐几桌
  4. 3. 关键计算:四张凳子取最小
  5. 4. 优化策略:调度员的四张牌
  6. 5. 性能误区:别只盯上座率
  7. 6. 工程实践:用工具看后厨
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

1. 核心概念:先看懂“上座率”

想象你经营一家后厨,灶台一次最多能同时开八桌菜。如果只安排两桌客人,其中一桌在等食材时,厨师可能只能干站着。占用率就是“现在开了几桌 / 最多能开几桌”这个比例。GPU 的道理一模一样:SM 是一个灶台区,Warp 是一桌 32 位客人,占用率就是活跃 Warp 数占 SM 最大 Warp 数的百分比。

在 CUDA 编程里,一个线程块(Block)由很多线程组成,一个 Warp 固定是 32 个线程。GPU 会把 Warp 当作最基本的调度单位,而不是单个线程。因此,真正决定 SM 能不能忙起来的是“同时有多少个 Warp 在执行”,也就是占用率。占用率越高,意味着调度器手里有越多“备选桌台”,当某一桌等显存数据时,立刻换另一桌继续炒菜。

这种“换桌炒菜”的能力叫延迟隐藏。显存访问通常几百个周期,如果 SM 里只有一两个 Warp,那么这段时间计算单元就会空转;如果 Warp 足够多,A 桌等菜时 B 桌、C 桌还能继续上灶,整体吞吐自然更高。占用率就是衡量这种“换桌余地”的指标。

占用率不是“GPU 卡用了百分之多少”,而是“一个灶台区坐了几成客人”。它是性能优化的起点,而不是终点:先让上座率足够高,再谈每一桌怎么炒得更快。

Occupancy=活跃 Warp 数SM 支持的最大 Warp 数\text{Occupancy}=\frac{\text{活跃 Warp 数}}{\text{SM 支持的最大 Warp 数}}
占用率是一个 0 到 1 之间的比例,它告诉你有多少“菜桌”可以同时接待。
  1. 活跃 Warp 数指当前 SM 中已经就绪、可以被调度执行或正在等待资源的 Warp 数量。
    Wactive≤Wmax⁡W_{\text{active}}\leq W_{\max}
  2. 最大 Warp 数由硬件决定,通常等于 SM 最大线程数除以 32。
    Wmax⁡=Tmax⁡32W_{\max}=\frac{T_{\max}}{32}
  3. 相除得到占用率把实际活跃 Warp 数除以硬件上限,就得到占用率。
    Occupancy=WactiveWmax⁡∈[0,1]\text{Occupancy}=\frac{W_{\text{active}}}{W_{\max}}\in[0,1]

2. 硬件资源限制:四张板凳决定能坐几桌

一个灶台区能坐多少桌,不是服务员想安排多少就安排多少。后厨有四条硬规矩:座位数、私人餐具数、公共储物间大小、以及最多同时接待几批团客。GPU 的 SM 也一样,有四个资源上限:最大线程数、寄存器文件、共享内存、最大常驻块数。

首先是线程槽位。SM 能容纳的总线程数有限,比如 2048 个线程。如果每桌(Block)有 256 个线程,那么线程数这一条就限制最多放 8 个 Block。其次是寄存器:每个线程都有自己的“小抽屉”用来放局部变量,SM 的寄存器总数有限;每线程用掉的寄存器越多,能进场的线程就越少。第三是共享内存,它像一个公共储物间,每个 Block 会申请一块;每块申请越多,能同时存放的 Block 就越少。最后还有一个硬性块数上限,哪怕资源和线程都够,也不能超过硬件规定的 Block 数量。

这四个限制不是“选一个最强的”,而是“每条凳子都坐满才算”。任何一个资源耗尽,都会成为进场的瓶颈。所以计算占用率前,得先把四张板凳各自能坐几桌算出来。

把后厨的每一条凳子都看成资源上限:座位、餐具、储物间、团客数量。任何一个先到顶,后厨就不能再加桌了。这也是为什么“块大小”和“每线程寄存器数”会直接决定占用率。

Bt=⌊Tmax⁡B⌋Br=⌊Rmax⁡B⋅r⌋Bs=⌊Smax⁡s⌋\begin{aligned}B_t &= \left\lfloor \frac{T_{\max}}{B} \right\rfloor \\B_r &= \left\lfloor \frac{R_{\max}}{B\cdot r} \right\rfloor \\B_s &= \left\lfloor \frac{S_{\max}}{s} \right\rfloor\end{aligned}
\(B_t\) 是线程数允许的块数,\(B_r\) 是寄存器允许的块数,\(B_s\) 是共享内存允许的块数。
  1. 线程数限制用 SM 最大线程数除以每个 Block 的线程数,向下取整。
    Bt=⌊Tmax⁡B⌋B_t=\left\lfloor \frac{T_{\max}}{B} \right\rfloor
  2. 寄存器限制整个 SM 的寄存器总数,除以“一个 Block 总共需要的寄存器数”。
    Br=⌊Rmax⁡B⋅r⌋B_r=\left\lfloor \frac{R_{\max}}{B\cdot r} \right\rfloor
  3. 共享内存限制SM 的共享内存总量除以每个 Block 申请的共享内存量。
    Bs=⌊Smax⁡s⌋B_s=\left\lfloor \frac{S_{\max}}{s} \right\rfloor

3. 关键计算:四张凳子取最小

服务员要安排桌位,会同时看四条规矩,最后能开几桌,一定是最“小气”的那条规矩说了算。GPU 也一样:把线程数算出的块数、寄存器算出的块数、共享内存算出的块数,以及硬件最大块数放在一起,取最小值,才是真正能常驻的 Block 数。

例如一个 SM 最多 2048 个线程,每 Block 256 线程,线程数允许 8 个 Block;但每 Block 共享内存申请 48KB,SM 只有 96KB,共享内存只允许 2 个 Block。那么最终只能放 2 个 Block,哪怕线程槽位还空着。这就是性能分析中最常见的“找瓶颈”:先找出是哪一个资源把后厨的门关小了。

有了常驻 Block 数,再乘以每个 Block 的 Warp 数,就能得到活跃 Warp 数,最后除以 SM 最大 Warp 数,得到占用率。这个计算过程是 GPU 性能优化的基本功,也是后面所有调优判断的基础。

这一节其实就是“短板效应”:后厨能开几桌,取决于最挤的那条资源通道。做优化时,先算出这四个数,哪个最小,就先解决哪个。

Bactive=min⁡(Bt,Br,Bs,Bm),Occupancy=Bactive×⌈B/32⌉Wmax⁡B_{\text{active}}=\min(B_t,B_r,B_s,B_m),\quad\text{Occupancy}=\frac{B_{\text{active}}\times \lceil B/32\rceil}{W_{\max}}
占用率公式的终点是“最小资源限制后的活跃 Warp 数”除以“最大 Warp 数”。
  1. 取最小块数四种限制分别算出一个块数,最终结果取最小值。
    Bactive=min⁡(Bt,Br,Bs,Bm)B_{\text{active}}=\min(B_t,B_r,B_s,B_m)
  2. 块数转 Warp 数每个 Block 包含多少个 Warp,由线程数除以 32 后向上取整得到。
    ⌈B/32⌉\lceil B/32\rceil
  3. 计算占用率用活跃 Warp 数除以 SM 最大 Warp 数。
    Occupancy=Bactive×⌈B/32⌉Wmax⁡\text{Occupancy}=\frac{B_{\text{active}}\times \lceil B/32\rceil}{W_{\max}}

4. 优化策略:调度员的四张牌

知道了短板在哪,调度员就能想办法多塞几桌。第一张牌是调整块大小。块太小,每个块的 Warp 数少,硬件块数上限会限制总量;块太大,又可能让寄存器或共享内存不够用。通常让块大小是 32 的整数倍,再在 128、256、512 之间做实验。

第二张牌是用 launch_bounds 限制每线程寄存器数。编译器默认可能给每个线程分配很多寄存器,导致占用率很低。如果你告诉编译器“我们最多需要 128 个寄存器”,编译器就会更节省地使用寄存器,从而让更多 Warp 进场。第三张牌是减少每 Block 的共享内存申请,比如把大数组改成分批处理,或者用寄存器替代部分共享内存。

不过,这些牌要组合着打。盲目把寄存器压得太低,可能导致寄存器溢出到本地内存,反而把“快菜”变成“慢菜”;块大小也不是越大越好,过大可能让 Block 之间调度不灵活。目标是在资源和并行度之间找到平衡。若想达到某个目标占用率,可以反向计算每线程最多能用多少寄存器。

好的调度员不是“无脑坐满”,而是知道哪张桌子最省资源、哪种客人的菜最容易等。优化占用率,本质上就是优化资源在“桌数”和“每桌效率”之间的分配。

r≤⌊Rmax⁡Occtarget×Tmax⁡⌋r \le \left\lfloor \frac{R_{\max}}{\text{Occ}_{\text{target}}\times T_{\max}} \right\rfloor
已知目标占用率时,能反推出每线程寄存器预算;这是 launch_bounds 调参背后的数学依据。
  1. 目标活跃线程数目标占用率乘以 SM 最大线程数,得到需要同时活跃的线程数。
    Occtarget×Tmax⁡\text{Occ}_{\text{target}}\times T_{\max}
  2. 寄存器总预算分摊把 SM 寄存器总数平分给这么多活跃线程。
    Rmax⁡Occtarget×Tmax⁡\frac{R_{\max}}{\text{Occ}_{\text{target}}\times T_{\max}}
  3. 向下取整寄存器按整数分配,所以向下取整得到每线程上限。
    r≤⌊Rmax⁡Occtarget×Tmax⁡⌋r \le \left\lfloor \frac{R_{\max}}{\text{Occ}_{\text{target}}\times T_{\max}} \right\rfloor

5. 性能误区:别只盯上座率

很多人以为上座率越高,餐厅营收一定越高。但真实情况是:如果每桌客人都点了一堆需要长时间准备的菜,哪怕满座,翻台率也可能很低。GPU 也是这样,100% 占用率不一定代表最快,它只是说明有足够多的 Warp 可供调度;如果这些 Warp 内部指令相关性很强、彼此都在等同一个结果,调度器依然无事可做。

所以第二个误区是“低占用率一定慢”。有时候 Kernel 里有大量指令级并行(ILP),单个 Warp 自身就有好几条独立指令可以连续执行,即使只有 50% 占用率,同样能把延迟藏住。反之,高占用率配合很差的 ILP,也可能跑不出好成绩。占用率是“潜力”,不是“结果”。

第三个误区是为了提占用率无限压低寄存器。寄存器是线程的私人餐具,压得太狠,编译器会把数据倒到本地内存,也就是“把菜放到后门外面的货架上”,取用速度慢很多,反而拖慢性能。理论占用的数字再漂亮,也要通过实测耗时来验证。

这就像“满座”和“赚钱”之间隔着翻台率、菜品结构、服务效率。GPU 优化也一样:先把上座率调到合理区间,再用性能分析工具看真实表现,而不是迷信某一个百分比。

性能≠100%占用率\text{性能}\neq 100\%\text{占用率}
上座率只是条件,不是目的;最终要看的是“单位时间炒出多少道菜”,也就是吞吐和耗时。
  1. 性能不是占用率占用率描述可调度的 Warp 数量,性能描述每秒完成多少指令。
    性能=完成的指令数耗时\text{性能} = \frac{\text{完成的指令数}}{\text{耗时}}
  2. 高占用率是必要条件之一足够多的 Warp 才能换桌,但每桌自身的并行度同样重要。
    隐藏延迟能力≈活跃 Warp 数×Warp 内并行度\text{隐藏延迟能力} \approx \text{活跃 Warp 数} \times \text{Warp 内并行度}

6. 工程实践:用工具看后厨

手工算占用率适合理解原理,真到了工程里,一定要用工具。CUDA 提供了 cudaOccupancyMaxActiveBlocksPerMultiprocessor 和 cudaOccupancyMaxPotentialOccupancy 这类 API,它们像“预订系统”,输入内核的块大小、寄存器用量、共享内存用量,直接给出理论最大常驻块数和最佳占用率。

另一个常用工具是 Nsight Compute。它能像“后厨监控录像”一样,报告内核实际的占用率、Warp 停顿原因、访存延迟等。理论占用率是“按菜单最多能接待多少桌”,实际占用率是“今天到底同时坐了几桌”。两者经常不一致,原因可能是 Block 数量不够多、负载不均衡、某个 Barrier 让 Warp 互相等待。

工程优化的标准流程是:先用 API 算出理论短板,再用 Nsight 看实测瓶颈,然后针对性地调整块大小、寄存器或共享内存,最后用逐次运行耗时来验证。每一步都要记录数据,因为 GPU 架构不同,参数最优值也不同。只有用数据说话,才算真正会调占用率。

后厨管理不能只靠感觉,要用预订系统算座位,用监控录像看实况。GPU 优化同样如此:理论公式负责缩小搜索范围,性能工具负责验证最终效果。

Occachieved=WmeasuredWmax⁡\text{Occ}_{\text{achieved}}=\frac{W_{\text{measured}}}{W_{\max}}
实际占用率是 Nsight 测量出的活跃 Warp 数与硬件最大 Warp 数的比值,用它来判断理论假设是否成立。
  1. 实测活跃 Warp 数通过 Profiler 统计内核运行期间每个周期实际活跃的 Warp 数。
    WmeasuredW_{\text{measured}}
  2. 除以硬件上限得到实际达到的占用率。
    Occachieved=WmeasuredWmax⁡\text{Occ}_{\text{achieved}}=\frac{W_{\text{measured}}}{W_{\max}}
  3. 对比理论值若实际远低于理论,说明存在负载不均或调度等待。
    Occachieved≪Occtheory\text{Occ}_{\text{achieved}} \ll \text{Occ}_{\text{theory}}

AI 应用场景

大型语言模型推理服务调优

阶段:模型部署与推理优化

解决的问题:LLM 推理时有很多矩阵乘法和 Attention Kernel,访存密集且延迟敏感。传统做法是盲目选一个块大小,结果 SM 中 Warp 太少,显存等待明显,GPU 利用率低。利用占用率计算和 Occupancy API,可以快速选出让活跃 Warp 数更高的 Kernel 配置,从而提升推理吞吐。

具体案例:某推理团队发现 decode 阶段 Kernel 的实际占用率只有 30%,通过 cudaOccupancyMaxPotentialOccupancy 查到共享内存是瓶颈,于是把每 Block 的共享内存从 80KB 降到 64KB,块大小从 128 调到 256,最终 token 生成速度提升约 40%。

深度学习训练框架的卷积内核优化

阶段:训练框架底层算子开发

解决的问题:卷积 Kernel 在 GPU 上运行时,不同 shape 的最优块大小不同。手工枚举耗时且不通用,框架希望有一套自动选择 Launch 配置的规则。

具体案例:PyTorch 自定义 CUDA 算子时,开发者用 cudaOccupancyMaxActiveBlocksPerMultiprocessor 对不同输入尺寸做预算,再结合带宽实测,选择占用率不是最高但吞吐最高的配置,最终让训练整体 step 时间缩短 15%。

自动驾驶实时视觉流水线

阶段:实时感知前处理与后处理

解决的问题:摄像头图像预处理需要做大量访存操作,如果占用率太低,显存延迟容易造成流水线空泡,影响端到端延迟。

具体案例:自动驾驶平台在做图像缩放、归一化等 Kernel 时,通过 Nsight Compute 发现寄存器限制导致占用率只有 50%,使用 launch_bounds 将寄存器限制到 128 后,占用率升到 75%,整条感知流水线的帧耗时下降 20%。

Python 演示

python34 行
def calc_occupancy(max_warps, max_threads, block_size, regs_per_thread,                   max_regs, smem_per_block, max_smem, max_blocks_hw):    # 一个 Block 由几个 Warp 组成    warps_per_block = (block_size + 31) // 32    # 线程槽位允许的 Block 数    blocks_by_thread = max_threads // block_size    # 寄存器允许的 Block 数    blocks_by_regs = max_regs // (block_size * regs_per_thread)    # 共享内存允许的 Block 数    if smem_per_block > 0:        blocks_by_smem = max_smem // smem_per_block    else:        blocks_by_smem = 10 ** 9    # 最终常驻 Block 数取所有限制的最小值    active_blocks = min(blocks_by_thread, blocks_by_regs,                        blocks_by_smem, max_blocks_hw)    active_warps = active_blocks * warps_per_block    occupancy = active_warps / max_warps    return occupancy, active_blocks, active_warps if __name__ == "__main__":    occ, blocks, warps = calc_occupancy(        max_warps=64, max_threads=2048, block_size=256,        regs_per_thread=32, max_regs=65536,        smem_per_block=49152, max_smem=98304, max_blocks_hw=32,    )    print("occupancy=%.1f%%" % (occ * 100))    print("resident_blocks=%d" % blocks)    print("active_warps=%d" % warps)     # 反推达到 75% 占用率时每线程最多能用多少寄存器    target_occ = 0.75    reg_budget = int(65536 // (2048 * target_occ))    print("target_75_occupancy_regs_per_thread<=%d" % reg_budget)
目的:用纯 Python 模拟 CUDA Occupancy 的核心计算过程,帮助你理解线程、寄存器、共享内存如何共同决定占用率。
  1. warps_per_block = (block_size + 31) // 32计算一个 Block 包含几个 Warp,等价于线程数除以 32 后向上取整。
  2. blocks_by_thread = max_threads // block_size线程槽位这条限制允许放几个 Block。
  3. blocks_by_regs = max_regs // (block_size * regs_per_thread)寄存器总量分摊到每个 Block 的每个线程后,能容纳几个 Block。
  4. blocks_by_smem = max_smem // smem_per_block共享内存总容量决定还能再放几个 Block。
  5. active_blocks = min(...)短板效应:最终常驻 Block 数由最小的那个限制决定。
  6. occupancy = active_warps / max_warps用活跃 Warp 数除以硬件最大 Warp 数,得到占用率。
  7. reg_budget = int(65536 // (2048 * target_occ))反推出达到目标占用率时,每线程最多允许使用多少寄存器。

常见误区

误区我只要把占用率调到 100%,Kernel 就一定是最快的,因为 GPU 看起来“坐满了”。

正解占用率只是延迟隐藏的潜力,不代表每一条指令都高效。如果 Warp 内部指令相互依赖、缺少独立运算,或者访存模式很差,即使满座,计算单元依然可能空转。还要注意提高占用率可能带来的寄存器溢出、块数减少等副作用,最终要以耗时和吞吐为准。

为何常见:因为“占用率”这个名字听起来像“利用率”,初学者很容易把“能坐满”和“很高效”划等号。

误区我算出来理论占用率是 80%,所以 Kernel 实际就是 80%,不需要再用 Profiler 看。

正解理论占用率假设所有 Warp 都能均匀被调度,但现实中还存在负载不均衡、Block 数量不足以填满整个 GPU、线程同步等待、访存冲突等问题。Nsight Compute 测出的实际占用率往往更低。只有把理论值和实测值对比,才能真正定位瓶颈。

为何常见:理论公式简单直观,手工算一次就有“我已经优化好了”的错觉,忽视了真实运行时的复杂调度。

误区既然寄存器用得多会降低占用率,那我就在编译时把寄存器限制调到很小。

正解寄存器是每个线程的私有存储,压得太低会让编译器把部分变量转移到本地内存,也就是“倒菜到门外”,访问速度骤降。这会导致每个 Warp 执行速度变慢,抵消甚至超过占用率提升带来的收益。正确的做法是结合目标占用率反推寄存器预算,再通过实验寻找拐点。

为何常见:初学优化时只关注“数字好看”,忽略了寄存器溢出带来的隐性成本,属于把手段当成了目标。

误区块大小越大,能装下的线程越多,占用率自然越高,索性直接用 1024。

正解块大小增大后,每 Block 需要的寄存器和共享内存总量也会变大,可能反而限制常驻 Block 数,导致占用率下降。而且 Block 数量太少时,负载分配不够灵活,容易出现“尾部效应”,最后几个 Block 不能占满 GPU。最优块大小通常要在 128、256、512 之间实测。

为何常见:人们下意识觉得“批量越大越省事”,却忽略了 GPU 的资源是按 SM 和 Block 双重限制分配的。

面试题

Q1. 占用率(Occupancy)在 GPU 性能优化中指什么?

单选题 · easy

  • A.计算核心利用情况
  • B.活跃Warp数占比值← 正确答案
  • C.显存空间占用比例
  • D.寄存器堆占用情况

答案:B。占用率是活跃 Warp 数与 SM 最大 Warp 数的比值。它衡量 SM 中有多少 Warp 可供调度,而不是显存或 GPU 卡的整体利用率。A 是笼统的核心利用率,C、D 都对应资源占用,与占用率定义不同。

Q2. 一个 Warp 通常由多少个线程组成?

单选题 · easy

  • A.16 个线程
  • B.32 个线程← 正确答案
  • C.64 个线程
  • D.128 个线程

答案:B。CUDA 以 Warp 为基本调度单位,一个 Warp 固定包含 32 个线程。每次 GPU 调度一桌就是 32 个线程,所以计算 Warp 数时,Block 线程数需要除以 32。

Q3. 某 SM 最大线程数为 2048,Block 大小为 256,那么线程数限制最多允许几个 Block 常驻?

单选题 · easy

  • A.4 个
  • B.8 个← 正确答案
  • C.16 个
  • D.32 个

答案:B。线程槽位限制的块数等于 2048 除以 256,结果是 8。这就像座位区有 2048 个座位,每桌占 256 个座位,最多能同时接待 8 桌。

Q4. 每个线程使用 64 个寄存器,SM 寄存器总数为 65536,Block 大小为 256,则寄存器限制允许几个 Block?

单选题 · mid

  • A.2 个
  • B.4 个← 正确答案
  • C.8 个
  • D.16 个

答案:B。每个 Block 需要 256 乘 64 等于 16384 个寄存器,65536 除以 16384 得到 4。寄存器像私人餐具,餐具总数固定,每桌客人要用的餐具越多,能接待的桌数就越少。

Q5. 下面哪些因素会限制 SM 中常驻 Block 的数量?

多选题 · mid

  • A.最大线程槽位数← 正确答案
  • B.寄存器文件大小← 正确答案
  • C.共享内存容量← 正确答案
  • D.显存带宽大小

答案:ABC。线程槽位、寄存器文件、共享内存和硬件块数上限都会限制常驻 Block 数。显存带宽虽然影响访存速度,但不直接决定 SM 能容纳多少 Block。

Q6. 若 SM 最大 Warp 数为 64,实际活跃 Warp 数为 32,则占用率是多少?

单选题 · mid

  • A.25%
  • B.50%← 正确答案
  • C.75%
  • D.100%

答案:B。占用率等于活跃 Warp 数除以最大 Warp 数,32 除以 64 等于 0.5,也就是 50%。相当于灶台区一共能开 64 桌,现在坐了 32 桌。

Q7. 下列哪些做法可能提高 Kernel 的占用率?

多选题 · hard

  • A.调整块大小为合适值← 正确答案
  • B.用 launch_bounds 限制寄存器← 正确答案
  • C.减少每块共享内存用量← 正确答案
  • D.直接增大显存容量

答案:ABC。调整块大小可以让线程数和资源分配更均衡;launch_bounds 能降低每线程寄存器数;减少共享内存可以增加常驻 Block 数。显存容量是全局资源,不会改变 SM 内共享内存和寄存器的分配,因此不能提高占用率。

Q8. 关于占用率与性能的关系,下列说法正确的是?

单选题 · hard

  • A.100% 占用率一定最快
  • B.低占用率一定导致性能差
  • C.高占用率需配合指令级并行← 正确答案
  • D.占用率与性能毫无关系

答案:C。高占用率提供延迟隐藏的潜力,但 Warp 内部也需要有足够的独立指令,否则调度器没有可执行的指令。因此不能说完美占用率一定快,也不能说低占用率一定慢,C 更全面。

Q9. 在 CUDA 中,用来查询给定内核最大常驻块数的接口属于哪一类?

单选题 · extreme

  • A.显存管理类接口
  • B.占用率查询类接口← 正确答案
  • C.流同步类接口
  • D.数据拷贝类接口

答案:B。cudaOccupancyMaxActiveBlocksPerMultiprocessor 属于占用率查询 API,它接收内核函数、块大小和资源参数,返回一个 SM 上最多能常驻的块数。显存管理、流同步和数据拷贝都不负责计算常驻块数。

Q10. 下面哪些工具或接口可用于分析 CUDA 内核的实际占用率?

多选题 · hard

  • A.Nsight 分析工具← 正确答案
  • B.Occupancy API← 正确答案
  • C.CUDA 事件计时
  • D.内核打印输出

答案:AB。Nsight Compute 能测出实际占用率和 Warp 停顿原因,Occupancy API 能计算理论占用率。CUDA 事件计时只能测耗时,内核打印输出只是调试信息,它们无法直接给出占用率数据。