性能工具perf的用法以及如何绘制性能火焰图

本文深入介绍了perf,一个内置在Linux内核中的性能分析工具,详细解释了其工作原理,包括基于事件采样的性能事件分析,以及如何使用perf进行性能瓶颈定位和热点代码分析。文章涵盖了perf的多种使用场景,如直接启动服务或挂接到已启动的进程,以及如何通过perftop、perfrecord和perfreport等命令进行性能监控和分析。此外,还探讨了perf在不同权限设置下的功能限制。

perf简介

Perf是内置于Linux内核源码树中的性能剖析(profiling)工具。其基于事件采样原理,以性能事件为基础,常用于性能瓶颈的查找与热点代码的定位。

性能调优工具如 perf,Oprofile 等的基本原理都是对被监测对象进行采样,最简单的情形是根据 tick 中断进行采样,即在 tick 中断内触发采样点,在采样点里判断程序当时的上下文。假如一个程序 90% 的时间都花费在函数 foo() 上,那么 90% 的采样点都应该落在函数 foo的上下文中。只要采样频率足够高,采样时间足够长,那么以上推论就比较可靠。因此,通过 tick 触发采样,我们便可以了解程序中哪些地方最耗时间,从而重点分析。

稍微扩展一下思路,就可以发现改变采样的触发条件使得我们可以获得不同的统计数据:

  • 以时间点 ( 如 tick) 作为事件触发采样便可以获知程序运行时间的分布。
  • 以 cache miss 事件触发采样便可以知道 cache miss 的分布,即 cache 失效经常发生在哪些程序代码中
  • 等等其他事件

当然,perf使用更多是CPU的PMU计数器,PMU计数器是大部分CPU都有的功能,它们可以用来统计比如L1 Cache失效的次数,分支预测失败的次数等。PMU可以在这些计数器的计数超过一个特定的值的时候产生一个中断,这个中断,我们可以用和时钟一样的方法,来抽样判断系统中哪个函数发生了最多的Cache失效,分支预测失效等。

perf 用法

本文示例代码:

//
// Created by wilcohuang on 2018/11/19.
//

#include <unistd.h>

using namespace std;

#define NUM 500000

void init(int *int_array) {
    for (int i = 0; i < NUM; i++) {
        int_array[i] = i;
    }
}

void accu(int *int_array, long &sum) {
    for (int i = 0; i < NUM; i++) {
        sum += int_array[i];
        usleep(3);
    }
}

int main() {
    int int_array[NUM];
    init(int_array);
    long sum = 0;
    accu(int_array, sum);
}

说明

perf的使用可以分为两种方式:

  1. 直接使用perf启动服务
  2. 挂接到已启动的进程
    第一种方式不需要root权限,第二种方式需要root权限

perf top

用于查看cpu的主要性能消耗点

跟踪一个名为main的进程:

perf top -e cycles -p `pgrep main`

输入如下:
在这里插入图片描述

perf record

同样是分析诊断进程:

perf record -e cpu-clock -g ./run
或者
perf record -e cpu-clock -g -p 4522

使用ctrl+c中断perf进程,或者在程序执行结束后,会产生perf.data的文件,使用
perf report
会产生结果分析,如图
在这里插入图片描述

火焰图

上面通过文件查看不够直观,还有一种火焰图分析的方式:
工具下载:
git clone https://github.com/brendangregg/FlameGraph.git
使用命令:

使用perf script工具对perf.data进行解析perf script -i perf.data &> perf.unfold
将perf.unfold中的符号进行折叠:/data/stackcollapse-perf.pl perf.unfold &> perf.folded
最后生成svg图:/data/flamegraph.pl perf.folded > perf.svg

然后可以通过chrome或者看图软件打开:
r

Y轴表示调用栈,X轴越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。

所以,一般我们只需要看有没有出现 “平顶”,如果有,那么这个函数可能有性能问题。

perf diff

优化程序性能后,我们自然要看下效果:
perf diff perf.data perf.data.before

我们干掉了上文中的usleep(3);这句代码,然后diff结果输出如下:

init、accu函数的时间占比已经将为了0 ?

权限问题

perf如果不是root,你可以做什么取决于sysctl设置。kernel.perf_event_paranoid

cat /proc/sys/kernel/perf_event_paranoid

kernel.perf_event_paranoid= 2:您无法进行任何测量。该perf实用程序可能仍然是有用的分析现有的记录用perf ls,perf report,perf timechart或perf trace。
kernel.perf_event_paranoid= 1:您可以使用perf stator 跟踪命令perf record,并获取内核分析数据。
kernel.perf_event_paranoid= 0:您可以使用perf stat或跟踪命令perf record,并获取CPU事件数据。
kernel.perf_event_paranoid= -1:您获得了对内核跟踪点的原始访问权限(具体来说,您可以mmap创建文件perf_event_open,我不知道其含义是什么)。

参考

更全的perf参考:

本文参考:

<think>嗯,用户现在问的是关于如何使用perf工具抓取内核调用栈以及制作火焰。我需要先回忆一下perf的基本用法火焰的制作步骤。首先,perf是Linux内核自带的性能分析工具,可以收集各种性能数据,比如CPU的调用栈。火焰则是一种可视化工具,能够直观展示调用栈的分布情况,帮助定位性能瓶颈。 用户之前已经询问过alarm的相关概念,现在转向性能分析工具,可能是在实际工作中遇到了性能问题,或者正在学习系统调优。考虑到用户可能是开发人员或者运维工程师,需要详细但清晰的步骤说明。他们可能需要从安装perf开始,到数据收集、生成火焰的整个流程。 首先,我应该确认用户的操作系统环境,但可能用户没有说明,所以需要给出通用的步骤,比如安装perf工具,可能需要安装linux-tools或者相关包。然后,使用perf record命令记录调用栈,这里要提到常用的选项,比如-g(记录调用栈)、-F(采样频率)、-p(指定进程)等。接着,使用perf script将数据转换为可读格式,再通过FlameGraph脚本生成火焰。 需要注意的是,用户可能对某些步骤不熟悉,比如如何获取FlameGraph的脚本库,是否需要克隆GitHub仓库。此外,权限问题也是常见的,比如运行perf可能需要sudo权限,或者调整内核参数如perf_event_paranoid。这些都是需要提及的。 另外,火焰的解读方法也很重要。用户可能生成了火焰,但不知道如何分析,所以需要简单说明如何查看火焰,比如宽度代表资源占用,层级代表调用栈深度,以及如何识别热点函数。 可能用户遇到的困难包括采样频率设置不当导致数据不准确,或者生成火焰时脚本路径错误。需要提醒常见问题及解决方法,比如权限问题、依赖安装等。此外,是否支持用户空间和内核空间的调用栈同时记录,这也是perf的优势之一,可以一并说明。 最后,总结步骤,确保用户能按部就班地操作,同时提供参考链接,方便进一步学习。还要保持回答的结构清晰,分步骤说明,使用代码块展示命令,这样用户容易复制和执行。</think>以下是使用 **`perf` 工具抓取内核调用栈并生成火焰**的完整流程,适用于 Linux 系统性能分析: --- ### **1. 工具准备** #### (1) 安装 `perf` ```bash # Ubuntu/Debian sudo apt-get install linux-tools-common linux-tools-generic # CentOS/RHEL sudo yum install perf # 验证安装 perf --version ``` #### (2) 获取火焰生成脚本 ```bash git clone https://github.com/brendangregg/FlameGraph.git cd FlameGraph # 后续步骤均在此目录下操作 ``` --- ### **2. 抓取调用栈数据** #### (1) 使用 `perf record` 采样 ```bash # 全局采样(所有进程) sudo perf record -F 99 -a -g -- sleep 60 # 采样 60 秒,频率 99Hz # 指定进程采样(PID=1234) sudo perf record -F 99 -p 1234 -g -- sleep 60 ``` - **参数说明**: - `-F 99`:采样频率(通常 99Hz 足够,避免过高影响性能)。 - `-a`:监控所有 CPU。 - `-g`:记录调用栈(即 `--call-graph`)。 - `-- sleep 60`:采样持续时间(单位:秒)。 #### (2) 生成原始数据文件 ```bash sudo perf script > perf.script # 将二进制数据转换为可读文本 ``` --- ### **3. 生成火焰** #### (1) 处理数据并生成 SVG ```bash # 提取调用栈信息 ./stackcollapse-perf.pl perf.script > perf.folded # 生成火焰 SVG ./flamegraph.pl perf.folded > flamegraph.svg ``` #### (2) 查看火焰 ```bash xdg-open flamegraph.svg # 在浏览器中打开 ``` --- ### **4. 火焰解读** - **横轴宽度**:表示函数在采样中出现的频率(即资源消耗占比)。 - **纵轴层级**:表示调用栈深度,顶层是正在运行的函数,下层是其调用者。 - **关键用途**: - 快速定位 CPU 热点(最宽的“塔”通常是性能瓶颈)。 - 分析内核与用户空间的调用链关系(如系统调用、锁竞争)。 --- ### **5. 高级用法** #### (1) 指定事件类型 ```bash # 监控特定事件(如缓存未命中、上下文切换) sudo perf record -e cache-misses -a -g -- sleep 10 ``` #### (2) 内核与用户空间分离 ```bash # 仅抓取内核调用栈 sudo perf record -a -g --kcore # 分离用户态和内核态火焰 ./flamegraph.pl --color=java perf.folded > user.svg ./flamegraph.pl --color=hot perf.folded > kernel.svg ``` #### (3) 实时生成火焰 ```bash # 一键式管道操作 sudo perf record -F 99 -a -g -- sleep 10; \ sudo perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > realtime.svg ``` --- ### **6. 常见问题** - **权限不足**:需 `sudo` 或调整 `/proc/sys/kernel/perf_event_paranoid` 值为 `-1`。 - **符号表缺失**:确保调试符号已安装(如 `linux-image-$(uname -r)-dbgsym`)。 - **火焰空白**:检查采样时间是否太短或进程无 CPU 占用。 --- ### **参考工具链** - **perf**: Linux 内核内置性能分析工具。 - **FlameGraph**: Brendan Gregg 开源的火焰生成脚本库。 - **Hotspot**: 形化火焰分析工具(基于 KDE)。 如果需要更具体的场景分析(如网络延迟、磁盘 I/O 火焰),可进一步说明需求! 🔥
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值