ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Perfetto GPU 计算内核 Occupancy 分析:定位占用率的真正限制因素

Perfetto GPU 计算内核 Occupancy 分析:定位占用率的真正限制因素 Perfetto GPU 计算内核 Occupancy 分析定位占用率的真正限制因素【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfettoOccupancy占用率是 GPU 计算内核调优中的关键指标它衡量每个计算单元中实际活跃 warp/wavefront 数与硬件上限的比值。本文基于 Perfetto AI Skills 中的 GPU 计算内核分析工作流ai/skills/perfetto/workflows/gpu/compute/occupancy.md系统讲解如何从 trace 中提取 occupancy 相关数据、如何判读理论占用率 vs 实际占用率之间的差距以及如何确定到底是寄存器、共享内存还是 block 数量构成了限制占用率的瓶颈资源——读完本文你可以对任意 Perfetto trace 中的计算内核完成占用率是否受限、受什么限制的完整诊断。Occupancy 是什么以及为什么不是越高越好Occupancy 定义为每个计算单元NVIDIA 上是 SMAMD 上是 CU中活跃的 warp/wavefront 数占硬件最大值的比例。更高的 occupancy 有助于隐藏内存延迟和指令延迟但这并不意味着多多益善一旦延迟已经被隐藏继续追求更高的 occupancy 毫无收益反而可能以寄存器或共享内存为代价。因此该工作流只回答两个问题这个内核是否受 occupancy 限制如果是具体是哪种资源把它卡住了这是整套 GPU 计算分析中的解释层interpretation layer数据提取本身是厂商相关的NVIDIA/AMD 各有计数器体系但解释规则是厂商中立的对所有 GPU 通用。获取数据数据获取分两条路径取决于 GPU 厂商NVIDIA / CUDA运行厂商专属提取脚本详见 NVIDIA 提取说明trace_processor query --remote SESSION --query-file $SKILL_ROOT/workflows/gpu/compute/nvidia/scripts/occupancy.sql其他厂商每个资源的 block 上限per-resource block limits来自 launch 参数通常不依赖厂商、任何计算内核的 trace 里都有但实际占用率achieved occupancy需要厂商计数器支持。NVIDIA 提取的完整输出是一个通用展示名 → 输出列 → NVIDIA 计数器/launch 参数的映射每个计算内核一行按执行时长降序排列通用展示名输出列NVIDIA 计数器 / 参数Theoretical Occupancytheoretical_occ_pctsm__maximum_warps_per_active_cycle_pctlaunch 参数Achieved Occupancyachieved_occ_pctsm__warps_active.avg.pct_of_peak_sustained_active计数器AVGBlock Limit (blocks)limit_blocksoccupancy_limit_blocksBlock Limit (registers)limit_registersoccupancy_limit_registersBlock Limit (shared memory)limit_shared_memoccupancy_limit_shared_memBlock Limit (warps)limit_warpsoccupancy_limit_warpsBlock Limit (barriers)limit_barriersoccupancy_limit_barriers除上表外脚本还输出描述 launch 形态的列block_size、grid_size、registers、shared_mem_static、shared_mem_dynamic、waves_per_sm以及binding_resourceblock 上限最小的那个资源即应当优先放松的瓶颈资源。核心指标含义按通用展示名理解这些指标Theoretical Occupancy理论占用率launch 配置允许的上限占硬件最大 warp 数的百分比。它由 block 大小、每线程寄存器数、每 block 共享内存量等 launch 配置共同决定。Achieved Occupancy实际占用率实际运行时的活跃 warp 占比。它来自运行时计数器反映的是内核真正跑出来的占用水平。Block Limit每资源可容纳的 block 数分别为 registers / shared memory / warps / blocks / barriers 各自允许每计算单元容纳的 block 数。其中数值最小的那个就是约束资源binding constraint。Block Size、Grid Size、Registers、Shared Memory、Waves per compute unit描述 launch 形态launch shape的一组参数——每 block 线程数、block 总数、每线程寄存器、共享内存用量、每个计算单元上的波数。判读规则拿到数据后按以下四条规则判读。这些规则在 occupancy.md 中定义适用于任意厂商的 GPU。规则一Block Size 必须是 warp/wavefront 的整数倍Block size 应当是 warp/wavefront 大小的整数倍——NVIDIA 上是 32AMD 上是 64。不是整数倍意味着每个 warp/wavefront 都有一部分线程被浪费。两个方向的极端都不可取块太小每个计算单元得不到充分利用块太大寄存器/共享内存压力升高反过来把 occupancy 卡住。规则二用 Waves per compute unit 判断网格是否喂饱了 GPUWaves per compute unit grid size ÷ 每单元可驻留 block 数判断标准 1网格太小填不满整个 GPU部分计算单元在空转。杠杆增加并行度更大的 grid或与其他计算做融合fusion。1–2存在尾部效应tail effects——一部分单元提前完成开始空转而最后一个 wave 还在收尾。杠杆把 grid 调整为更靠近日整波数的尺寸。≥ 4负载均衡良好。规则三理论 vs 实际的差距说明什么差距大Achieved ≪ Theoretical内核没有维持住配置所允许的 warp/wavefront 数量——通常是负载不均衡、尾部效应或线程提前退出early exits所致。差距小且 Theoretical 本身偏低说明 launch 配置本身就是上限 → 去看 binding 的 Block Limit 是哪个资源。规则四放松哪个资源Block Limit 中数值最小的那个就是为了让 Theoretical Occupancy 上升而应该放松的资源。针对不同瓶颈的对应手段registers→ 降低寄存器压力使用更小的数据类型、减少同时存活的值live values或使用 launch-bounds 提示shared memory→ 减少每 block 的共享内存用量或调小 carveout 配置warps / blocks→ 受 block 大小或硬件每单元上限约束调整 block 尺寸barriers→ 减少每 block 的命名屏障named barriers数量。前置条件先确认内核确实是 latency-bound只在内核确实受延迟限制时才值得追逐 occupancy——判据是 Speed of Light 分析显示计算吞吐和内存吞吐两条天花板都低详见 Speed of Light 工作流。一个计算受限或内存受限的内核即使 occupancy 偏低也完全没问题——强行提高它的 occupancy 不会带来任何收益。底层实现occupancy.sql 是如何计算这些指标的理解 occupancy.sql 的实现可以确认这些指标在 Perfetto trace 数据模型中的确切来源1. 计算内核的识别。所有脚本统一用gpu_slice.render_stage_category 2COMPUTE 渲染阶段类别0OTHER、1GRAPHICS、2COMPUTE且dur 0来筛选计算内核并按ts用ROW_NUMBER()分配 launch 序号保证同一内核在不同分析脚本间的id一致CREATE PERFETTO TABLE _kernels AS SELECT s.id, s.ts, s.dur, s.arg_set_id, ROW_NUMBER() OVER (ORDER BY s.ts) AS launch_id, EXTRACT_ARG(t.dimension_arg_set_id, ugpu) AS ugpu, COALESCE( EXTRACT_ARG(s.arg_set_id, kernel_demangled_name), EXTRACT_ARG(s.arg_set_id, kernel_name), s.name ) AS kernel FROM gpu_slice AS s JOIN gpu_track AS t ON s.track_id t.id WHERE s.render_stage_category 2 AND s.dur 0;这正对应gpu_slice/gpu_track两张标准表——render_stage_category与ugpuhost 唯一 GPU id字段在 GPU 数据源文档中有定义解析逻辑位于 gpu_event_parser.cc。2. 实际占用率来自计数器轨道的时间窗匹配。Achieved Occupancy不是 launch 参数而是 COMPUTE 计数器组gpu_counter_group.group_id 6即GpuCounterGroup枚举的 COMPUTE 值中名为sm__warps_active.avg.pct_of_peak_sustained_active的 counter track。脚本把计数器值按时间戳落进每个内核的[ts, tsdur)窗口内求平均并按ugpu匹配到正确的 GPUCREATE PERFETTO TABLE _achieved AS SELECT k.id AS kernel_id, AVG(c.value) AS achieved_occ_pct FROM _kernels AS k JOIN gpu_counter_group AS g ON g.group_id 6 JOIN gpu_counter_track AS ct ON ct.id g.track_id AND ct.ugpu k.ugpu AND ct.name sm__warps_active.avg.pct_of_peak_sustained_active JOIN counter AS c ON c.track_id ct.id AND c.ts k.ts AND c.ts k.ts k.dur GROUP BY k.id;注意脚本注释中特别提醒的两个compute 魔数2render_stage_category的 COMPUTE 值和6GpuCounterGroup的 COMPUTE 值是两个不同枚举里的值不要混淆。3. 理论占用率与 block limit 全部是 launch 参数。theoretical_occ_pct直接取自 slice 参数sm__maximum_warps_per_active_cycle_pct五个 block limit 取自occupancy_limit_*系列参数。这些都是 launch 时随 slice 记录下来的所以不依赖厂商计数器——这也是其他厂商路径下 block limit 依然可用的原因。4. binding_resource 的计算避免了 MIN 的 NULL 陷阱。找出最小 limit看似可以一行MIN()解决但 SQLite 的标量MIN(a,b,...)只要有一个参数缺失NULL就整体返回 NULL会把本来明确的瓶颈藏掉。脚本因此先把五个 limit 拆成每资源一行unpivot再用窗口函数取最小值NULL 自动跳过并列时按 blocks → registers → shared_mem → warps → barriers 的固定顺序决出CREATE PERFETTO TABLE _binding AS SELECT kernel_id, resource AS binding_resource FROM ( SELECT kernel_id, resource, ROW_NUMBER() OVER (PARTITION BY kernel_id ORDER BY v, rank) AS rn FROM _limits WHERE v IS NOT NULL ) WHERE rn 1;最终查询输出每个内核一行包含全部指标列与binding_resource按dur降序排列方便直接定位耗时最长的热点内核。在整个 GPU 计算分析流程中的位置Occupancy 工作流是 kernel_analysis.md 定义的三阶段流程中 Phase 2 的一个分支与另外三个视角Speed of Light、Compute Workload Analysis、Launch Statistics互补Phase 1 全局分诊先用厂商中立的 kernels_summary.sql 列出所有计算内核id、kernel、ugpu、dur_ns、block_size、grid_size、registers挑出dur_ns最大的热点内核。若该查询无行返回说明 trace 中没有计算分派没有render_stage_category 2的 slice整个工作流不适用。Phase 2 分类与深挖Speed of Light 判定内核是 compute-bound、memory-bound 还是 latency/occupancy-bound——只有落到最后一类时本文的 occupancy 判读才有意义compute-bound 则转 Compute Workload Analysis 找饱和的流水线launch 参数本身是否合理则由 Launch Statistics 描述性地回答occupancy 回答配置是否真的成了限制两者分工明确。Phase 3 报告一份合格的结论应包含热点内核id、名称、耗时及其占 GPU 时间的比例、bound 类型附数字Compute/Memory Throughput、Achieved Occupancy、饱和流水线以及具体的杠杆改 block 尺寸/寄存器/共享内存以提 occupancy、改精度/指令组合、或改内存布局与局部性。需要说明的适用前提当前 trace 中的完整 Speed-of-Light 计数器集只有 NVIDIA 具备occupancy 的achieved一侧同样依赖厂商计数器occupancy_limit_*等参数名虽源自 CUDA 命名但 CUDA、HIP 等各计算 producer 在 trace 中以相同 key 记录因此 block limit 部分是厂商中立的。所有指标均以通用展示名描述、由厂商提取层映射到具体计数器跨厂商判读规则完全一致。【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表