【linux性能分析】perf分析CPU占用详情

1. 如何使用perf工具
1.1 perf安装
  • 参考perf工具安装和使用

  • perf安装命令:

    sudo apt-get install linux-tools-$(uname -r) linux-tools-generic -y
    sudo apt-get install linux-tools-$(uname -r) linux-tools-generic -y --fix-missing
    
    perf -v		# 查看perf版本
    
1.2 首次使用perf报错
  • No permission to enable cycles: u event

  • 解决方法:直接修改 /proc/sys/kernel/perf_event_paranoid,按照报错提示修改为 -1

  • 如果是docker容器环境提示 read only file system, 新建容器的时候应该添加 privileged=true 赋予权限

1.3 添加测试程序
  • 新建并添加测试程序如下,输入代码
    touch main.cpp
    vim main.cpp
    
    #include <iostream>
    using namespace std;
    
    void delay()
    {
    	int i,j;
    	for(i = 0; i < 1000000; i++)
    		j=i;
    }
    
    void function_1()
    {
    	int i;
    	for(i=0 ; i < 10; i++)
    		delay();
    }
    
    void function_2()
    {
    	int i;
    	for(i = 0; i< 30; i++)
    		delay();
    }
    
    int main(void)
    {
    	std::cout << "begin: " << std::endl;
    	function_1();
    	function_2();
    	std::cout << "end!" << std::endl;
    }
    
1.4 编译并执行指令生成perf.data文件
  • 编译测试程序

    g++ main.cpp -o main
    
  • 生成perf.data

    sudo perf record ./main
    
1.5 添加-g选项能查看call graph调用信息
  • 添加-g选项查看调用信息

    sudo perf record -g ./main
    
1.6 查看perf.data
  • 生成热点函数占用CPU的比例

    perf report
    
  • 可以看到, 程序中main函数总体CPU资源占比(CPU时间片)97.85%, 其中delay函数占比97.59%, function_1和function_2的占比占比近7:3

1.7 perf工作流
1.8 sudo perf record -F 99 -p 2512 -g – sleep 60
  • record: 表示采集系统事件,没有采用-e执行采集事件,则默认采用CPU时钟周期
  • -F: 指定采样频率, 可以设置99, 1000等等, -F 99表示每秒采样99次, 如果99次都是同一函数, 说明CPU在这1s内都在执行这一函数, 可能存在性能问题. 频率越高,perf record获得的样本数量也会越多,分析结果会更加精细,但采样会使程序的运行变慢,因此需要根据具体情况选择合适的采样频率; 默认频率4000Hz
    在这里插入图片描述
  • -p: 指定进程号, 对某一进程进行分析
  • -g: 表示记录调用栈, 拿到程序的call graph信息
  • --sleep 60: 表示对进程持续分析60s
2. 如何生成火焰图
2.1 安装火焰图生成工具
  • Flame Graph工程实现了一套生成火焰图的脚本, 直接clone下来使用

    git clone https://github.com/brendangregg/FlameGraph.git
    
  • 该文件夹下有很多perf语言脚本, 可完成不同堆栈分析

2.2 生成和创建火焰图的步骤
  • 捕获堆栈: perf script -i perf.data &> perf.unfold

  • 折叠堆栈: ./FlameGraph/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded

  • 生成火焰图: ./FlameGraph/FlameGraph/flamegraph.pl perf.folded > perf.svg

  • 各个步骤的含义:

    • 捕获堆栈: 可以使用 perf、systemtap、dtrace 等工具抓取程序的运行堆栈
    • 折叠堆栈: 对捕获的堆栈信息进行分析组合, 将重复的堆栈累计在一起, 从而体现出负载和关键路径, 由FlameGraph的stackcollapse程序生成, 注意程序路径
    • 生成火焰图: 分析由stackcollapse输出的堆栈信息的火焰图, 执行完后生成.svg图片
2.3 火焰图的含义
  • y轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数

  • x轴表示抽样数,如果一个函数在x轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间占比越大。注意,x轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的

  • 颜色无特殊含义, 因为火焰图表示CPU的繁忙程度, 所以一般选择暖色调

  • 火焰图就是看顶层的哪个函数占据的宽度最大。只要有"平顶",就表示该函数可能存在性能问题

  • 鼠标悬浮: (浏览器打开.svg图片)可显示函数名, 抽样抽中的次数, 占总抽样次数的百分比

  • 点击放大: 点击某一层,该层会占据所有宽度,显示详细信息,再点击左上角ResetZoom可恢复

  • 查找: Ctrl + F, 高亮显示查找的函数

  • 火焰图的缺陷: 调用栈可能不完整, 当调用栈过深时,某些系统只返回前面的一部分(比如前10层); 函数名可能缺失, 有些函数没有名字,编译器只用内存地址来表示(比如匿名函数), 有可能是编译器优化等级过高

  • FlameGraph我们习惯称之为"CPU火焰图", 还有"浏览器火焰图"(x轴是任务时间轴), “红/蓝差分火焰图”, 红蓝差分火焰图可以用来对比分析两次修改的性能差异, 红色表示上升, 蓝色表示下降, 由此来寻找根因; 此外还有"Memory Flame Graphs"(检测内存占用量增加的原因), “Off-CPU Flame Graphs”(不在CPU上运行的时间,如I/O时间等), “Hot/Cold Flame Graphs”(CPU和非CPU结合,显示所有线程的运行时间)

2.4 生成"红/蓝差分火焰图"示例
  • 修改源程序

    #include <iostream>
    using namespace std;
    
    void delay()
    {
    	int i,j;
    	for(i = 0; i < 1000000; i++)
    		j=i;
    }
    
    void function_1()
    {
    	int i;
    	for(i=0 ; i < 20; i++)
    		delay();
    }
    
    void function_2()
    {
    	int i;
    	for(i = 0; i< 20; i++)
    		delay();
    }
    
    int main(void)
    {
    	std::cout << "begin: " << std::endl;
    	function_1();
    	function_2();
    	std::cout << "end!" << std::endl;
    }
    
  • 重新编译执行

    g++ main.cpp -o main
    sudo perf record -g ./main		# 生成新的perf.data
    
  • 折叠堆栈

    perf script -i perf.data &> perf.unfold		# 生成新的perf.unfold
    ./FlameGraph/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded1
    
  • 生成火焰图

    ./FlameGraph/FlameGraph/flamegraph.pl perf.folded1 > perf2.svg
    
  • 以perf.folded为基准,生成差分火焰图

    ./FlameGraph/FlameGraph/difffolded.pl perf.folded perf.folded1 | ./FlameGraph/FlameGraph/flamegraph.pl > diff.svg
    
  • 浏览器打开diff.svg

    红色部分表示function_1中delay耗时增加了, 蓝色部分表示function_2中delay耗时减少了, 和我们修改的预期是一样的

3. 使用perf分析节点CPU占比
  • 执行报错1:sudo perf record -g ./可执行文件, 执行失败。节点编译完成后报错找不到
    error while loading shared libraries: liblibstatistics_collector.so

  • 解决方法:搜索发现liblibstatistics_collector.so存在, 但通过export添加路径后不生效

    • export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/so_path 执行后不管用
    • sudo ldconfig # 动态链接库管理, 让不同目录下的动态链接库为系统所共享
    • 或者试下 ldconfig 然后 perf record -g ./可执行文件, 不要加sudo
    • 执行后生效
  • 执行报错2:上一步生成的perf.data执行perf report提示文件size field is 0
    data size field is 0 which is unexpected

  • 原因分析:看下来是perf record -g ./可执行文件的形式没有正确生成perf.data, 单独执行perf record进行采样

    top		# 查看程序PID = 228
    
    perf record -p 228 -g		# 生成perf.data, Ctrl + C结束录制
    
    perf report				# 可正常读取
    
  • 生成火焰图

    perf script -i perf.data &> perf.unfold		# 捕获堆栈
    
    ./FlameGraph/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded	# 折叠堆栈
    
    ./FlameGraph/FlameGraph/flamegraph.pl perf.folded > perf.svg		# 生成火焰图
    
  • 浏览器打开.svg图片

    ros2的CPU占用,播包5min
    ros1的CPU占用,播包5min
  • 对比结论:

    • 节点总体CPU占用在102%
    • 长时播包测试可知,节点的CPU占用主要来自std::thread::State_impl占74.51%,其中主程序25%+多线程相关45%
    • 多线程相关的45%分析
      • 对比ros1的CPU占用,在ros2中节点的CPU占用高只是运行机制的差异
      • 对多线程管理占用的45%的CPU,包含除主程序外的多个任务:不同topic消息队列同步访问,消息转proto,消息收发同步;线程同步统计节点掉线信息;线程同步维护节点状态信息等
      • 此外,在添加多线程同步前,这部分的CPU还是1-2核占满,线程间阻塞同步的方式降低了一个核以上的CPU占用,但线程同步还存在一部分的CPU占用

 


 
创作不易,如有帮助,请点赞收藏支持
 


[参考文章]
[1].FlameGraph火焰图安装和用法
[2].perf工具简单demo
[3].火焰图分析程序性能
[4].perf工具和+火焰图种类+红蓝差分火焰图的生成等
[5].perf工具基础介绍
[6].perf的基本使用方法
[7].perf使用命令详情, 需要仔细看下
[8].perf和gperftools使用
[9].执行程序时找不到共享库
[10].perf介绍-较全

created by shuaixio, 2024.04.12

  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: perf是一个流行的系统级性能分析工具,它可以帮助用户监测系统资源的使用情况,找出程序的性能瓶颈,提高程序的运行效率。perf具有以下几个特点: 第一,perf可以监控CPU、内存、硬盘I/O、网络等系统资源的使用情况,通过分析这些数据,可以找到程序的瓶颈所在。 第二,perf支持多种测量模式,包括采样模式、跟踪模式、事件计数模式等,方便用户根据自己的需要进行性能分析。 第三,perf可以和其他一些工具结合使用,如火焰、Callgrind等,可以更加直观地展示程序的性能瓶颈,便于用户找到问题。 第四,perf对于内核开发人员也十分有用,可以帮助他们在开发过程中找到内核的性能问题,优化内核代码。 总之,perf是一款功能强大的性能分析工具,可以帮助用户在开发过程中找到程序的性能问题,提高程序的运行效率。 ### 回答2: perf是一款开源的系统级性能分析工具,它可以帮助开发者实现对Linux系统的性能分析和优化。perf可以测量和记录CPU的使用率、缓存的效率、内存的占用、磁盘I/O的读写速度等关键性能指标。 perf具有很强的功能,如事件计数器、系统调用跟踪、板载性能监视器等。使用perf分析工具来优化代码是极为有效的,而且很容易实现。perf的操作简单易学,它使用命令行用户界面,可以轻松地探测出代码中的性能削弱点。 除此之外,perf还提供了分析结果保存、数据可视化和报告生成等功能,这些功能将有助于关键的性能指标的更好的整理和分析perf还支持监视多线程程序,可以帮助开发人员分析并发应用程序的性能瓶颈。 总的来说,perf是一款非常强大的系统级性能分析工具,它可以帮助开发人员进行更加高效、精确地性能分析。相比于其他分析工具,perf性能表现更加稳定,且支持多种类型的分析,因此成为了许多开发人员在Linux系统上进行性能测试和优化的首选工具之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值