Linux性能分析工具-perf并生成火焰图

1 简介

perf 是一个非常实用且深入的性能分析工具,适用于从底层硬件交互到上层应用程序逻辑的全方位性能剖析。

perf 工具的设计目的是为了帮助开发者和系统管理员分析应用程序以及内核本身的性能,寻找潜在的性能瓶颈,并据此进行针对性的优化。

perf 主要特性包括以下几个方面:

1、函数级和指令级热点分析:

perf 可以通过采样分析,精确到函数级别或甚至指令级别来发现CPU占用率高的热点代码段。

2、性能计数器:

利用Linux内核的perf_events子系统,它能够监控和记录各种硬件事件,如CPU cycles、指令执行、缓存未命中的次数、分支预测失败等,还可以监控软件事件,如系统调用、页错误等。

3、CPU性能监测:

监控各个进程或线程的CPU使用率,识别哪些函数或代码路径是CPU消耗大户。

4、缓存行为分析:

分析内存访问模式,包括L1、L2、L3缓存的命中和未命中的情况,有助于优化内存访问策略。

5、系统调用和事件跟踪:

记录和分析程序运行过程中的系统调用,以及相关的事件流。

6、调用图生成:

创建函数调用图,可视化地展示函数间的调用关系,方便理解程序执行流程及其开销。

7、动态跟踪:

支持动态跟踪技术,可以实时捕获和分析程序运行时的行为。

8、跨进程和跨线程分析:

不仅能分析单个进程的性能,还能处理多进程间的数据关联,提供全面的系统级视图。

9、兼容性:

由于其直接集成在内核中,perf 具备良好的硬件兼容性,能够充分利用不同架构CPU的性能监控单元(PMU)。

2 工作原理

perf 工作原理的核心在于对Linux内核性能事件的支持和利用。以下是perf工具的基本工作原理概述:

1、硬件事件(Hardware Events):

perf 能够利用CPU内部的Performance Monitoring Units (PMUs)。PMUs是一组硬件寄存器,能够追踪和记录特定的微架构事件,如指令执行次数、缓存未命中、分支预测失败等。通过编程这些寄存器,perf可以设置特定事件的阈值,在达到一定次数后触发中断,收集此时的上下文信息,如CPU寄存器状态、PC指针(指向当前正在执行的指令地址)、进程ID、线程ID等。

2、软件事件(Software Events):

对于软件级别的事件,perf 利用内核中的计数器和tracepoints。内核计数器可以追踪系统级事件,如上下文切换、页错误、任务调度等。Tracepoints是内核中预定义的静态探针点,允许在特定位置插入额外的追踪代码,以便在关键内核操作发生时收集信息。

3、采样(Sampling):

perf 工具主要采用采样法进行性能分析。它可以根据设置的事件类型和频率定期或者在满足条件时触发采样,每次采样都会记录下当时CPU正在执行的指令或函数信息。通过大量的采样数据,可以得出热点函数或代码段,从而找出可能导致性能瓶颈的部分。

4、记录与报告(Recording and Reporting):

perf 可以实时或事后分析记录的数据。它可以创建统计数据报告,展示CPU使用率、上下文切换、内存访问统计等信息,还可以生成调用图(火焰图)以直观地显示函数调用层级和耗时情况。

5、跟踪(Tracing):

除了采样之外,perf 还提供了更复杂的跟踪能力,允许持续记录系统的活动,包括系统调用、函数入口退出、irq处理等,这对于分析系统行为和优化系统响应时间非常有用。

总之,perf 集成了多种性能分析手段,通过对硬件和软件事件的监控,结合采样和跟踪技术,实现了对Linux系统和应用程序的深度性能剖析。

3 perf安装

sudo apt install linux-tools-common

sudo apt install linux-tools-5.15.0-101-generic

4 perf相关命令

最常用的perf命令及其功能理解如下:

   annotate        读取perf.data(由perf record生成)并结合源代码展示详细的性能分析结果,包括CPU执行热点、函数调用栈等信息。
   archive         使用perf.data文件中找到的带构建标识符的对象文件创建归档文件,便于后续对这些对象文件进行调试或者分析
   bench           通用基准测试套件框架,允许用户定义和运行多种基准测试场景,用于评估系统在不同条件下的性能表现。
   buildid-cache   管理perf用来关联二进制文件与其符号表信息的构建ID缓存,可以添加、删除或查看缓存内容。
   buildid-list    列出perf.data文件中的构建标识符
   c2c             共享数据C2C/HITM分析器:针对共享数据缓存一致性(Cache-to-Cache)和高速缓存命中(Hit in Translation)进行分析的工具,帮助诊断多核心间的缓存交互问题。
   config          读取和设置perf配置文件中的变量,用于个性化perf的行为或指定默认参数。
   daemon          在后台运行记录会话,适用于长期监控系统的性能情况。
   data            提供一系列与perf.data文件相关联的操作,如检查文件内容、转换格式等。
   diff            比较两个或多个perf.data文件,分析并展示它们之间的性能差异,常用于对比不同条件下系统的性能变化。
   evlist          列出perf.data文件中的事件名称,这些事件可能包括硬件性能计数器事件、软件事件、tracepoint事件等。
   ftrace          内核ftrace功能的简单包装器,允许实时追踪和分析内核函数调用路径。
   inject          过滤器,用于向事件流中添加附加信息,增强事件的数据量和丰富度,便于更加深入地分析性能问题
   iostat          显示I/O性能指标,如块设备读写速率、I/O操作延时等
   kallsyms        在运行中的内核中搜索符号
   kmem            用于跟踪/测量内核内存属性的工具,如分配、释放、碎片率等
   kvm             用于跟踪/测量KVM虚拟机操作系统性能的工具
   list            列出所有符号事件类型
   lock            分析系统中锁的获取和释放行为,包括锁竞争、等待时间等,有助于发现潜在的并发瓶颈
   mem             对内存访问模式进行分析,包括页错误、缓存未命中的次数、内存带宽使用等。
   record          执行命令并将其性能概要记录到perf.data中
   report          读取perf.data(由perf record创建)并显示概要
   sched           用于跟踪/测量调度器属性(延迟)的工具,从而优化进程调度策略。
   script          读取perf.data(由perf record创建)并显示跟踪输出
   stat            执行命令并收集性能计数器统计信息
   test            运行内置的一系列sanity测试,确保perf工具自身正确性和稳定性。
   timechart       工具用于可视化工作负载期间的系统整体行为
   top             系统性能分析工具,类似于Linux的top命令,但专注于性能分析,显示正在运行进程的实时性能统计数据。
   version         显示perf二进制文件的版本信息
   probe           定义新的动态跟踪点,使得perf能够追踪和记录自定义的内核函数或模块行为。
   trace           类似strace的工具,用于跟踪系统调用和信号

相关视频推荐

2024,彻底搞懂计算机的底层原理,linux内核源码分析教程,六大模块全面分析(内存管理、进程管理、设备驱动、网络协议栈、文件系统、中断管理及基础)https://www.bilibili.com/video/BV1GT4y1t7Hs/

免费学习地址:Linux C/C++开发(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全)

需要C/C++ Linux服务器架构师学习资料加qun579733396获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

5 perf list查看事件源

perf list 是Linux内核性能分析工具perf的一个重要子命令,它的作用是列出当前系统支持的所有性能监视事件。

这些事件可以包括但不限于:

1、硬件事件(Hardware Events):指处理器提供的各种性能计数器事件,例如指令计数器(Instructions retired)、缓存命中/未命中(Cache hits/misses)、分支预测失败(Branch mispredictions)等,这些事件反映了处理器在微观层面的具体运行状态。

2、软件事件(Software Events):由操作系统内核或其他软件层模拟或定义的事件,比如进程切换(Context switches)、页故障(Page faults)、磁盘I/O操作等。

3、内核 tracepoints 和 uprobes:内核 tracepoints 是内核开发者预先植入内核代码中的钩子,用于跟踪内核函数的执行;uprobes 则允许用户在用户空间程序的任何地址处插入探针,收集运行时数据。

当你运行 perf list 命令时,它会显示出当前平台支持的所有性能事件的详细列表,每个事件都有一个对应的名称,你可以基于这个列表选择感兴趣的事件,然后在其他perf子命令中引用这些事件来执行性能分析操作。

例如,如果你想监控某个进程的CPU使用情况,你可以先通过 perf list 查找与CPU时间相关的事件(如 cpu-clock),然后使用 perf stat -e cpu-clock来测量命令执行过程中CPU时间的消耗。同样,对于更复杂的性能分析需求,也可以结合 perf record 和 perf report 等子命令来采集并分析更为详尽的性能数据。

监测单个命令的CPU时间

这个命令将会运行 sleep 5 (让进程休眠5秒),同时计算该进程在这5秒内占用CPU的总时间(毫秒)。

sudo perf stat -e cpu-clock 

监测程序执行期间的CPU时间

sudo perf stat -e cpu-clock ./a.out

6 perf stat

perf stat 是 Linux 内核性能分析工具 perf 的一个重要子命令,主要用于在执行指定命令或进程时,收集和显示性能计数器统计信息。此命令能够准确地测量和分析系统或特定进程在某一时间段内的性能特征。

perf stat 的基本用法和功能特点如下:

1、基础使用:

命令格式:

perf stat [options] [<command>]

示例

perf stat ls

这将运行 ls 命令,并在命令执行前后显示这段时间内系统的性能统计数据,如CPU时间、上下文切换、缓存事件等。

2、事件选择:

指定性能事件:

perf stat -e <event1>,<event2>,... <command>

示例

perf stat -e cpu-cycles,cache-misses ls

3、统计范围:

系统范围:默认情况下,perf stat 会对整个系统的性能进行统计。

进程范围:可以通过 -p 选项指定进程ID(PID)来只针对特定进程统计。

perf stat -p <PID> [-e <event>] 

4、其他选项:

-a 或 --all-cpus:收集所有CPU的数据。

-d 或 --detailed:提供更详细的统计数据。

-r 或 --repeat=N:重复执行命令 N 次,并统计平均性能数据。

-I 或 --interval=N:以固定间隔重复采样。

5、输出解读:输出结果通常包含事件发生的绝对数量、单位时间内的平均事件发生率、以及某些比例数据。例如,可以得到CPU时间、上下文切换次数、页面错误数、缓存命中/未命中次数等。

6、长时间监控:可以结合 -o 选项将统计数据导出到文件,便于后期分析,或者使用 -t 选项指定执行时间,而不是依赖于命令自身的执行结束。

总之,perf stat 是一个强大的实时性能监控工具,不仅能够快速获取单次执行命令的性能数据,还能通过灵活的选项定制针对特定性能事件的持续监控,非常适合进行系统性能分析、应用调优等工作。

7 perf record

perf record 是 Linux 内核性能分析工具 perf 的一个重要子命令,用于收集指定进程或系统的性能数据,包括但不限于 CPU 性能事件、硬件性能计数器、内核动态追踪以及调用栈信息。以下是 perf record 命令的基本结构及一些关键选项的解释:

perf record [options] [command]

常用选项包括:

-e, --event=EVENT: 指定要监控的特定性能事件,例如 CPU 时钟周期、指令计数器、缓存未命中的次数等。例如 perf record -e cycles my_program 会记录 my_program 运行过程中的 CPU 周期数。

-p, --pid=PID: 跟踪指定进程 ID 的性能数据,例如 perf record -p 12345 会监控进程ID为12345的进程。

-g, --call-graph=[fp| dwarf| lbr]: 启用调用栈跟踪,收集函数调用层级信息。不同的选项对应不同的调用图生成方式。

-F, --freq=N: 设置采样频率,比如 -F 99 表示每秒采样99次。

-a, --all-cpus: 监控所有CPU核心的性能数据。

sleep N: 结合命令一起使用时,会让 perf record 在执行指定命令后等待 N 秒再停止记录。

perf record 执行后会在当前工作目录下生成一个名为 perf.data 的二进制文件,其中包含了所有收集到的性能数据。

当您完成数据收集后,可以使用 perf report 命令来分析和展示这些数据。

8 perf record

perf report用于解析和展示由 perf record 命令收集的性能数据。这个命令读取 .data 格式的二进制性能数据文件,并生成易于理解和可视化的性能报告,帮助开发者和系统管理员识别程序或系统中消耗资源最多的部分,如CPU、内存、缓存或其他硬件相关的性能事件。

perf report [-i perf.data] [options]

-i, --input=FILE:指定要读取的 perf 数据文件,默认通常是 perf.data。

几个关键选项和特性包括:

  • 折叠模式(Collapse Mode): 显示函数层级关系和调用栈汇总,便于分析函数间的调用开销。

  • 树状视图(Tree View): 展示函数之间的调用关系,直观地看到哪个函数调用了哪些其他函数以及每个函数所消耗的资源比例。

  • 百分比模式(Percentages): 报告按照占用资源(如CPU时间)的百分比排列各项,帮助快速定位热点区域。

  • 限制显示范围(Filtering Options): 可以通过模块名、函数名、地址范围等过滤条件来筛选需要关注的部分。

  • 符号解析(Symbol Resolution): 自动或手动解决函数符号,以便准确知道哪些具体代码段消耗了较多资源。

  • 调用图表(Call Graphs): 如果原始数据包含调用图信息,则报告中可以展示详细的调用层级和上下文切换信息。

perf report 输出通常包含以下几个部分:

概述:总体的统计数据,包括样本总数、各事件发生的总次数等。

函数列表:按样本数量排序的函数列表,展示了各个函数占整体执行时间的比例。

调用图:如果启用了 -g 参数,会展示函数调用关系图,这对于识别性能瓶颈和热点函数非常有用。

通过这种方式,开发者可以根据 perf record 和 perf report 的输出来优化代码性能,定位耗时操作,进而进行针对性的性能调优。

9 perf top命令

它可以实时显示系统上各个函数或指令的CPU使用率,帮助开发者和系统管理员追踪和定位性能瓶颈。相比传统的 top 命令,perf top 提供了更深入的性能分析视角,能够精确到函数级别的统计信息。

其输出结果的列含义如下:

第一列:展示了各个符号所引发的性能事件所占的比例,具体表现为占用的CPU周期比例。这一列体现了每个函数或内核调用在CPU使用中的相对权重。

第二列:标识了与性能事件关联的DSO(Dynamic Shared Object),即动态共享对象。这可能是应用程序本身、Linux内核、动态链接库(.so文件)或内核模块。

第三列:列出了DSO的类型标记。方括号中的内容提供了符号所属的代码区域信息,例如,[]表示该符号属于用户态的ELF(Executable and Linkable Format)文件,这可能是一个可执行文件或动态链接库;而[K]则表示该符号源自内核或内核模块代码。

第四列:给出了具体的符号名称。在某些情况下,如果perf无法解析符号信息,这一列可能会显示十六进制的地址,而非函数名。而在可以解析的情况下,这一列将显示具体的函数或方法名称。

10 生成火焰图

火焰图(Flame Graph)是一种高性能分析工具,由Brendan Gregg创造,主要用于可视化程序执行时的CPU调用栈,展示程序在不同函数层级上的时间消耗情况。这种图形化的表示方法因其形状酷似燃烧的火焰而得名。

火焰图的特点如下:

  • 可视化堆栈跟踪:火焰图将多个堆栈跟踪(stack traces)合并在一起,形成一个层次分明的图表。每个函数调用形成一个矩形,宽度表示函数在CPU上执行的时间占比,高度表示函数调用的层级。

  • 直观揭示性能瓶颈:通过观察火焰图,可以直观地看到哪些函数在执行过程中占据了大量的CPU时间,从而快速定位潜在的性能瓶颈。

  • 排序方式:x轴通常按照函数名称字母顺序排列,而不是时间顺序。这样做的好处是可以很容易地对比相似函数在整个程序中的开销。

  • 颜色编码:图中的每个矩形(或称"火焰条")通常使用随机颜色,目的是在视觉上更容易区分相邻的函数调用。有些变种火焰图可能会采用不同的颜色方案来区分不同的代码区域或模块。

  • 分析数据来源:火焰图的数据来源于性能分析工具(如Linux中的perf工具)收集的CPU采样数据,或者是通过其他性能分析手段得到的调用栈信息。

  • 应用领域:火焰图广泛应用于性能优化、故障排查、代码重构等领域,尤其适合大型复杂软件系统,有助于工程师们快速理解和改进程序性能。

下载火焰图代码

git clone https://github.com/brendangregg/FlameGraph.git

使用perf采集一组数据

执行top命令,可以看到gnome-shell进程的PID是1847

sudo perf record -F 100 -p 1847 -g -- sleep 30

这条命令是用来使用Linux的性能分析工具perf进行记录和分析特定进程的性能数据的。命令的组成部分及其功能解释如下:

  • sudo: 以超级用户权限执行命令,因为在很多情况下,为了获取详细的性能数据,perf需要访问受保护的内核资源。

  • perf record: perf工具的子命令,用于执行性能数据记录。它会在指定条件下收集有关系统或进程的性能数据,并将其保存到一个数据文件中(默认为perf.data)。

  • -F 100: 设置采样频率为每秒100次。这意味着每隔大约10毫秒就会进行一次采样,以此频率收集性能数据。

  • -p 1847: 指定要监控的进程ID(PID)为1847。perf将会收集这个进程的性能数据。

  • -g: 启用调用栈收集(call graph)。这意味着在每次采样时,perf不仅记录当前执行的指令地址,还会记录当时的函数调用栈,这对于分析函数间的调用关系和性能瓶颈非常有用。

  • --: 表示命令行选项的结束,之后的参数会被当作非选项参数传递给命令。在这种情况下,后面跟的是sleep 30命令。

  • sleep 30: 这是一个简单的命令,让它执行30秒。在此期间,perf会记录PID为1847的进程的性能数据。sleep命令的作用是为了确保有足够的采样数据被收集,同时不影响被监控进程的正常运行。

所以,整个命令的目的是在接下来的30秒内,以每秒100次的频率,对PID为1847的gnome-shell进程进行详细的性能数据采样(包括调用栈信息),并将这些数据存储起来供后续分析使用。

统计调用栈信息

sudo perf report -n --stdio

具体解读如下:

  • perf report: perf工具的另一个子命令,用于从之前记录的性能数据文件中生成分析报告。通常是在运行perf record采集数据后,使用此命令来查看和分析结果。

  • -n: 选项告诉perf report不要尝试去解析符号(symbolicate),也就是说,不将地址转换为函数名称或其他可读性更高的形式。如果未加载适当的调试信息或符号表,或者出于某种原因不需要函数名的解析,则可以使用这个选项。

  • --stdio: 指定报告输出至标准输出(stdout),而不是默认的交互式TUI模式。这意味着报告将以纯文本的形式直接打印到终端窗口,适合自动化脚本处理或直接查看简单报告,而非通过图形界面浏览详细报告。

综上所述,该命令旨在以非解析符号的纯文本格式,从之前用perf record收集的性能数据中生成并显示一个简洁的性能分析报告。由于没有指定具体的数据文件名,perf report将默认读取最近一次记录的.data文件。

生成程序性能分析火焰图的一组流程

成程序性能分析火焰图的一组流程
# 生成折叠后的调用栈,该命令从名为 perf.data 的 perf 数据文件中提取详细的性能事件样本信息,并以可读的文本格式输出。
# 这一步生成的 perf.unfold 文件包含了未折叠的调用栈信息,即每次采样的函数调用链。
# perf.unfold 是上一步生成的包含详细调用栈信息的文件。
sudo perf script -i perf.data > perf.unfold

# 生成火焰图
# ./stackcollapse-perf.pl 是 FlameGraph 工具集中的一部分,用于处理 perf 生成的未折叠调用栈数据。
# 经过 
stackcollapse-perf.pl 处理后的文件内容是对原始调用栈进行了折叠统计,
# 即将同一调用路径下的事件次数累加,形成一种更紧凑的格式,便于生成火焰图。
./stackcollapse-perf.pl perf.unfold > perf.folded

# 最后生成 svg 图
# ./flamegraph.pl 是 FlameGraph 工具集中用于生成火焰图的脚本
# 将火焰图生成的输出重定向到了名为 perf.svg 的SVG矢量图形文件中。
./flamegraph.pl perf.folded > perf.svg

SVG是一种可缩放的矢量图形格式,生成的火焰图可以直接在浏览器中查看,形象地展示了各个函数在CPU执行过程中的调用关系及其占用时间比例,有助于定位性能瓶颈。

相关推荐
滴水之功1 小时前
VMware OpenWrt怎么桥接模式联网
linux·openwrt
ldinvicible1 小时前
How to run Flutter on an Embedded Device
linux
YRr YRr2 小时前
解决Ubuntu 20.04上编译OpenCV 3.2时遇到的stdlib.h缺失错误
linux·opencv·ubuntu
认真学习的小雅兰.2 小时前
如何在Ubuntu上利用Docker和Cpolar实现Excalidraw公网访问高效绘图——“cpolar内网穿透”
linux·ubuntu·docker
zhou周大哥2 小时前
linux 安装 ffmpeg 视频转换
linux·运维·服务器
不想起昵称9293 小时前
Linux SHELL脚本中的变量与运算
linux
the丶only3 小时前
单点登录平台Casdoor搭建与使用,集成gitlab同步创建删除账号
linux·运维·服务器·docker·gitlab
枫叶红花4 小时前
【Linux系统编程】:信号(2)——信号的产生
linux·运维·服务器
_微风轻起4 小时前
linux下网络编程socket&select&epoll的底层实现原理
linux·网络