CPU性能优化--基于处理器事件的采样

基于处理器事件的采样processor event based sampling PEBS 是CPU的另一种非常有用的特性,PEBS被用来在每个采样点获取更多的补充数据。在Intel处理器中,PEBS是在NetBrust微架构开始i引入的,在AMD处理器中,类似的特性叫基于指令的采样IBS。

这些补充数据有定义好的格式,为PEBS配置性能计数器之后,处理器会保存PEBS缓冲区的内容,并将之转存到内存中。记录的信息包括处理器的架构状态,例如,通用的寄存器,EAX, EBX, ESP等,指令指针寄存器EIP和标志寄存器EFLAGS 等的状态,

用户可以通过dmesg命令来检查PEBS是否启用。

字节偏移 字段 字节偏移 字段

EFLAGS R11

EIP R12

RAX R13

EBX R14

ECX R15

EDX

ESI

EDI

EBP

ESP

linux perf工具没像处理LBR那样把原始的PEBS内容导出来,它基于具体需要处理PEBS记录并只导出部分数据。所以,不可能通过linux perf工具导出原始PEBS数据。linux perf工具只提供一些从原始采样数据处理后的PEBS数据,可以通过命令perf report -D获得。要获得原始PEBS记录,可以使用pebs-grabber 工具。

6.3.1 精准事件

当出现溢出导致的中断时,处理器需要一定的时间来停止执行并标记触发溢出的指令。这对现代复杂的乱序执行CPU架构来说,实现起来非常困难。

引入滑动概念,被定义为触发性能事件的IP与标记事件的IP在PEBS记录的IP字段间的距离。滑动使得寻找导致性能问题的指令变得困难,实际上会造成性能问题。想象一个缓存未命中次数很多的程序,热点汇编代码如下load1,load2,load3 性能剖析工具将load3识别为导致高缓存未命中的指令。然而实际上load1才是,通常,这会给新手带来很多困惑,感兴趣的读者可以在intel Developer Zone website找到这类问题潜在的原因的更多信息。

滑动的问题通过让处理器自身记录PEBS记录中的指令地址得到了缓解。PEBS记录中EventingIP字段表示的就是导致性能事件的指令,需要硬件的支持,并且通过只支持一部分性能事件,这样的事件被称为精准事件。具体微架构的精准事件详见,下面列出了Skylake 微架构的精确事件。

INST_RETIRED

OTHER_ASSISTS

BR_INST_RETIRED

BR_MISP_RETIRED

FRONTEND_RETIRED

HLE_RETIRED

RTM_RETIRED

MEM_INST_RETIRED

MEM_LOAD_RETIRED

MEM_LOAD_L3_HIT_RETIRED

TMA分析方法严重依赖精准事件来定位低效率执行代码的具体位置。

easyperf 博客的一篇文章介绍了使用精准事件缓解滑动的例子。linux perf工具的用户需要在事件后面增加ppp后缀来启动精准标注。

perf record -e cpu/event=0xd1

6.3.2 降低采样开销

频繁产生中断并让分析工具采集被中断服务过程中的程序状态,都需要与操作系统交互,这会消化非常多系统资源。这也是为何有些硬件允许无中断的自动对特定的缓冲区采样多次。只有当特定的缓冲区满了,处理器才会发起中断把缓冲区内容刷新到内存中。这种方式的开销相比传统的基于中断的采样开销要低。

为PEBS配置性能计数器后,计数器的溢出条件会支撑PEBS机制,对溢出后的事件,处理器会生成PEBS事件。在PEBS事件中,处理器会把PEBS记录存储到PEBS缓冲区,然后清理计数器溢出状态并恢复到初始值。如果缓冲区满了,CPU将发起一次中断

注意,PEBS缓冲区位于主存内,大小可以设置,性能分析工具的工作时分配和配置内存区域,供CPU导出PEBS记录。

6.3.3 分析内存访问

内存访问时很多应用程序性能的关键因素,有了PEBS,就有可能收集程序中的内存访问相关的详细信息,数据地址剖析可以实现这个功能。为了提供被采样加载和存储指令的更多信息,利用了PEBS特性中的如下字段,

数据线性地址0x98

数据源编码0xa0

时延值 0xA8

如果性能事件支持数据线性地址功能并且启用了该功能,CPU会导出被采样内存访问的地址和时延。请注意,这个功能不会记录所有的存储和加载指令,否则会开销非常大。所以,它只是对内存访问进行采样,例如,大概只会分析1000次访问中的一次,你可以根据需要设置每秒的采样次数。

PEBS扩展的重要使用场景之一的就是检测真伪共享,linux perf 工具严重依赖DLA数据来寻找有争议,可能导致真伪共享内存访问,

此外有了数据地址剖析工具的帮助,用户可以获得程序中内存访问的一般统计信息:

从上面的输出,我们可以看到程序的加载指令有8%通过L1缓存实现,15%通过 DRAM实现。

相关推荐
花椒技术7 小时前
直播间常驻子应用加载优化实践:从 1550ms 到 890ms
性能优化·直播·前端工程化
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
你听得到115 天前
用户说 App 卡,但说不清在哪?我把 Flutter 监控 SDK 升级成了链路观测工作台
前端·flutter·性能优化
亲亲小宝宝鸭8 天前
前端性能监控:web-vitals
前端·性能优化·监控
TrisighT11 天前
Electron 跑在鸿蒙 PC 上,单窗口和多窗口内存差 800MB?我抓了 5 组数据
性能优化·electron·harmonyos
jump_jump15 天前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
小小工匠16 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
大鱼>16 天前
地平线BPU部署实战:YOLOv8在J5/X3上的算法适配与性能优化
算法·yolo·性能优化
醉颜凉16 天前
Elasticsearch高性能优化:Bulk API大规模数据导入性能调优全攻略
elasticsearch·性能优化·jenkins
隔窗听雨眠16 天前
C语言函数递归从入门到精通(下):性能优化与工程实践
c语言·算法·性能优化