ON-CPU分析方法-- intel&amd topdown 与perf简介
文章目录
topdown
Intel使用PMU-TOOLS
AMD?
现代的CPU为了能够尽可能的提高IPC(instruction per cycle),采取了诸多技术:
- 乱序执行
- 分支预测
- 超标量
- 硬件预取
这些技术非常好的提高了CPU的理论上限,但是也增加了分析微架构数据的难度。
Intel IceLake的微架构图
顶层划分
在Top-Down最开始的时候,我们需要考虑如何做最顶层的划分。Top-Down方法按照如下的方式对微指令做划分:
对于一个已经被发射的微指令,那么它最终只有两个结果:Retired或者Cancelled。
因此,这条指令要么被计入到Retiring阶段或者Bad Speculation阶段。
反过来,对于一个还没有分配的微指令,如果出现了Backend Stall,后端由于一些原因无法处理相关的指令,则计入到Backend Bound;反之则将其计入到Frontend Bound。
Frontend Bound
前端主要承担以下工作:
- 基于分支预测取出下一条地址
- 取出cache line解析指令
- 将指令解析成微指令
当没有指令从前端传递到后端时,这样的循环被标记为前端绑定。理想前端每个周期可以发出 4 个微操作。此类未使用的插槽示例是由于指令缓存未命中instruction cache misses而导致的停顿。
对于 AMD 处理器,前端绑定类别最准确的等效项是 DECODER_EMPTY 性能计数器。需要注意的是 DECODER_EMPTY 不考虑后端是否停止。
这是连接前端和后端的单元。当它为空时,意味着进程的执行受到前端的限制——这些可能是等待错过指令高速缓存的指令获取的周期。
对于 Intel 处理器,用于计算前端绑定类别的IDQ_UOPS_NOT_DELIVERED性能计数器在机器后端未停止时在内部仅计算从前端到资源分配表的未交付 UOPS 数量。因此,不需要其他数学运算
架构 | performance counter | difference |
---|---|---|
Intel | IDQ_UOPS_NOT_DELIVERED | 仅在后端未停止时计算从前端到资源分配表的未交付 UOPS 数量 |
AMD | DECODER_EMPTY | 不考虑后端是否停止 |
前端绑定类别进一步分为指令缓存未命中Instruction Cache Misses和指令转换后备缓冲区未命中Instruction Translation Lookaside Buffer(ITLB) Misses。
这两个中的第一个计算指令缓存中未完成的请求数。这些可以通过使用性能计数器来定义INSTRUCTION_FETCH_STALL。它有效地计算了指令获取器为内核停止的周期数。
AMD处理器只计算ITLB未命中的次数,而不是丢失的周期数,未命中的固定成本定义为 7 个周期的值。
此成本稍后乘以L1_ITLB_MISS_AND_L2_ITLB_MISS的两个性能计数器的数量。
Frontend Bound | performance counter | stall reason |
---|---|---|
Instruction Cache Misses | DECODER_EMPTY | 指令缓存未完成 |
Instruction Translation Lookaside Buffer(ITLB) Misses | L1_ITLB_MISS_AND_L2_ITLB_MISS | 指令转换后备缓冲区未命中(请求的地址不在 TLB 中,查找页表继续进行Page Walk) |
Bad Speculation category
Bad Speculation category计算由于错误推测而丢失的槽数。这些主要是由错误预测的分支指令造成的。最初,该指标被定义为所有发出的微操作数量减去最终退出的微操作数量=Bad Speculation category。
AMD仅提供有关事件数量的信息,而不提供有关事件使用的周期的信息,因此在此指标中还引入了这些事件的成本。这是继 ITLB 未命中之后的第二个指标,也是 AMD 自上而下表征中使用额外成本值的最后一个指标。该成本的具体值取决于给定的处理器,使用 12 个周期的值。然而,这两个指标的绝对值相对较低,因此固定成本带来的误差相对较低。
架构 | performance counter |
---|---|
Intel | (UOPS_ISSUED.ANY − UOPS_RETIRED.RETIRE_SLOTS) + Pipeline_Width ∗INT_MISC.RECOVERY_CYCLES |
AMD | AMD 公式考虑了管道的长度。这个数字近似于错误预测分支的整个执行的成本(RETIRED_MISPREDICTED_BRANCH_INSTRUCTIONS + RETIRED_TAKEN_BRANCH_INSTRUCTIONS_MISPREDICTED + RETIRED_INDIRECT_BRANCHES_MISPREDICTED) ∗ (Branch misprediction cost)/UNHALTED_REFERENCE_CYCLES |
Retiring category
架构 | performance counter |
---|---|
Intel | UOPS_RETIRED.RETIRE_SLOTS |
AMD | RETIRED UOPS |
Backend Bound category
指令从前端分配,后端负责监视微操作数据操作数何时可用,并在可用的执行单元中执行微操作。Backend Bound 反映了**当后端耗尽某些资源(例如加载缓冲区)**时,在管道上未交付微操作的情况。
Backend Bound 类别的计算方式为 100% 减去所有其他三个指标的总和,即层次结构的顶部。
Backend Bound | performance counter | stall reason |
---|---|---|
Memory Bound | Intel:CYCLE_ACTIVITY.STALLS_LDM_PENDING AMD:未命中地址缓冲区 (MAB):MAB_WAIT | memory subsystem:cache misses and memory accesses. |
Core Bound | Backend Bound减去Memory Bound | non-optimal use of the available execution units in the CPU in each cycle |
leading loads model
对所有内存访问进行计数并将其乘以某个预定义成本是不够的,因为处理器可以通过重叠多个缓存未命中来利用内存级并行性 (MLP)。最后,DRAM 访问延迟随访问模式的不同而变化,因此很难仅根据访问计数来预测等待内存所花费的时间。
尽管许多内存访问可能未完成,但只有一个可以使管道停顿。因此,在核心高速缓存的最后一级中未命中的第一个非推测性负载被视为leading loads。内存时间计算为未命中和数据返回到处理器之间的时间。该负载返回之前的所有其他未命中都不是领先负载,因此会被忽略。
在 AMD 处理器上,引入了未命中地址缓冲区 (MAB),它是一种跟踪未完成的高速缓存未命中的结构。每次缓存未命中时,都会使用其中一个条目来保存内存请求。
当前未保存请求的最高优先级条目始终用于保存最新的内存请求。因此,具有最高优先级的条目保存有关领先内存请求的信息。此外,可以使用指定的硬件性能计数器MAB_WAIT直接测量每个条目在周期中占用的时间。
AMD 引入了一种新的分析技术,提供精确的配置文档信息 - 基于指令的采样 (IBS) 。
传统的性能计数器采样,称为基于事件的采样 (EBS) ,提供有关预配置事件的数量。
Perf
常见用法
- Performance Counter : 计数指定的事件类型(cycles、 instruction)
运行perf record命令来收集性能数据:
perf record -e cycles <your_program>
运行perf report命令来查看性能数据报告:
perf report
- Event Sampling :以一定的频率对指定的事件进行采样,获取事件发生时的上下文信息,以及调用链数据。这样可以较为准确地了解事件的发生频率、发生位置和调用链的关系,帮助分析程序的热点和性能瓶颈。
获取进程的PID(进程ID)。
运行perf record命令采样指定的事件,并指定进程ID和调用链选项:
perf record -e <event> -p <pid> -g
运行perf report命令来查看采样数据报告:
perf report
- Call Graph :perf工具可以采集程序的调用链数据,生成函数调用关系图,展示函数之间的调用关系和调用次数。这对于分析程序的调用层次、函数之间的耗时以及优化热点函数等非常有用。
编译C++程序,并确保包含调试符号信息(例如使用-g选项)。
运行perf record命令来采集调用链数据,并指定调用链类型为DWARF:
perf record -g --call-graph dwarf <your_program>
运行perf report命令来查看调用图报告:
perf r
常见命令
- perf list :列出所有能够出发Perf采样点的事件
- perf trace :类似于strace跟踪进程系统调用
- perf record :类似于strace跟踪进程系统调用,可以指定采样率、事件类型和监测范围等参数
# -p $pid 记录进程pid的events
# -a 采集所有cpu上的events
# -e $event 指定PMU(处理器监控单元)event,默认是cycles:app(cpu周期数)
# -g 启动堆栈/栈回溯功能
# -F $freq 采用频率
# -o $path 指定采样文件输出路径
- perf report :对perf record采样的数据进行分析,可视化显示
- perf top :实时查看当前系统中的性能热点函数和指令 eg.:
perf top --call-graph fractal
- perf stat :可以获取到更底层的性能数据,以便分析和优化。
- perf annotate :可以将性能数据与源代码进行关联,以便更深入地分析和理解性能瓶颈所在。perf annotate命令将在源代码中显示函数的注释和性能数据,帮助定位到具体的代码行,并查看相关的性能指标。
- 结合调用图:
使用-g选项运行perf record命令,并在perf report中查看调用图
- 结合事件采样:
在perf record命令中使用-c选项指定采样率,并在perf report中查看采样数据,可以获得更细粒度的性能分析结果
- perf script :将性能数据转换为可读性更强的脚本输出,以便进一步处理和分析。可以将perf script的输出导入到其他工具或脚本中进行更深入的数据处理和可视化
结合其他工具:
-
Flame Graphs :成火焰图的工具通常包括FlameGraph和火焰图生成脚本。可以将perf工具的输出数据作为输入,然后使用火焰图工具生成具有层级结构的火焰图
-
System Tracing:eBPF :eBPF可以通过在内核中插入自定义的代码,捕获和分析系统的各种事件和指标。
-
Dynamic Tracing:DTrace
aphs** :成火焰图的工具通常包括FlameGraph和火焰图生成脚本。可以将perf工具的输出数据作为输入,然后使用火焰图工具生成具有层级结构的火焰图 -
System Tracing:eBPF :eBPF可以通过在内核中插入自定义的代码,捕获和分析系统的各种事件和指标。
-
Dynamic Tracing:DTrace
-
topdown