第三章:Details 剩余数据补读 ⭐教你读懂 Nsight Compute 报告 系列合集⭐

第三章:Details 剩余数据补读

第二章从 Details 页里挑出了三个重点 section,这一章沿着 Details 页往下走,把剩下的 11 个 section 按页面顺序补齐,依次是 PM Sampling、Compute Workload Analysis、Scheduler Statistics、Warp State Statistics、Instruction Statistics、NVLink Topology、NVLink Tables、NUMA Affinity、Launch Statistics、Occupancy、GPU and Memory Workload Distribution,加上第二章那三个,Details 页的 14 个 section 到这一章全部读完。

PM Sampling

PM Sampling 是 Details 页的第二个 section。PM 是 Performance Monitor,性能监视器,GPU 上自带的一套计数电路,用来累计各条管线忙了多少周期、各级缓存搬了多少字节。前面读过的吞吐率、命中率等全程指标,把 kernel 从开始到结束的活动汇总成一个值;为了收齐指标,ncu 可能需要重放多次,每次采集其中一部分。PM Sampling 也可能分多次重放采集,但会在运行过程中按设定间隔读取计数器,把各采样窗口里的结果沿时间轴画出来,好似示波器那样呈现变化,得到这一节的时间线视图。

基本数据表

ncu 说明为:PM 指标在 workload 运行期间周期性采样得来的时间线视图,数据跨多个 pass 收集,这一节用来看 workload 的行为随运行时间是怎么变化的。workload 指的是这次被剖析的 kernel 运行本身;pass 表示一次采集重放。GPU 能同时采集的计数器数量有限,全部指标无法一次采齐时,ncu 就把指标分组,在不同次重放中分别采集。

说明底下是 4 个数据:

项 值 说明
Maximum Sampling Interval 1 us 各采样组配置的采样间隔中的最大值,间隔越短,通常能看到越细的时间变化,也会产生更多数据 本报告两组都设为1微秒。以318.43微秒的kernel时长估算,对应约318个采样间隔;实际样本数量还受采集起止边界和样本合并影响
Maximum Buffer Size 24 Mbytes 采样到的数据先写进缓冲区,这一行给出各采样组所用缓冲区大小的最大值 本报告两组各为25,165,824字节,即24 × 1,024 × 1,024字节,按二进制单位应写作24 MiB;截图沿用界面的24 Mbytes
# Pass Groups 2 这次PM采样分成多少组指标采集,每组对应一次采样重放 本kernel的PM指标分成2组,分别通过两次重放采回来;这是PM Sampling自身的采集次数
Dropped Samples 0 sample 因缓冲区装不下而丢弃的样本数 两组都为0,说明这次采集没有因缓冲区不足而丢样

这4项交代采集设置和采集状态:本次分2组采样,间隔都设为1微秒,也没有因缓冲区不足而丢样。还要留意样本合并:采样结果来不及及时传出时,硬件可能合并样本,本报告两组分别记录了432和421个合并样本。因此,读时间线时仍要结合样本时间戳、采样窗口和不同次重放的对齐情况判断时间细节。

时间线

展开section,得到时间线图。横轴是时间,每一行展示一个指标在各个采样窗口里的值。图中从上往下分成Overview、SM、DRAM、L2 Cache、L1 Cache五组,点击组名左侧的三角形可以折叠这一组。读具体一行时,先看左侧的指标名,再看右侧标出的纵轴范围,最右边是随时间变化的采样值。这里百分比行的刻度上限统一是100 %,其它行按采到的最大值显示。

按住Ctrl键滚动滚轮可以缩放时间轴,左键单击可以选中一个采样值,悬停时能看到对应的时间和数值。下面写到的中段数值取自报告的采样数据,都是近似读数;行名旁边的最大值则沿用截图。横条只有几十个像素高,贴近0的曲线要通过悬停提示或采样数据确认读数。

最后一行Workload Execution用黄色横条标出本kernel的运行区间。时间轴的0是采样数据对齐后的相对起点,不一定与kernel的开始时刻重合,所以黄色横条从0的右侧才开始。黄色条的左右边界来自单独采集的kernel起止时间戳;开头这段间隔只说明两个起点不同,不能直接当作kernel的启动开销。

本报告的曲线来自两次重放:Overview、SM和DRAM属于一组,L2 Cache和L1 Cache属于另一组。ncu会过滤并对齐这些采样数据,但不同次重放不一定完全对齐,采样边界也不一定与kernel的起止边界重合。读时间线主要看运行中段的状态和整体趋势。有些曲线会比黄色条更早出现,或者更晚才归零,判断kernel的执行范围仍以黄色条为准。

Overview分组:

指标 说明
Average Active Warps Per Cycle,0 到 48.01 warp 平均到每SM的活跃warp数,正在等数据或等同步的warp也算。本卡每两个SM组成一个TPC,采样先用TPC内累计的活跃warp周期数除以相应的TPC活跃周期数,得到平均每TPC每活跃周期驻留多少个warp,再除以2折算到每SM 开头迅速升到接近48,中段主要在46左右,末尾再下降。48是每SM的硬件驻留上限,中段46 ÷ 48约为96 %,说明大部分warp位置一直有人占着,驻留数量较充足。刻度上的48.01是本图采到的最大值,比硬件上限高约0.02 %,属于轻微越界读数。ncu按测量值绘图,判断驻留容量仍使用48个warp的硬件上限
Total Active Warps Per Cycle,0 到 3.94k warp 把各SM的活跃warp数汇总到整块GPU。82个SM各驻留48个warp时,一共是82 × 48 = 3,936个,图上的最大值显示为3.94k 这条曲线与上一行对应,中段约为46 × 82 ≈ 3,770个warp,开头上升、末尾下降。两行分别从单个SM的平均值和整块GPU的总量描述驻留情况
Blocks Launched,0 到 98 block 每个采样窗口里新启动的block数。本kernel共有8,192个block,每block有256 ÷ 32 = 8个warp。按每SM的48个warp上限计算,最多能驻留48 ÷ 8 = 6个block,当前资源配置能达到这个上限,整卡同时最多容纳82 × 6 = 492个 开头集中启动一批block,随后暂时没有新block启动,曲线降到0,但前面启动的block仍在执行。中段每个窗口大约新启动25到30个block,用来接替已经完成的block,此时上一行的活跃warp仍接近满驻。末尾新启动数降到0,只表示不再补入新block,已经驻留的block还要继续收尾
SM Active Cycles,0 到 1.42k cycle 每个采样窗口里,各SM活跃周期数的平均值。SM只要还有warp驻留就算活跃,即使这些warp正在等待,也会计入 中段约1,400周期。按1微秒窗口和约1.39 GHz的SM频率估算,1.39 × 10⁹ × 10⁻⁶ ≈ 1,390周期,说明中段多数SM几乎整个窗口都有warp驻留。开头上升对应SM陆续进入活跃状态,末尾下降对应SM陆续空下来
Executed Ipc Active,0 到 1.54 inst/cycle IPC是instructions per cycle,每个周期执行多少条指令,这里数的是warp级指令。一个窗口内,各SM平均执行的指令数除以各SM平均活跃周期数,得到每SM每个活跃周期平均执行的指令条数 起步时较低,中段约0.57,尾段上升,最高显示为1.54。一个SM有4个SMSP,每个SMSP每周期最多发射一条指令;中段每SM每活跃周期只执行约0.57条,说明驻留虽充足,指令执行速率仍低。最后这条曲线尾段抬高,很容易被读成"剩下的block不用竞争,所以跑得更快了"。我们把分子、分母拆开看:中段一个窗口的IPC约为0.576,平均活跃周期约1,396,折算每SM约执行0.576 × 1,396 ≈ 804条指令;尾段IPC达到约1.535的窗口,平均活跃周期却只剩46.49,折算约1.535 × 46.49 ≈ 71条。IPC升高,窗口里的指令总量反而下降了。图上能确认的是活跃周期这个分母下降得更快,剩下的活跃周期里指令执行更密;具体是哪类等待减少、哪段代码占比改变,仅凭这曲线还分不出来。这里统计的是执行侧IPC,要精确读发射槽占用,应使用发射侧指标

SM分组:

这一组按SM及其内部SMSP的硬件时钟数周期,SMSP就是第二章介绍过的SM子分区,与所属SM使用同一时钟。SM频率约1.39 GHz,表示SM的时钟每秒走过约13.9亿个周期,1微秒内约有1,390个周期。采样窗口里的这些周期全部计入"流逝周期",其中也包括SM没有warp驻留的周期。

Overview里的Executed Ipc Active只把SM有warp驻留的周期计入分母。举个计算例子:假设一个SM在某个窗口里流逝了1,000个周期,其中600个周期有warp驻留,那么它的流逝周期数是1,000,活跃周期数是600。warp驻留期间即使在等数据,这些周期仍算SM活跃周期。这样,两种分母分别数什么就清楚了。

接下来我们要读管线的百分比。以ALU为例,分子是窗口内ALU实际执行的指令数,分母是"该SM在窗口内的流逝周期数 × ALU每周期可持续执行的指令数",相除再乘100 %。分母表示这条管线在整个窗口里持续吃满时能执行多少条指令。FMA Light和FMA Heavy在SMSP层统计,使用对应SMSP的流逝周期数和对应管线的峰值。Tensor这一行数的是管线活跃周期。各条管线能执行的指令类型和每周期的峰值不同,所以每行的100 %各指自己的满负荷水平,SM Throughput按这些组成指标中的最高值统计。

指标 说明
SM Throughput,0 到 100 % 先分别计算SM各组成指标的"实际处理速率 ÷ 对应峰值 × 100 %",再取其中最高值,得到本窗口里SM最忙执行资源相对自身峰值的利用率;下面四条管线只展示组成指标的一部分 运行中段约14 %,表示这套采样指标中利用率最高的SM执行资源,也只达到自身峰值的一成多。第二章Compute (SM) Throughput的15.98 %是全程汇总结果,两者都说明SM执行资源没有吃满;逐窗口采样和全程汇总不要求数值完全相同
SM ALU Pipe Throughput,0 到 100 % ALU实际执行的指令数,除以同一窗口内ALU持续吃满时能执行的指令数,再乘100 %,得到ALU的指令吞吐达到自身峰值的比例。整数加法、逻辑和比较等指令走ALU管线 起步后升到约12 %的平台,末尾下降,与本kernel持续计算数组下标和循环条件的代码相呼应。这里的12 %说的是指令吞吐达到ALU自身峰值的比例;第二章ALU的11.84 %数的是管线有活动的周期占比,两项分别按指令数和活跃周期数计算
SM FMA Light Pipe Throughput,0 到 100 % FMA Light实际执行的指令数,除以同一窗口内该SMSP的FMA Light管线持续吃满时能执行的指令数,再乘100 %,得到这条管线的指令吞吐达到自身峰值的比例。这条管线处理FP32、FP16浮点算术 中段约1.4 %,表示FMA Light的指令吞吐只达到自身峰值的约1.4 %,曲线贴近底线。本kernel求和用的FADD是单精度浮点加指令,它的执行次数远少于整数和地址计算指令,FMA Light没有吃满
SM FMA Heavy Pipe Throughput,0 到 100 % FMA Heavy实际执行的指令数,除以同一窗口内该SMSP的FMA Heavy管线持续吃满时能执行的指令数,再乘100 %,得到这条管线的指令吞吐达到自身峰值的比例。除浮点算术外,这条管线还处理IMUL整数乘法、IMAD整数乘加等指令 中段约6.8 %,Light约为1.4 %;两个百分比分别以各自管线的峰值为基准。kernel计算全局下标、访存地址以及求余展开时都会用到整数乘加,所以Heavy的活动也包含整数计算。第二章FMA Heavy的8.82 %数的是管线有活动的周期占比,与这里按执行指令数统计的分子不同
SM Tensor Pipe Throughput,0 到 100 % 分子是采样窗口内SM内部Tensor管线实际处于活跃状态的周期计数,分母是该管线在所属SM的全部流逝周期内持续满负荷时对应的活跃周期计数,相除再乘100 %,得到Tensor管线活动达到持续峰值的比例。矩阵乘加等Tensor指令走这条管线 本kernel没有Tensor运算,采样值全为0,曲线全程贴底

DRAM分组:

DRAM就是GPU的显存。这一组看显存的数据传输速度,读、写分别表示数据从显存送出、向显存写入。下面的百分比都把实际速率与显存对应方向的峰值速率相比。

指标 说明
DRAM Throughput,0 到 100 % 先分别计算显存各组成指标的实际吞吐,再除以各自对应的持续峰值并乘100 %,最后取最高值,得到显存侧最忙组成指标相对自身峰值的利用率。这里量的是显存和显存控制器的数据传输 中段大约23 %,与第二章全程DRAM Throughput的23.23 %接近,说明显存侧最忙的组成指标也没有接近峰值。显存吞吐未满仍可能有访存等待:每秒搬了多少字节,和某条读取请求要等多久才能拿到数据,是两个不同的量
DRAM Read Bandwidth,0 到 100 % 在一个采样窗口里,从显存读出的字节数除以窗口时长,得到显存读速率;再用这个速率除以显存读方向的峰值速率并乘100 %,得到显存读速率达到读方向峰值的比例。两个速率都可以用字节/秒表示 中段约23 %,说明读取速度达到显存读峰值的约两成多。输入数组的数据如果已经在L1或L2中找到,就不需要再从显存读取,也不会增加本行的读流量。第二章Memory Chart里的显存读流量约67.12 MB,是整个kernel期间的总量;本行则把读活动按采样窗口分开显示
DRAM Write Bandwidth,0 到 100 % 在一个采样窗口里,写入显存的字节数除以窗口时长,得到显存写速率;再除以显存写方向的峰值速率并乘100 %,得到显存写速率达到写方向峰值的比例。它与上一行分别以写、读方向的峰值为基准 多数窗口接近0,间或出现短小的凸起,总体远低于读方向。序章里每个block只写回一个float,第二章Memory Chart里的显存写流量约2.05 MB,也远小于读流量。图上的凸起反映显存写活动在对应采样窗口中的增加

L2 Cache分组:

名字 含义
L2 Throughput,0 到 100 % 对L2内部处理请求和传输数据的各条通路,分别用实际处理速率除以该通路的持续峰值速率,再乘100 %,取其中最高值,得到L2最忙通路相对自身峰值的利用率。按周期计算速率时,使用L2单元自身的时钟周期 起步后升到约82 %的平台,末尾回落。这表示L2最忙的通路达到自身峰值的八成多,与第二章全程L2 Cache Throughput的80.44 %相近。显存约23 %则是显存相对自身峰值的水平;两个百分比分别反映两级硬件各自距离满负荷还有多远
L2 Hit Rate,0 到 100 % 统计这一窗口里,向L2查询的sector有多少已经能在L2中找到数据。用命中的sector数除以请求查询的sector数,再乘100 %,就是命中率 中段约89 %,可以读作每查询100个sector,大约89个在L2中找到数据,其余约11个需要继续向下一级存储请求。第二章的全程命中率是87.53 %。病态一按列读取时,相邻block会用到同一个sector里的不同float,前一个请求把数据带进L2,后续请求就有机会命中。因此,L2要处理很多请求,显存却不必为每个请求重新读一次数据。末尾的请求数量要结合L2 Throughput判断,即使命中率接近100 %,也只说明剩余请求多数命中

L1 Cache分组:

名字 含义
L1 Throughput,0 到 100 % 逐条计算L1TEX各组成通路在这一窗口里的"实际处理速率 ÷ 对应通路的持续峰值速率 × 100 %",再取最高百分比,得到L1TEX最忙通路相对自身峰值的利用率。计算每周期处理速率时,用的是L1TEX自身在窗口内的全部流逝周期,包括通路没有工作的周期 中段约57 %,采样最大值约63 %。本行来自L1TEX的实时采样指标,第二章L1/TEX Cache Throughput的92.45 %来自另一项全程采集指标。两处界面名称相近,解读时要分清各自使用的指标和采集方式。本图能说明L1TEX中段持续有访存工作;判断整条内存链路的瓶颈,还要结合L2和显存各自的吞吐以及第二章的流量证据
Writeback Throughput,0 到 359.29 cycle 每个采样窗口里,分别数各SM内部L1TEX的数据返回通路有多少个L1TEX时钟周期在工作,再对这些L1TEX单元取平均。数据返回通路负责把读回的数据交还给SM的寄存器 中段约300周期,最大值359.29周期。300的意思是每个L1TEX的数据返回通路,在这个窗口里平均有约300个自身时钟周期处于活跃状态。本kernel的全局读和共享读持续产生返回数据,中段因此形成平台。这个值汇总了窗口内多笔请求的数据返回活动
Hit Rate,0 到 100 % 统计这一窗口里,向L1TEX缓存查询的sector中有多少命中,再用命中的sector数除以请求查询的sector数并乘100 %,得到L1TEX这一层的sector命中率。与L2 Hit Rate的算法相同,区别是查询和命中都发生在L1TEX这一层 曲线几乎贴底,运行中段通常低于0.1 %,全程指标为0.080881 %,说明请求很少直接在L1TEX中找到数据。本kernel的全局读中,相邻线程的地址相隔32 KB,同一warp内难以合并;不同block之间虽然可能复用同一个sector,却不保证被安排到同一个SM、共用同一个L1。L2由所有SM共享,因此L1命中很少与L2命中较多并不矛盾
Wavefronts (Data),0 到 850.93 每个采样窗口里,先数每个L1TEX的数据管线处理了多少个wavefront,再对各L1TEX单元取平均。一个wavefront是一份能在L1TEX数据管线的一个时钟周期内处理完的工作;一条访存请求可能拆成多份wavefront,分别占用多个管线周期 中段约800,最大值850.93,起步上升、末尾下降。800表示每个L1TEX在这个窗口里平均处理约800份wavefront工作。多单元取平均后,结果可以带小数。计数里包含正常访存所需的wavefront,也包含bank conflict导致的额外wavefront;第二章已把多余的524,288个wavefront定位到两条LDS.128共享内存加载指令

这张时间线补上了全程平均值里看不到的起步、中段和收尾过程。中段每个SM约驻留46个warp,每个SM活跃周期却平均只执行约0.57条warp级指令,说明驻留充足没有换来高指令执行速率。L2吞吐约82 %、显存约23 %,分别表示两级硬件相对自身峰值的利用程度,与第二章看到的内存链路压力分布相呼应。读图时,先认清每行统计的是哪个硬件单元,再看分子数的是指令、字节、sector还是活跃周期,以及分母用的是什么;同样叫百分比,回答的问题也可能完全不同。

Compute Workload Analysis

这一节分析SM在整个kernel执行期间的计算资源利用情况,主要看指令执行与发射速率,以及各条执行管线的利用率。

IPC,instructions per cycle,也就是每周期执行或发射多少条指令,这里仍按warp级指令计数。每个SM有4个SMSP,每个SMSP每周期最多发射一条,因此每SM每周期最多发射4条;发射侧IPC除以4,就得到发射槽利用率。

下面的数据表有Executed Ipc Elapsed、Executed Ipc Active和Issued Ipc Active三个IPC指标。名称里的Executed表示执行,Issued表示发射,用来区分分子数的是已执行的指令还是发射出去的指令。指标名末尾的Elapsed和Active用来区分分母。Elapsed使用SM在整个kernel执行期间流逝的全部时钟周期,Active只使用其中至少有一个warp驻留的活跃周期。这两种周期都按SM自身的时钟统计;warp驻留期间即使正在等数据或等同步,也会计入SM活跃周期。本报告每SM平均活跃437,992.54个周期,平均流逝442,680.22个周期,两者相除约为0.9894。同一项指令计数,用活跃周期作分母得到的速率,乘0.9894就能换成流逝周期口径。第二章的443,927是GPU层的流逝周期数,本节的IPC统一使用SM层的周期数。

基本数据表

ncu说明为:对流式多处理器(SM)计算资源的详细分析,包括每周期执行指令数和各计算管线利用率,利用率非常高的管线有可能限制整体性能。

这一节的5项在界面上分左右两列,左列三个是IPC,右列两个是百分比,下表先左列后右列:

项 值 说明
Executed Ipc Elapsed 0.56 inst/cycle 每SM的warp级执行指令数,除以该SM在kernel期间流逝的全部时钟周期数,得到每SM每个流逝周期平均执行的指令条数 20,488,192 ÷ 82 ÷ 442,680.22 ≈ 0.5644,界面显示0.56,表示每SM每个流逝周期平均执行约0.56条指令
Executed Ipc Active 0.57 inst/cycle 每SM的warp级执行指令数,除以该SM有warp驻留的活跃周期数,得到每SM每个活跃周期平均执行的指令条数 20,488,192 ÷ 82 ÷ 437,992.54 ≈ 0.5705,界面显示0.57。剔除SM没有warp驻留的周期后,分母略小,所以比上一行略高
Issued Ipc Active 0.57 inst/cycle 每SM的warp级发射指令数,除以该SM的活跃周期数,得到每SM每个活跃周期平均发射的指令条数 20,512,745 ÷ 82 ÷ 437,992.54 ≈ 0.5711,界面也显示0.57。发射数比执行数多24,553条,约0.12 %
SM Busy 14.28 % 用SM指令处理的实际吞吐除以对应持续峰值,再乘100 %,得到SM指令处理活动相对持续峰值的利用率;统计范围是SM有warp驻留的活跃周期 本报告为14.28 %,与Issue Slots Busy相同。它量的是SM的指令处理活动
Issue Slots Busy 14.28 % 实际发射指令数,除以SM活跃周期内全部可用发射槽数,再乘100 %,得到发射槽中实际被使用的比例。每SM每周期有4个发射槽 0.5711 ÷ 4 ≈ 14.28 %;若把SM空闲周期也计入分母,再乘0.9894,约为第二章的14.13 %

这五个值要把执行与发射分开读:执行侧每SM每活跃周期约0.5705条,发射侧约0.5711条;后者除以4个发射槽,得到14.28 %。也就是说,平均约85.72 %的发射机会没有用上。原因可能是驻留的warp太少,也可能是warp已经驻留,但下一条指令所需的数据或同步条件还没满足;满足这些条件、随时可以发射的warp,报告称为eligible,也就是合格warp。

表格底下还挂着一条OPT警告,规则名叫Low Utilization,它说:所有计算管线都没吃满,要么是本workload非常小,要么是每个调度器发射的warp不够多,可以到Launch Statistics和Scheduler Statistics里看进一步细节。Est. Local Speedup是88.04 %。

这里的Local表示估算范围。不带Local的Est. Speedup估计整个kernel的运行时间可以减少多少;Est. Local Speedup针对规则关注的局部问题,例如某条管线还剩多少利用空间。评估优化建议时,要先分清估算范围。本条的88.04 %来自100 % − 11.96 %;图中指标表给出的ALU管线利用率原值为11.9634,保留两位小数就是11.96 %。ALU是这条规则比较的计算管线中最忙的一条,这个利用率按SM活跃周期统计。规则在这个利用率低于20 %时触发,本报告满足条件。剩余的88.04 %表示这套估算中尚未利用的份额,实际加速效果需要修改后重新测量。规则建议检查启动规模和调度情况。PM Sampling已经看到运行中段每SM约驻留46个warp,接近48个的硬件上限,因此本例可以先检查这些驻留warp为什么仍发不出指令。

Pipe Utilization 图

展开section,Pipe Utilization图把各条管线画成横条。左右面板的横轴都是利用率,范围为0到100 %,一行对应一条管线。横条不直接标数字,下面的读数来自悬停提示;显示值保留两位小数。管线可以同时处理多条尚未完成的指令。左面板统计管线活动的周期,右面板统计执行的指令,两边的百分比分别对照各自峰值读取。

左面板标题为Pipe Utilization (% of active cycles)。分子数管线有活动的周期,分母以该管线所属SM的活跃周期为基础,并按该管线持续满负荷的水平换算成百分比。SM有warp驻留时,ALU或FMA可能暂时没有指令要处理,因此管线的活跃周期数可以远少于SM活跃周期数。各行从上往下是ALU 11.96 %、FMA 5.17 %、FP64 0 %、Tensor (All) 0 %、Tensor (FP) 0 %、Tensor (INT) 0 %。ALU的活动主要来自整数加法、逻辑、比较和下标计算。FMA则是GA10x上覆盖FMA Light、FMA Heavy两条物理管线的汇总口径,既包含浮点算术,也包含Heavy承担的整数乘加。第二章FMA的5.11 %与FMA Heavy的8.82 %覆盖范围重叠,而且各自的峰值不同。本kernel没有双精度和Tensor运算,所以左面板后四行都是0。

右面板标题为Pipe Utilization (% of peak instructions executed)。这里改数执行过的指令:实际指令数除以"所属SM或SMSP的活跃周期数 × 对应管线每周期的指令吞吐峰值",再乘100 %。它表示一条管线达到自身指令吞吐峰值的程度。右面板从上往下有数值的七行是LSU 16.15 %、ALU 11.96 %、XU 8.76 %、ADU 4.38 %、FMA 4.07 %、Uniform 0.09 %、CBU 0.05 %;其余FMA (FP16)、FP64 (DMMA)、FP64 (FP64)、TEX、Tensor (FP)、Tensor (INT)都是0。两个FP64条目分别对应双精度矩阵运算和普通双精度指令,Tensor的FP、INT分别表示浮点和整数矩阵运算,本例都没有使用。

右面板最忙的是处理访存指令的LSU,16.15 %乘SM活跃周期与流逝周期之比0.9894,约为第二章的15.98 %。左面板最忙的是ALU的11.96 %,Low Utilization规则用的就是这一项。ALU两边读数相同,FMA则分别为5.17 %和4.07 %,对应的分子分别数周期和指令。XU仍是第二章介绍过的超越函数与类型转换单元,本例的I2F整数转浮点、MUFU.RCP求倒数、F2I浮点转整数来自病态三的求余展开。ADU支持分支地址处理和block同步,本kernel执行了720,896条BAR同步指令,是需要结合代码分析的一部分。Uniform是warp共用输入输出的标量通路,CBU处理汇聚屏障等指令;本行CBU按执行指令数和SM活跃周期计算,得到0.05 %;第二章那一项只计至少有一个线程满足执行条件的CBU指令,并使用流逝周期及该指标对应的峰值,得到0.20 %。两项各有自己的计数条件和分母。

Compute Workload Analysis给出的全程结果与PM Sampling相呼应:驻留的warp很多,SM执行和发射指令的速率却低。每SM每活跃周期只发射约0.57条,四个发射槽的利用率为14.28 %;各条执行管线也远未吃满。接下来沿调度器这一层,查看驻留warp里究竟有多少已经准备好发射。

Scheduler Statistics

这一节统计warp调度器管理、选择和发射warp的情况,通过驻留数量、合格数量和实际发射率,判断调度器有没有充分利用发射机会。每个SMSP有一个调度器,整卡共82 × 4 = 328个,每个最多管理12个驻留warp。下面表中的三个指标名称分别是Active Warps Per Scheduler、Eligible Warps Per Scheduler和Issued Warp Per Scheduler。Per Scheduler表示按每个调度器统计;Active Warps指已驻留的warp,Eligible Warps指其中下一条指令已具备执行条件的warp,Issued Warp指实际被调度器选中并发出指令的warp。调度器可以让多个warp交替发射:一个warp等数据时,另一个准备好的warp继续执行,这就是延迟隐藏,它把等待与其它warp的工作重叠起来。如果驻留的warp都没有准备好,调度器就只能空过这个发射机会。

基本数据表

ncu说明为:汇总调度器的指令发射活动。每个调度器从自己管理的驻留warp中检查哪些已经准备好,再选出一个发射;没有合格warp时,发射槽空着。大量空槽说明其它warp的工作没有充分盖住等待。本卡每个调度器每周期最多发射一条指令,按这个上限读本节数据即可。

这一节的5项在界面上分左右两列,左列三个是每调度器的warp数,右列两个是周期占比,下表先左列后右列。这里按SMSP的时钟数周期,平均数和周期占比以SMSP有warp驻留的活跃周期为统计范围。

项 值 说明
Active Warps Per Scheduler 11.42 warp 在SMSP活跃周期里,平均每个调度器管理多少个驻留warp,原值11.421472 11.421472 ÷ 12 ≈ 95.18 %,说明驻留数量接近上限。正在等待的warp也计入这个平均数
Eligible Warps Per Scheduler 0.28 warp 在SMSP活跃周期里,平均每个调度器有多少个warp已经准备好发射,原值0.278029 0.278029 ÷ 11.421472 ≈ 2.43 %,说明平均驻留数量中,合格的部分很少;每个周期按整数计数,跨周期平均后得到0.28
Issued Warp Per Scheduler 0.14 warp 在SMSP活跃周期里,平均每个调度器每周期实际发射多少个warp的指令,原值0.142769 本卡每次选中一个warp发射一条指令,1 ÷ 0.142769 ≈ 7.0,即每个调度器平均约7个活跃周期才发射一条
No Eligible 85.72 % 没有合格warp的SMSP活跃周期数,除以SMSP活跃周期总数,再乘100 %,得到调度器因没有合格warp而空过发射机会的周期占比 85.72 %的活跃周期没有可发射的warp。各调度器的结果在85.52 %到85.85 %之间,说明这种低发射率普遍存在
One or More Eligible 14.28 % 至少有一个合格warp的SMSP活跃周期数,除以SMSP活跃周期总数,再乘100 %,得到调度器有warp可发射的周期占比 与No Eligible互补,85.72 % + 14.28 % = 100 %。本卡每个合格周期能使用一个发射槽,因此与前面的发射槽利用率对应,但统计层级分别是SMSP和SM

这五个值连起来读:每个调度器平均有11.42个驻留warp,但每周期平均只有0.28个已经准备好,85.72 %的活跃周期里一个合格warp都没有。驻留数量接近上限,发射机会却大部分空着,说明等待没有被其它warp的工作充分隐藏。

表格底下还挂着一条OPT警告,规则名叫Issue Slot Utilization,它说:每个调度器本来每个周期能发出一条指令,本workload却平均每7.0个周期才发出一条,可能让硬件资源没用满、性能不够理想。12个warp的上限里平均有11.42个活跃、每周期只有0.28个合格;要增加合格warp,得避免各warp执行时长差太多造成负载不均,减少停顿也有帮助。Est. Local Speedup是19.56 %。

这条规则先算空槽份额:100 % − 14.28 % = 85.72 %。随后用Compute与Memory Throughput中较高的80.44 %约束估算,取85.72 %与100 % − 80.44 %两者中较小的值,得到19.56 %。这个19.56 %是规则针对当前计数器数据给出的估算。警告下方的关键指标表列出发射率原值0.142769,与上表Issued Warp Per Scheduler对应。倒数1 ÷ 0.142769 ≈ 7.0,给出平均每个调度器约7个活跃周期发射一条指令的结果。

Warps Per Scheduler 图

图的横轴是warp数,范围为0到16。五条横条依次是硬件上限12、本次配置的理论上限12、实际活跃11.42、合格0.28、实际发射0.14。前两条相等,说明启动配置没有把驻留上限压低;实际活跃数也接近12,合格和发射两条却很短。图中最明显的差距发生在"已经驻留"到"准备好发射"之间。

Scheduler Statistics把发不出指令的原因收窄到了warp状态:数量充足,但准备好的warp太少。平均每个调度器约7个活跃周期才发射一条指令,85.72 %的活跃周期没有合格warp;具体在等什么,要看这些warp各自的停顿原因。

Warp State Statistics

这一节按warp所处的状态统计周期,展示各类等待分别占多少。一个warp可能在等数据、等同步、等队列腾位,也可能已经准备好、只是调度器选了别的warp。ncu把这些状态分别统计;被选中并发出指令的状态叫Selected。这里统计warp累计周期,时钟仍是warp所在SM/SMSP的时钟。例如两个warp各等待3个周期,累计就是6个warp周期,即使两者的等待发生在同一段3周期里。把某种状态累计的warp周期数除以发射指令数,才得到图上"每发射一条指令平均摊到多少周期"的值。多个warp可以同时等待,要注意区分累计warp周期占比与kernel实际运行时间占比。表里的CTA是cooperative thread array,也就是一个block;CTA barrier要求同一个block内的线程在同步点会合。状态图中的Stall Membar指等待内存屏障,它处理访存先后顺序要求,和block内线程是否到齐不同。

基本数据表

ncu说明为:统计kernel执行期间warp所处的各类状态,分析warp为什么能或不能发射下一条指令。每条发射指令摊到的warp周期越多,就越需要其它准备好的warp提供工作来隐藏等待。分析停顿时,重点看它是否让调度器持续发不出指令。本例调度器有85.72 %的活跃周期发不出指令,所以值得分析占比最大的停顿。

说明底下是4个数据,界面上左右两列各两项,两条讲周期、两条讲线程数,下表先左列后右列:

读后两项前,先看归并循环里的if:条件成立的线程做加法,其余线程跳过这次加法。编译器会把各线程的条件判断结果保存为真或假,汇编里把这种结果叫谓词,后续指令据此决定哪些线程实际参与操作。例如一个warp的32个线程都还活跃,其中只有16个满足加法条件,这条指令就计32个活跃线程、16个实际参与操作的线程。后两项分别统计这两种数量的全程平均值。

项 值 说明
Warp Cycles Per Issued Instruction 80.00 cycle 全部驻留warp累计的活跃周期数,除以warp级发射指令总数,得到每发射一条warp级指令平均摊到的warp周期数,原值79.999944 每条发射指令平均摊到约80个warp周期。这80个warp周期由多个warp的驻留周期累加而来;按每个调度器的时钟统计,实测平均约7个活跃周期发射一条指令
Warp Cycles Per Executed Instruction 80.10 cycle 同一份warp累计活跃周期数,改除以warp级执行指令总数,得到每执行一条warp级指令平均摊到的warp周期数,原值80.095815 执行数比发射数少24,553条,分母略小,所以由80.00增到80.10
Avg. Active Threads Per Warp 31.94 把每次执行warp级指令时的活跃线程数累计起来,除以warp级执行指令总数,得到每条指令平均有多少个活跃线程 654,352,384 ÷ 20,488,192 ≈ 31.94;满足执行条件的线程数见下一行
Avg. Not Predicated Off Threads Per Warp 25.79 每次先数有多少活跃线程满足这条指令的执行条件,把这些线程参与的次数累计起来,再除以warp级执行指令总数,得到每条指令平均实际参与操作的线程数 528,400,384 ÷ 20,488,192 ≈ 25.79。与31.94相差约6.15,表示平均每条指令有约6.15个活跃线程因执行条件不满足而跳过操作

前两个数说明每条发射或执行指令摊到的warp累计周期,后两个数说明每条warp级指令有多少线程参与。活跃线程平均31.94个,按执行条件筛选后,实际参与操作的平均有25.79个。第二章Branch Efficiency为100 %,描述分支跳转是否一致;这里进一步统计每条指令有多少线程满足执行条件并参与操作。

以归并循环里的浮点加指令FADD为例:它执行524,288次,每次统计32个活跃线程,共16,777,216条线程指令;其中满足执行条件、实际参与加法的只有2,088,960条,比例约12.45 %。回到代码,8轮里实际做加法的线程数是128、64、32、16、8、4、2、1,加起来255;总的线程轮次是256 × 8 = 2,048,255 ÷ 2,048 ≈ 12.45 %。报告和源码在这里对上了,病态三的低效就体现在这些陪跑线程上。

表格下方有两条OPT警告和一条INF提示。第一条Barrier Stalls指出,每条发射指令平均摊到32.1个等待CTA barrier的warp周期,占80.0个总warp周期的约40.1 %。规则建议找到等待最多的同步位置,检查同步之前各warp的工作是否均衡;Est. Speedup为19.56 %。

关键指标表有两行:发射率0.142769,以及barrier等待原值32.0652。后者保留两位小数是32.07,32.07 ÷ 80.00 ≈ 40.1 %,就是这类等待占总warp累计周期的比例。回到本例,归并循环每一轮都执行 __syncthreads(),不同warp的有效工作量越来越不均衡;第二章采样表中,归并同步后那条BRA的barrier样本最多,说明这里值得优先分析。这项汇总包含其它同步位置的等待,具体贡献仍要按同步点分别检查。规则中"512线程以上考虑切成更小的组"的建议针对更大的block;本例每个block为256线程,分析重点是同步前代码的负载分配和逐行采样。

第二条Mio Throttle Stalls指出,每条发射指令平均摊到28.1个等待MIO指令队列腾位的warp周期,占80.0个总warp周期的约35.2 %。MIO是前面介绍过的内存输入输出单元,共享内存、特殊数学和动态分支等指令会经过相关队列。规则建议检查是否能用更少、更宽的共享内存加载减轻队列压力;Est. Speedup同样为19.56 %。

关键指标表第二行给出MIO队列等待原值28.1336,保留两位小数为28.13。28.13 ÷ 80.00 ≈ 35.2 %。这里统计warp在MIO指令队列入口等待空位的周期;等待操作结果的周期在后面的状态图中另行统计。第二章已经定位到两条LDS.128的bank conflict:每次读理想需要4个wavefront,实际需要8个。额外wavefront在L1TEX中串行处理,会延长请求的服务时间,并可能加重上游排队。MIO队列以指令为单位,后续L1TEX数据管线则以wavefront为工作单位。一次指令发射后,请求可以在L1TEX里拆成多个wavefront继续处理。规则建议用更少、更宽的加载,本例编译器已经把八次float读合成了两条128位加载,但冲突仍在。加载宽度之外,还需要检查访问地址的布局;同时,MIO还有其它指令来源,要结合Source页定位,才能判断各段代码的贡献。

两条OPT都显示19.56 %,也与前面Issue Slot Utilization的数值相同,是因为估算都受到80.44 %这个吞吐指标的约束。三项涉及的等待可能互相关联,不能把三个19.56 %相加;前面的Issue Slot Utilization还是Local估算,两条停顿警告则估计整个kernel的运行时间改善。

第三条INF提示叫Warp Stall,没有Est. Speedup。它引向第二章读过的Warp Stall Sampling (All Samples):本节按原因汇总,那张表按指令定位,配合阅读才能把等待落回具体代码。

Warp State (All Cycles) 图

展开section,Warp State (All Cycles)图一行展示一种warp状态,按平均周期数从大到小排列。横轴是每发射一条指令摊到的该状态warp周期数,刻度为0到40;横条上的具体数值从悬停提示读取。图中也列出了Selected,即warp已经被选中发射的状态。

图上18行的数值和来历如下表所示,各行的占比是拿周期数除以80.00算出来的:

项 值 说明
Stall Barrier 32.07 cycle 等同一个block的其它warp到达同步点,占40.1 % 本例归并每轮都同步,逐行采样也指向归并循环;这一行汇总了所有同步位置的等待
Stall MIO Throttle 28.13 cycle 等MIO指令队列腾位,占35.2 % 共享内存冲突会延长访存服务,可能加剧上游排队;MIO也承接特殊数学和动态分支,要结合逐行信息判断来源
Stall Short Scoreboard 8.35 cycle 等MIO操作的结果依赖,占10.4 %;记分板记录哪些结果还没准备好 常见来源是共享内存访问,也可能来自特殊数学和动态分支。这里等MIO操作的结果,上一行等MIO指令队列腾位
Stall Wait 3.23 cycle 等待固定延迟指令的结果依赖,占总warp周期约4.0 % 前一条指令的结果还没准备好,当前指令又要使用这个结果,warp就不能继续发射。本例这一项明显小于Barrier和MIO Throttle
Stall Long Scoreboard 2.65 cycle 等待L1TEX访存操作的结果依赖,例如全局或本地内存读取,占总warp周期约3.3 % 病态一的全局加载可能造成这类等待。L2高命中率能减少需要下到显存的请求,具体等待位置仍要结合逐行采样分析;采样记录的是等待使用数据的指令,发起读取的LDG可能位于更前面
Stall LG Throttle 2.57 cycle 等待本地、全局访存方向的指令队列腾出位置,占总warp周期约3.2 % 本例有八条展开后连续发射的LDG.E全局加载指令,是需要检查的来源。这里等的是队列入口,Long Scoreboard等的是已发出请求的结果
Selected 1.00 cycle warp被选中并发出指令;Raw原值0.999997 每条发射指令平均对应约一个被选中的warp周期
Stall Not Selected 0.95 cycle warp已经合格,但这个周期调度器选了另一个warp发射,占总warp周期约1.2 % 它说明准备好的warp之间存在选择。本例这一项较小,结合Eligible平均只有0.28,主要问题仍是准备好的warp不足
Stall Drain 0.23 cycle warp执行EXIT后,等待尚未完成的访存操作结束,以便释放资源,占0.29 % EXIT是线程退出指令;本项记录退出阶段为收尾访存而等待的周期,具体位置可结合Source页判断
Stall Math Pipe Throttle 0.18 cycle 等数学管线可以接收下一条指令,占0.23 % 本报告这类等待很少
Stall Dispatch Stall 0.17 cycle 指令已备好,派发环节因为冲突或事件压着不发,占0.22 % 这里统计的是派发环节的等待,本报告占比很小
Stall No Instruction 0.13 cycle 等被选中取指,或等指令缓存缺失处理,占0.16 % 本报告取指等待占比较小
Stall Branch Resolving 0.10 cycle 等分支目标解析及程序计数器更新,占0.13 % 它和同一warp内线程走不同路径造成的分支分歧是两件事
Stall IMC Miss 0.10 cycle 等待立即数常量缓存的缺失处理,占总warp周期约0.13 %。IMC是immediate constant cache,用于访问指令中指定的常量数据 本例常量读取等待占比较小
Stall Tex Throttle 0.00 cycle 等待纹理方向的指令队列腾出位置,原值0.000669周期 保留两位小数后显示0.00,本报告这类等待极少
Stall Misc 0.00 cycle 未归入其它条目的硬件等待,原值0.000175周期,显示为0.00 本例占比很小
Stall Membar 0 cycle 等内存屏障,处理访存顺序要求 0,本报告没有记录到这类停顿;block同步位置的等待看Stall Barrier
Stall Sleeping 0 cycle warp里全部线程都阻塞、让出或睡眠时记这项,由NANOSLEEP这类指令造成 0,本kernel没有让线程睡过

这18行里,Barrier与MIO Throttle合计60.20个warp周期,除以80.00约占75.2 %;再加其后四项,前六项约占96.2 %。按这个占比确定分析顺序,应先检查同步、共享访存以及相关指令队列。本报告18项原值相加为79.87,与总项80.00略有差异;显示值相加为79.86,又有舍入差异。计算占比仍沿用总项80.00,保留各项实测值。

这张图还可以和第二章的Warp Stall Sampling表交叉验证。采样表按指令收集停顿样本,其中barrier占37.6 %、MIO Throttle占35.5 %、Short Scoreboard占11.5 %;与本表相比,前三项的顺序相同,比例也接近。一边的分母是17,547笔采样,另一边的分母是累计warp周期,两表从不同统计角度指向相同的主要等待原因。

Warp State Statistics把等待原因展开了:Barrier的32.07和MIO Throttle的28.13合计占总warp周期约75.2 %,应优先检查同步和相关指令队列。80.00 ÷ 11.421472 ≈ 7.0,也把每条指令摊到的warp累计周期,与前面每个调度器约7个活跃周期发射一条的结果接了起来。具体修改哪个同步点或哪段访存,仍要结合Source页的逐行证据。

Instruction Statistics

这一节统计各类SASS指令的执行次数,展示kernel实际执行的指令组成。报告按opcode,也就是操作码分类:IMAD算一类,FADD算另一类,每类把所有对应指令的执行次数加起来。这就是指令混合统计,用来观察整数计算、浮点计算、访存和控制指令各占多少。

基本数据表

ncu说明为:统计执行过的SASS指令,按类型和次数展示指令混合。某类指令特别多,说明对应管线承担的工作较多;是否限制性能,还要结合Compute Workload Analysis的管线利用率判断。按操作码分类统计的执行次数,与执行指令总数采用的采集方法不同,遇到系统调用等情况时可能出现偏差;本报告21类指令的次数之和与执行总数相等。

说明底下是4个数据,界面上左右两列各两项,左列两个总数、右列两个平均值,下表先左列后右列:

项 值 说明
Executed Instructions 20,488,192 inst 整个kernel执行的warp级指令总数,一条warp级指令计一次,不按32个线程重复计数 指令混合的占比与平均参与线程数都用20,488,192作分母;每条发射指令摊到的warp周期则用发射总数作分母
Issued Instructions 20,512,745 inst 整个kernel发射的warp级指令总数 20,512,745 − 20,488,192 = 24,553,比执行数多约0.12 %
Avg. Executed Instructions Per Scheduler 62,464 inst 20,488,192 ÷ 328 = 62,464,每个调度器平均执行的warp级指令数 最少61,272条,最多65,026条;(65,026 − 61,272) ÷ 62,464 ≈ 6.0 %,说明各调度器的执行数量比较接近
Avg. Issued Instructions Per Scheduler 62,538.86 inst 20,512,745 ÷ 328 ≈ 62,538.86,每个调度器平均发射的warp级指令数 比平均执行数多74.86条,正好对应总差额24,553 ÷ 328 ≈ 74.86

这四个值把全章反复使用的两个总数列到了一起:执行20,488,192条,发射20,512,745条。Compute Workload Analysis用它们除以SM周期算IPC;Warp State分别用它们作分母,计算每条指令摊到的warp周期和线程参与数量。

表格底下挂着一条OPT警告,规则名叫FP32 Non-Fused Instructions,它说:本kernel执行了0条融合和1,048,576条非融合的FP32指令,建议检查是否能把成对的非融合指令换成融合版本,并给出FP32环节50 %的优化空间,可以到Source页找FP32指令的位置。Est. Speedup是2.58 %。

这说的是融合乘加:FADD做加法,FMUL做乘法,FFMA一条指令计算a×b+c。存在合适的乘、加配对时,一条FFMA可以代替两条指令,编译器通常会尝试这种融合。本kernel的1,048,576条非融合FP32指令全是FADD:共享内存里的八个数逐次相加,共524,288条;树形归并中的FADD又执行524,288次。这两处都是纯加法,缺少与加法配对的乘法,因此这条融合建议在本例中用不上。规则用"非融合指令占比的一半"估算局部空间,本例是100 % ÷ 2 = 50 %,再乘图中指标表给出的FMA管线利用率5.16628 %,得到显示的2.58 %。这个估计的前提是代码中存在可融合的乘加组合,阅读这条建议时要先核对这一条件。

Executed Instruction Mix 图

表格底下是Executed Instruction Mix图,把执行过的指令按opcode分类画了出来:

一行一种opcode,按执行次数从大到小排,横轴是warp级指令条数,刻度到5,000,000;横条上不标数字。一共21行,行序与图完全一致,占比拿每行条数除以20,488,192;MUFU、LOP3、LEA、LDG、I2F、F2I六条并列524,288次,ULDC、SHF、CS2R三条并列65,536次,并列的按名字倒着排:

项 值 说明
IMAD 4,792,320 整数乘加,一条指令计算整数a × b + c,占全部执行指令约23.4 % 本例最多的一类,主要用于下标、地址及求余展开中的整数计算,GA10x上由FMA Heavy管线承担
ISETP 3,276,800 整数比较,把条件成立与否写进谓词寄存器,占16.0 % 循环条件、if判断、归并每轮的步长判断都靠它;后续指令利用这个结果决定哪些线程参与操作,走ALU管线
IADD3 2,555,904 三输入整数加法,占12.5 % 地址计算里的加法、循环变量自增,走ALU管线
MOV 1,646,592 搬运操作数,占全部执行指令约8.0 % 本例用于初始化寄存器、给后续指令准备输入
LDS 1,187,840 共享内存读,占全部执行指令约5.8 % 归并中的两条LDS各执行524,288次,共1,048,576次;病态二的两条LDS.128各执行65,536次,共131,072次;收尾读取smem0再执行8,192次,合计1,187,840次。本行按warp级指令计数,访存请求数与wavefront数另行统计
STS 1,114,112 共享内存写,占5.4 % 病态一读回的八个数由八条STS各存一个、各65,536次;部分和算完由第九条STS写回,也是65,536次;归并循环里的那条执行524,288次
FADD 1,048,576 单精度浮点加,占5.1 % 本kernel全部的非融合FP32指令,来历见上面OPT那段
BAR 720,896 block同步指令,占3.5 % 归并循环中的一条执行524,288次,另外三条各执行65,536次。指令次数能认出同步有多频繁,等待有多长还要看Stall Barrier和逐行采样
BRA 589,824 分支跳转,占2.9 % 归并循环中的那条执行524,288次,对应第二章Warp Stall Sampling表最上面那一行;另一条执行65,536次
MUFU 524,288 特殊函数指令,这里是求倒数MUFU.RCP,占2.6 % 它与I2F、F2I一起参与病态三的变量求余展开,这几步走XU单元;求余过程还包含整数乘加等指令
LOP3 524,288 三输入位逻辑运算,一条对三个操作数做任意逻辑组合,占2.6 % 参与求余展开
LEA 524,288 地址计算指令,占2.6 % 归并循环里算共享内存的访存地址
LDG 524,288 全局内存读,占全部执行指令约2.6 % 八条展开的LDG.E各执行65,536次,对应病态一从input搬数的循环。每条指令先按globalIdx < n判断哪些线程需要读取,读取结果随后存入共享内存;非合并访问多出的sector来自这里
I2F 524,288 整数转浮点,占2.6 % 本次编译把变量求余展开成了包含类型转换和求倒数的指令序列,I2F是其中的整数转浮点步骤
F2I 524,288 浮点转整数,占全部执行指令约2.6 % 与I2F整数转浮点、MUFU.RCP求倒数一起参与变量求余的展开。这三类指令都走XU,求余展开的回代部分还包含整数乘法等操作
S2R 131,072 读特殊寄存器,占0.6 % 两条各65,536次,分别读blockIdx和threadIdx,kernel开头算下标用
EXIT 73,728 线程退出指令,占0.4 % 收尾时先让无需写回的线程退出,这条带条件的EXIT按warp计65,536次;每个block剩下的thread 0写回后再退出,又计8,192次,合计73,728次
ULDC 65,536 从常量内存读取数据到warp共用的统一寄存器,占全部执行指令约0.3 % 本例每个warp执行一次,8,192个block × 每block 8个warp = 65,536次。它属于准备常量数据的工作
SHF 65,536 移位运算,占0.3 % 算地址时把threadIdx左移5位,相当于乘32
CS2R 65,536 把特殊寄存器里的常量写进普通寄存器,占0.3 % 这里是把零常量写进寄存器当初始值
STG 8,192 全局内存写,占全部执行指令约0.04 % 本例只有一条STG,每个block由thread 0写回一个float,共执行8,192次。它对应序章if (threadIdx.x == 0)包住的output写回,也就是病态四

IMAD、ISETP、IADD3、MOV四类合计12,271,616条,占59.9 %,主要在算下标、算地址、比较条件和准备操作数。LDS、STS、LDG、STG四类合计2,834,432条,占13.8 %。访存类指令条数占比不高,仍可能制造很多sector、wavefront和等待,这正是本例值得读的地方。这里的59.9 %、13.8 %用全部执行指令数作分母;Compute Workload Analysis的ALU 11.96 %、LSU 16.15 %、XU 8.76 %则用各管线自己的峰值作分母。前者描述指令组成,后者描述管线利用率。21类指令的条数之和等于执行总数;表里的百分比逐项舍入后相加,可能与100 %略有差异。

Instruction Statistics说明本例指令以整数和地址计算为主,访存指令数量相对较少,却能产生大量sector、wavefront和等待。四个病态在不同指令上各有对应证据;FP32 Non-Fused规则给出的2.58 %估算,需要结合代码中的乘加配对条件评估。

接下来三个section展示硬件互联与主机亲和关系。NVLink用于GPU之间的高速直连;NVLink Topology的说明是展示逻辑连接及其收发吞吐。本报告展开后只有一句The system does not have any NVLink connections.,表示没有检测到NVLink连接。

NVLink Tables的说明为:给出详细表格,列出每条NVLink的属性,界面上表格的小标题写的是Logical NVLink Properties;本机没有连接,也就没有属性可列,展开后还是上一节那句话:

NUMA Affinity有实际数据。NUMA是non-uniform memory access,非统一内存访问:主机内存按节点组织,设备访问不同节点的距离和代价可能不同。亲和性说明GPU与哪些逻辑CPU、哪个内存节点关系更近。逻辑CPU是操作系统能够分别调度的处理器编号;启用超线程时,一个物理核心可以对应多个逻辑CPU。ncu在NUMA ID Table中按GPU列出这些关系,一行对应一个GPU。

表里只有GPU 0,即NVIDIA GeForce RTX 3090。NUMA ID by CPU Affinity为0,CPU Affinity为0-31,表示报告列出的亲和逻辑CPU编号是0到31、对应0号节点;NUMA ID by Memory Affinity也为0,表示内存亲和节点同样是0。两列分别描述CPU和内存亲和关系。

这三个section没有给出性能建议。NVLink两节确认没有NVLink连接,NUMA表给出CPU与内存亲和节点;本kernel是否访问主机内存,要看实际流量。第二章Memory Chart的System Memory为0.00 B,才是本次没有记录到主机内存流量的证据。

Launch Statistics

这一节列出kernel的启动配置:grid有多少个block,每个block有多少线程,以及寄存器和共享内存用量。线程、寄存器、共享内存和硬件block数量都有各自的上限;每个block占用多少资源,决定SM能同时驻留多少个block。

基本数据表

ncu说明为:kernel启动配置的汇总。启动配置定义了网格的大小、网格划分成block的方式,以及执行这个kernel需要的GPU资源,选一套高效的启动配置能把设备利用率拉满。

这一节一共15项,界面分左右两列。下表先读左列,从Grid Size到Enabled TPC IDs,再读右列,从Function Cache Configuration到# TPCs,与截图顺序一致。

项 值 说明
Grid Size 8,192 grid中的block总数 2^24个输入,每block负责256 × 8 = 2,048个数,2^24 ÷ 2,048 = 8,192,与序章的启动配置一致
Registers Per Thread 36 register/thread 编译后每个线程使用36个寄存器,硬件分配还要向上取整 每warp需要36 × 32 = 1,152个,按每warp 256个的分配粒度向上取整为1,280个,相当于每线程40个。计算资源能装几个block时,按取整后的分配量计算
Block Size 256 每个block的线程数 256 ÷ 32 = 8个warp,所以每多驻留一个本例的block,就要为8个warp安排位置
Threads 2,097,152 thread 全部线程数,8,192 × 256 = 2^21 224个数摊到221个线程上,每线程8个,搬数循环里那八条LDG.E就是这么来的
Waves Per SM 16.65 以当前配置下整卡能同时驻留的一批block为一波,grid总block数除以这一波的容量,得到整个grid相当于多少波的驻留容量 每SM最多6个block,整卡82 × 6 = 492个;8,192 ÷ 492 ≈ 16.65波。这个数按驻留容量折算,实际执行时有block完成就能补入新block;末尾不足一波时可能出现部分SM先空下来的尾效应
Uses Green Context 0 是否使用CUDA给任务划定部分GPU资源的Green Context机制 0表示本例没有使用
# SMs 82 SM 这块GPU有82个SM 本章所有按SM取平均的算法,分母都是它
Enabled TPC IDs all 本次启动可使用全部TPC,即前面介绍的每两个SM一组的硬件单元,没有被限制到其中一部分
Function Cache Configuration CachePreferNone kernel对缓存与共享内存划分的偏好配置 CachePreferNone表示没有提出特别偏好。本次实际分给每SM的共享内存容量,单独列在Shared Memory Configuration Size中
Static Shared Memory Per Block 0 byte/block 编译期静态申请的共享内存,0 本kernel的共享内存全是运行时动态申请的
Dynamic Shared Memory Per Block 8.19 Kbyte/block 启动时动态申请的共享内存,每block一份 本次由kernel启动的第三个参数指定8,192字节,界面按十进制缩写显示为8.19 Kbyte
Driver Shared Memory Per Block 1.02 Kbyte/block 驱动为每block预留的系统开销,与kernel申请多少无关,Raw页原值1,024字节 容易漏看,算驻留上限时必须加上
Shared Memory Configuration Size 65.54 Kbyte 本次每SM配给共享内存的容量,65,536字节,即64 KiB 界面使用十进制Kbyte,显示为65.54。驻留计算用原始字节数:65,536 ÷ 9,216 ≈ 7.11,可装7个block
Stack Size 1,024 启动时配置的栈大小,Raw页和说明未标出单位,这里沿用界面值 本报告local load/store指令数都是0
# TPCs 41 TPC是硬件里2个SM一组的单位,82 = 41 × 2 硬件信息,随设备而定,不随kernel变

这15个值给出了本次资源用量:8,192个block,每block 256个线程;每线程使用36个寄存器,分配时按每线程40个所在的档位计算;每block共享内存为8,192 + 1,024 = 9,216字节。把这些用量分别与每SM的资源总量相比,就能算出同时驻留的block上限。

Occupancy

这一节根据kernel的资源用量计算每SM的理论驻留上限,并与实测驻留数量比较。本例中,硬件最多容纳48个warp,若资源允许同时驻留6个本例的block,就是6 × 8 = 48个warp。驻留warp数除以48,得到的比例就是occupancy。它描述驻留数量;warp即使已经驻留,也可能正在等待,无法发射下一条指令。

基本数据表

ncu说明为:occupancy是每个SM的活跃warp数与其最大可驻留warp数之比。高occupancy不一定带来高性能;较低的occupancy会减少可用于隐藏延迟的warp数量。理论值与实测值差得很大时,应检查负载是否均衡。这里的"活跃"仍然是驻留,正在等待的warp也计入其中。

这一节共有8项,界面左列四项描述occupancy,右列四项分别给出资源允许的block数量上限,下表先左列后右列。

项 值 说明
Theoretical Occupancy 100 % 按启动配置和资源限制算出的每SM最大驻留warp数,除以硬件的48个warp上限,再乘100 %,得到本次配置在资源上允许的最大warp驻留比例 本例允许48个warp,48 ÷ 48 × 100 % = 100 %,表示本次配置在资源上允许满驻,实测值见Achieved Occupancy
Theoretical Active Warps per SM 48 warp 按本次资源用量计算,每SM理论最多驻留48个warp 各资源允许的block数取最小值,再乘每block的8个warp,得到这48个
Achieved Occupancy 95.41 % 实测每SM平均活跃warp数除以48,再乘100 %,得到实际平均驻留warp数占硬件上限的比例;这里的活跃仍表示驻留 45.795337 ÷ 48 × 100 % ≈ 95.406952 %,显示95.41 %,与100 %相差4.59个百分点;起步、block换入和收尾等阶段都可能出现暂未满驻的情况
Achieved Active Warps Per SM 45.80 warp 每SM在自身活跃周期里平均驻留45.80个warp Scheduler Statistics按每调度器统计,使用原值11.421472 × 4 ≈ 45.686,与SM层的45.795337相差约0.24 %。两个层级的实测计数略有差异,这里共同说明驻留接近48个的上限
Block Limit Registers 6 block 仅考虑寄存器容量时,每SM最多能驻留的block数 每warp分配1,280个,每block 8个warp,共10,240个;每SM有65,536个寄存器,65,536 ÷ 10,240 = 6.4,向下取整为6个block
Block Limit Shared Mem 7 block 共享内存给的驻留上限 每block 9,216字节,SM配了65,536字节,65,536 ÷ 9,216得7.11,取整7
Block Limit Warps 6 block warp数给的驻留上限 SM最多48个warp,每block 8个,48 ÷ 8 = 6
Block Limit SM 16 block 每SM硬件最多允许驻留16个block 本例还受寄存器和warp数量限制,只能驻留6个,达不到16个。资源上限中必须取最小值

四个block上限取最小值:寄存器允许6个、共享内存允许7个、warp数量允许6个、SM硬件允许16个,因此本例理论上最多驻留6个block,6 × 8 = 48个warp,理论occupancy为100 %。运行中旧block完成、新block补入,起步和收尾阶段也不一定满驻,所以实测为95.41 %。各SM的实测值从94.570542 %到96.292889 %,相差约1.7个百分点,说明驻留水平比较接近。

Impact of Varying 六图

展开section,六张Impact of Varying图分成上下两排,每排三张。横轴依次是每线程寄存器数、block线程数、每block共享内存用量;上排纵轴是occupancy百分比,下排是每SM驻留warp数,两排展示同一批理论结果。计算时固定其它条件,只改变横轴上的一个参数,按各项资源上限算出可驻留block数,再换成warp数和occupancy。圆点标记本kernel当前参数对应的理论结果。曲线达到100 %表示资源允许满驻;参数对运行时间的影响还要另行测量。

第一张横轴是Registers Per Thread,范围为0到256,每8个寄存器一格。按本例block大小,可驻留block数依次从6降到5、4、3、2、1,对应occupancy约100 %、83 %、67 %、50 %、33 %、17 %,所以曲线呈台阶状。寄存器按每warp 256个的粒度分配。本例每线程使用36个,一个warp需要36 × 32 = 1,152个,向上取整到1,280个,相当于每线程40个。使用量不超过40时仍在这一档;增到41时,分配量跳到每线程48个,每SM可驻留block数从6降到5。当前圆点位于36,仍在100 %平台上,使用量还能增加4个而不跳档。

第二张横轴是Block Size,范围为0到1,024,每32个线程一格。block很小时,每个block只有少数warp,而固定的共享内存用量最多允许7个block,所以32线程时只能驻留7个warp,7 ÷ 48 ≈ 14.6 %。线程数增多后,曲线在256、384、512、768等位置达到100 %,中间出现锯齿。对比192、224、256这三处:192线程是6个warp,装满48个warp需要8个block,但共享内存只允许7个,所以只能驻留7 × 6 = 42个warp,即87.5 %;224线程是7个warp,48 ÷ 7向下取整为6个block,也只能驻留42个warp;256线程是8个warp,6个block正好48个。锯齿来自资源限制与整块block必须一起驻留的约束,当前256的圆点位于满驻位置。

第三张横轴是Shared Memory Per Block,范围为0到101,888字节。每block用量增加,SM能容纳的block就逐档减少,曲线因此往下走台阶。本次每SM配置65,536字节共享内存,粗算能容纳6个block的分界为65,536 ÷ 6 ≈ 10,922字节;实际还要考虑分配粒度。当前圆点为每block 9,216字节,仍在100 %平台上。曲线在49,152字节附近降到0,对应本次配置采用的默认单block 48 KiB上限。要申请更大的单block份额,需要程序显式启用更大共享内存用量。每SM总容量限制同时能装几个block,单block上限限制一个block本身能否按当前配置启动,两者要分开看。

下排三张图的标题与横轴对应上排,纵轴改为每SM驻留warp数。第一、三张标0、20、40、60、80,第二张标0、12、24、36、48;其中48个warp都对应100 % occupancy。寄存器图中上排的100 %、83 %、67 %、50 %、33 %、17 %,换到下排就是48、40、32、24、16、8个warp。

三张图的圆点都压在满驻那一线上,横坐标与上排一一对应:36个寄存器、256、9,216字节,纵坐标都是48个warp。

Occupancy说明本例的资源用量允许满驻:寄存器和warp数量都把上限限制在6个block,正好48个warp;理论值100 %,实测95.41 %。这与Scheduler Statistics的结论一致,应优先解决驻留warp的等待。

GPU and Memory Workload Distribution

这一节比较同类硬件单元之间的活跃周期,查看工作是否集中在少数单元上。例如比较82个SM的最小值和最大值,能看出各SM有warp驻留的时间是否接近;L2和显存也分别在各自同类单元之间比较。SM、L2、DRAM分别使用各自的时钟。

基本数据表

ncu说明为:分析workload在各硬件单元上的分布。本报告列出SM、SMSP、L1、L2、DRAM五类单元的活跃周期,用来比较同类单元之间的活动是否均衡。

说明下方左右两列各五项,单位都是cycle。名称带Average的是同类单元的平均活跃周期数,带Total的是同类单元的流逝周期总数。活跃周期只计入该单元满足活动条件的周期,流逝周期则包含空闲时段;两者还一个取平均、一个取总和。所以下表按界面先左列后右列读,比较时必须把同一类单元、同一种周期统计配起来。

项 值 说明
Average SM Active Cycles 437,992.54 cycle 把82个SM各自有warp驻留的时钟周期数相加,再除以82,得到每SM平均有多少周期保持warp驻留 平均437,992.54周期,包含warp等待期间。Compute Workload Analysis中名称带Active的两个IPC指标用它作分母
Average L2 Active Cycles 427,849.06 cycle 把各L2 slice的活跃周期数相加,再除以slice数量,得到每个L2 slice平均活跃多少周期;周期属于L2自身时钟 本例平均427,849.06周期。与同类L2的流逝周期相比,活跃比例约98.45 %
Average DRAM Active Cycles 720,533.33 cycle 把各显存通道的活跃周期数相加,再除以通道数量,得到每个显存通道平均活跃多少周期;周期属于显存侧时钟 平均720,533.33周期。显存时钟约为SM的七倍,活跃比例要用显存自己的活跃周期数除以流逝周期数
Total L1 Elapsed Cycles 36,299,778 cycle 全部L1TEX单元在kernel期间流逝周期数的总和,包括各单元没有活动的周期 本报告与Total SM Elapsed Cycles同为36,299,778,但两行仍分别描述L1TEX和SM
Total SMSP Elapsed Cycles 145,199,112 cycle 328个SMSP在kernel期间流逝周期数的总和 145,199,112 ÷ 328 ≈ 442,680.22周期,是每SMSP的平均流逝周期;它与SM层的平均值相同,因为本卡每SM有4个SMSP,二者使用同一时钟
Average L1 Active Cycles 437,992.54 cycle 全部L1TEX单元的活跃周期总数除以单元数量,得到每个L1TEX单元平均活跃多少周期 本报告与SM层同为437,992.54周期。它记录L1TEX这一层的活动周期
Average SMSP Active Cycles 438,043.79 cycle 全部SMSP各自有warp驻留的活跃周期总数,除以328个SMSP,得到每SMSP平均有多少周期保持warp驻留 平均438,043.79周期,比SM层的平均值高约0.0117 %。计算SMSP层的指标沿用本行实测值
Total SM Elapsed Cycles 36,299,778 cycle 82个SM在kernel期间流逝周期数的总和,包括没有warp驻留的周期 36,299,778 ÷ 82 ≈ 442,680.22周期,是前面计算Executed Ipc Elapsed用的平均值;活跃总数35,915,388除以本行总数约为0.9894
Total L2 Elapsed Cycles 20,860,896 cycle 全部L2 slice在kernel期间流逝周期数的总和 L2活跃总数20,536,755 ÷ 流逝总数20,860,896 ≈ 98.45 %,两份总数必须都来自L2这一层
Total DRAM Elapsed Cycles 37,220,352 cycle 全部显存通道在kernel期间流逝周期数的总和 37,220,352 ÷ 12 = 每通道3,101,696周期;显存活跃总数8,646,400除以本行总数约为23.23 %

Workload Distribution 分布表

展开后的表格叫Workload Distribution,一行对应一类硬件单元。Average是这一类单元的平均活跃周期,Min与Max是其中最小、最大的活跃周期,Sum是全部同类单元的活跃周期之和;四列用的都是这一行硬件单元自身的时钟周期。

项 Average Min Max Sum
SM Active Cycles 437,992.54 435,302 441,248 35,915,388
SMSP Active Cycles 438,043.79 435,339 441,146 143,678,364
L1 Active Cycles 437,992.54 435,302 441,248 35,915,388
L2 Active Cycles 427,849.06 427,556 429,493 20,536,755
DRAM Active Cycles 720,533.33 719,184 721,712 8,646,400

用Sum除以Average,可以反推参与统计的单元数量:SM为35,915,388 ÷ 437,992.54 ≈ 82,SMSP为143,678,364 ÷ 438,043.79 ≈ 328,L2为20,536,755 ÷ 427,849.06 ≈ 48个slice,DRAM为8,646,400 ÷ 720,533.33 ≈ 12个显存通道。slice是第二章介绍过的L2分区,各管一部分地址。再用"Max − Min"除以Average比较同类单元间的差距。SM为(441,248 − 435,302) ÷ 437,992.54 ≈ 1.36 %;L2约0.45 %,显存通道约0.35 %。这些结果说明同类单元的活跃时长比较接近,没有出现少数单元长期活跃、其它单元大部分时间空闲的明显失衡。

前面Instruction Statistics中,各调度器执行指令数的最大值与最小值之差约为平均值的6.0 %,比SM活跃周期的1.36 %差距更大。两者数的对象不同:SM只要还有warp驻留,活跃周期就会增加,warp等待期间也算;指令计数则只记录实际执行的指令。

本报告L1这一行的四个数都与SM相同,沿用各自的实测值即可。DRAM的平均活跃周期720,533.33大于SM的437,992.54,则与两级时钟频率和活跃比例都有关。报告DRAM Frequency为9.74 GHz,SM Frequency为1.39 GHz,约相差七倍;用流逝周期核对,37,220,352 ÷ 12 = 每显存通道3,101,696周期,再除以SM平均流逝442,680.22周期,得到约7.01。要比较各层级在自己的运行窗口里有多少周期活跃,就分别用同类单元的活跃周期总数除以流逝周期总数。DRAM为8,646,400 ÷ 37,220,352 ≈ 23.23 %,与第二章DRAM Throughput数值一致;L2为20,536,755 ÷ 20,860,896 ≈ 98.45 %,说明多数L2周期都有活动。L2的98.45 %量的是活跃周期占比,第二章Throughput的80.44 %量的是各通路相对自身处理峰值的利用程度。SM与SMSP平均活跃周期还相差约0.0117 %,两个层级分别按各自实测值计算。

GPU and Memory Workload Distribution补上了同类单元之间的比较:SM活跃周期最大值与最小值之差约为平均值的1.36 %,L2和显存通道的差距更小。结合各调度器的指令计数,本例在SM和调度器之间没有显示明显的整体负载失衡;SM持续有warp驻留但发射率低,主要等待仍要回到同步与相关指令队列分析。

这一章到这里就结束了。第二章讲三个重点section,本章补齐其余11个,Details页的14个section已经读完。PM Sampling展示运行过程,Compute Workload Analysis与Scheduler Statistics确认驻留充足但发射率低,Warp State Statistics把主要等待指向barrier和MIO队列。Instruction Statistics再把活动接回实际指令,互联与NUMA表交代硬件关系,Launch Statistics、Occupancy和Workload Distribution则分别核对资源配置、驻留上限和工作分配。

把这一章和第二章连起来,四个病态的证据就串起来了:非合并全局读让读取请求涉及的sector数量达到理想合并访问的8倍;共享内存冲突集中在两条LDS.128上,多出524,288个wavefront;树形归并每轮同步、越来越多线程因条件不满足而跳过加法,与Barrier停顿和12.45 %的有效线程比例相对应;最后8,192条STG则对应每个block只由一个线程写回结果。

这些证据共同说明,本例应优先减少等待,让已经驻留的warp更早具备发射条件。汇总指标给方向,逐行计数和采样把问题落回代码;规则的预计收益仍需经过实际修改和测量验证。下一章离开Details页,继续阅读其它页面。

相关推荐
Starry-sky(jing)3 天前
onnxruntime 安装后 GPU 没加速?3 条命令确认它跑在 CPU 还是 GPU
python·gpu·cuda·onnxruntime·推理加速
论文复现现场10 天前
LAMMPS 用 RTX 5090 能跑多大?32GB 显存、CUDA 编译与规模验证
cuda·分子动力学·lammps·rtx5090
EatFan10 天前
从 CUDA 到昇腾:一张对照表拆解 DeepSeek 最新开源组件(TileLang / DeepGEMM / DeepEP / TileKernels)
开源·cuda·deepseek·deepgemm·tilelang·华为昇腾
论文复现现场12 天前
RTX 3090 24GB 适合科研吗?单卡论文复现、PyTorch 显存检查与 OOM 排错
人工智能·pytorch·python·深度学习·cuda·rtx3090
论文复现现场14 天前
RTX 5090 32GB 适合科研计算吗?单卡训练、推理、论文复现与 OOM 判断方法
pytorch·深度学习·cuda·rtx5090
论文复现现场14 天前
论文复现看到“RTX 3090 or higher”:显存、CUDA、batch size 与 OOM 怎么判断?
开发语言·pytorch·batch·cuda·rtx3090
_nibel14 天前
第二章:Details 重点数据细读 ⭐教你读懂 Nsight Compute 报告 系列合集⭐
cuda·ncu·nsight compute
论文复现现场24 天前
MiniCPM-o 4.5 需要多少显存?RTX 3090 24GB 的 BF16、AWQ、GGUF 部署边界与验收方法
cuda·多模态大模型·显存优化·rtx3090·minicpm-o
qq_1998868724 天前
第8板块·第2节:统一内存的高级特性与性能调优
c++·人工智能·gpu算力·cuda