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

一、perf安装及简介

1.安装perf

1.Ubuntu/Debian
apt install linux-tools-common
apt install linux-tools-5.15.0-101-generic

2.Centos/Redhat
yum install perf -y

2.常用的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的工具,用于跟踪系统调用和信号

3.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的总时间(毫秒)
perf stat -e cpu-clock sleep 5 
监测程序执行期间的CPU时间
sudo perf stat -e cpu-clock ./a.out

二、perf子命令

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

2.perf record

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

2.常用选项
-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 命令来分析和展示这些数据。

3.perf record

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

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

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

折叠模式(Collapse Mode): 显示函数层级关系和调用栈汇总,便于分析函数间的调用开销。
树状视图(Tree View): 展示函数之间的调用关系,直观地看到哪个函数调用了哪些其他函数以及每个函数所消耗的资源比例。
百分比模式(Percentages): 报告按照占用资源(如CPU时间)的百分比排列各项,帮助快速定位热点区域。
限制显示范围(Filtering Options): 可以通过模块名、函数名、地址范围等过滤条件来筛选需要关注的部分。
符号解析(Symbol Resolution): 自动或手动解决函数符号,以便准确知道哪些具体代码段消耗了较多资源。
调用图表(Call Graphs): 如果原始数据包含调用图信息,则报告中可以展示详细的调用层级和上下文切换信息。

perf report 输出通常包含以下几个部分:
概述:总体的统计数据,包括样本总数、各事件发生的总次数等。
函数列表:按样本数量排序的函数列表,展示了各个函数占整体执行时间的比例。
调用图:如果启用了 -g 参数,会展示函数调用关系图,这对于识别性能瓶颈和热点函数非常有用。

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

4.perf top命令

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


命令输出结果的列含义如下:
第一列:展示了各个符号所引发的性能事件所占的比例,具体表现为占用的CPU周期比例。这一列体现了每个函数或内核调用在CPU使用中的相对权重。
第二列:标识了与性能事件关联的DSO(Dynamic Shared Object),即动态共享对象。这可能是应用程序本身、Linux内核、动态链接库(.so文件)或内核模块。
第三列:列出了DSO的类型标记。方括号中的内容提供了符号所属的代码区域信息,例如,[]表示该符号属于用户态的ELF(Executable and Linkable Format)文件,这可能是一个可执行文件或动态链接库;而[K]则表示该符号源自内核或内核模块代码。
第四列:给出了具体的符号名称。在某些情况下,如果perf无法解析符号信息,这一列可能会显示十六进制的地址,而非函数名。而在可以解析的情况下,这一列将显示具体的函数或方法名称。

三、生成火焰图

1.安装火焰图

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

2.使用perf采集一组数据

1.使用top查看当前活跃的进程
 PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                
 19083 polkitd   20   0 1780688 427112  20808 S   0.7 11.1  20:18.38 mysqld                 
  8896 mongod    20   0 1558108 127880  17136 S   0.7  3.3  12:00.90 mongod                 
 18824 root      20   0 1849024  80532  28432 S   0.0  2.1   0:28.45 dockerd  

2.采集指定的进程
perf record -F 100 -p 19083 -g -- sleep 30 #这里采集MySQL进程,此命令结束后会自动创建perf.data 
命令的组成部分及其功能解释如下:
record: perf工具的子命令,用于执行性能数据记录。它会在指定条件下收集有关系统或进程的性能数据,并将其保存到一个数据文件中(默认为perf.data)。
-F 100: 设置采样频率为每秒100次。这意味着每隔大约10毫秒就会进行一次采样,以此频率收集性能数据。
-p 19083 : 指定要监控的进程ID(PID)为19083 。perf将会收集这个进程的性能数据。
-g: 启用调用栈收集(call graph)。这意味着在每次采样时,perf不仅记录当前执行的指令地址,还会记录当时的函数调用栈,这对于分析函数间的调用关系和性能瓶颈非常有用。
--: 表示命令行选项的结束,之后的参数会被当作非选项参数传递给命令。在这种情况下,后面跟的是sleep 30命令。
sleep 30: 这是一个简单的命令,让它执行30秒。在此期间,perf会记录PID为1847的进程的性能数据。sleep命令的作用是为了确保有足够的采样数据被收集,同时不影响被监控进程的正常运行。

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

3.统计调用栈信息

perf report -n --stdio
命令解释:
report: perf工具的另一个子命令,用于从之前记录的性能数据文件中生成分析报告。通常是在运行perf record采集数据后,使用此命令来查看和分析结果。
-n: 选项告诉perf report不要尝试去解析符号(symbolicate),也就是说,不将地址转换为函数名称或其他可读性更高的形式。如果未加载适当的调试信息或符号表,或者出于某种原因不需要函数名的解析,则可以使用这个选项。
--stdio: 指定报告输出至标准输出(stdout),而不是默认的交互式TUI模式。这意味着报告将以纯文本的形式直接打印到终端窗口,适合自动化脚本处理或直接查看简单报告,而非通过图形界面浏览详细报告。

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

4.生成程序性能分析火焰图

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

2.生成火焰图
./stackcollapse-perf.pl perf.unfold > perf.folded

./stackcollapse-perf.pl 是 FlameGraph 工具集中的一部分,用于处理 perf 生成的未折叠调用栈数据。


3.生成 svg 图
./flamegraph.pl perf.folded > perf.svg

将火焰图生成的输出重定向到了名为 perf.svg 的SVG矢量图形文件中
抄自于:https://mp.weixin.qq.com/
 
posted @ 2024-05-07 16:41  百衲本  阅读(1180)  评论(0编辑  收藏  举报
cnblogs_post_body { color: black; font: 0.875em/1.5em "微软雅黑" , "PTSans" , "Arial" ,sans-serif; font-size: 15px; } cnblogs_post_body h1 { text-align:center; background: #333366; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 23px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } cnblogs_post_body h2 { text-align:center; background: #006699; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 20px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } cnblogs_post_body h3 { background: #2B6695; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 18px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } 回到顶部 博客侧边栏 回到顶部 页首代码 回到顶部 页脚代码