嵌入式驱动学习第二周——使用perf进行性能优化

前言

   这篇博客来聊一聊如何使用perf进行性能优化。

   嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关注本博主并订阅本专栏,一起讨论一起学习。现在关注就是老粉啦!

目录

  • 前言
  • 1. perf介绍
  • 2. 安装perf
  • 3. perf初探
    • 3.1 perf list使用
    • 3.2 perf record使用
    • 3.3 perf stat使用
    • 3.4 perf top使用
    • 3.5 perf diff使用
    • 3.6 火焰图
  • 4. 实际操作
    • 4.1 生成执行文件并放入设备运行
    • 4.2 生成perf.data文件
    • 4.3 生成火焰图
  • 5. 问题
  • 参考资料

1. perf介绍

   perf可以在CPU Usage增高的节点上找到具体引起CPU增高的函数,之后就可以有针对的聚焦那个函数做分析。

   举例来说,使用 Perf 可以计算每个时钟周期内的指令数,称为 IPC,IPC 偏低表明代码没有很好地利用 CPU。Perf 还可以对程序进行函数级别的采样,从而了解程序的性能瓶颈究竟在哪里等等。Perf 还可以替代 strace,可以添加动态内核 probe 点,还可以做 benchmark 衡量调度器的好坏。

2. 安装perf

   详见博主的另一篇博客,里面记录了ubuntu下和嵌入式系统重perf的安装过程,按照流程来是可以正常安装成功的:perf的安装与迁移

3. perf初探

3.1 perf list使用

   perf list可以列出所有的采样事件。

perf list

在这里插入图片描述

   至此,我们了解到event都有哪些类型,即每行最后[]中的内容,最主要的是三个event,如下所示:

Hardware event: 由PMU(电源管理单元,具有许多与普通计算机相似的组间,包括固件和软件,存储器,CPU,输入/输出功能)产生,如L1缓存命中等,当想了解程序对硬件特性的使用情况时,就可以对这些事件采样。
  
Software event: 由内核产生的事件,如进程切换等
  
Tracepoints event: 由内核静态跟踪点所触发的事件,这些tracepoint用来判断程序运行期间内核的行为细节,如slab分配器的分配次数等

3.2 perf record使用

   perf record命令可以用来采集数据,并把数据写入数据文件中,随后可以通过perf report命令对数据文件进行分析。

   具体有什么用呢?举例来说明。比如说我们已经断定目标程序计算量较大,也许是因为有些代码写的不够精简。那么面对长长的代码文件,究竟哪几行代码需要进一步修改呢?这便需要使用 perf record 记录单个函数级别的统计信息,并使用 perf report 来显示统计结果(perf record表示记录到文件,perf top直接会显示到界面)。

   perf record常用选项如下所示:

-e: 选择一个事件,可以是硬件事件也可以是软件事件
-a: 全系统范围的数据采集
-p: 指定一个进程的ID来采集特定进程的数据
-o: 指定要写入采集数据的数据文件
-g: 使能函数调用图功能
-C: 只采集某个CPU的数据

   同时还可以使用grep来使用程序名监控程序

perf record -e event -g -p grep your_program

   perf record常用选项如下所示:

-i: 导入的数据文件名称,默认为perf.data
-g: 生成的函数调用关系图
--short: 分类统计信息,如PID、COMM、CPU

   在使用上,可以先用perf record指令保存信息到perf.data中,在用perf report指令输出record的结果。

perf record -a -p -F 99 -- sleep 10
perf report

   最后的结果如图所示:

在这里插入图片描述

3.3 perf stat使用

   当我们接到一个性能优化任务时,最好采用自顶向下的策略。先整体看看该程序运行时各种统计事件的汇总数据,再针对某些方向深入处理细节。

  有些程序运行的慢是因为计算量太大,起多数时间在使用CPU进行计算,这类程序叫CPU-Bound型;而有些程序运行的慢是因为过多的I/O,这时其CPU利用率应该不高,这类程序叫I/O-Bound型。这二者之间的调优是不同的。

   perf stat选项,可以在终端上执行命令时收集性能统计信息

   该指令的选项如下所示:

-a: 显示所有CPU上的统计信息
-c: 显示指定CPU上的统计信息
-e: 指定要显示的事件
-p: 指定要显示的进程ID

   我们在本地跑一个进程,这个程序是一直向终端打印hello world,我们使用ps aux查看进程

ps aux

在这里插入图片描述

   可以看到我们刚刚运行的hello的线程号是86

   然后我们利用perf stat可以查看进程的相应信息,输入后还需要输入ctrl+c杀死进程

perf stat -p 86
ctrl+c(键盘上按这两个键)

在这里插入图片描述

  • task-clock(msec) 是指程序运行期间占用了xx个的任务时钟周期,单位为毫秒,该值高就说明程序的多数时间花费在CPU计算上而非IO
  • context-switches是指程序运行期间发生了xx次上下文切换,记录了程序运行过程中发生了多少次进程切换,频繁的进程切换应该是避免的(进程与进程间,内核态与用户态之间)
  • cpu-migrations是指程序运行期间发生了xx次CPU迁移,即用户程序原本在一个CPU上运行,后来迁移到另一个CPU
  • page-faults是指程序发生了xx次页错误
  • cycles:消耗的处理器时钟数,一条机器指令可能需要多个cycles
  • Instructions:机器指令数目,表示执行了多少条指令,IPC平均为每个CPU时钟周期执行了多少条指令
  • branches: 遇到的分支指令数
  • branch-misses: 预测错误的分支指令数
  • 其他可以控制的譬如分治预测、cache命中等

3.4 perf top使用

   该指令用于实时显示当前系统的性能统计信息。该命令主要用来观察整个系统当前的状态,比如可以通过查看该命令的输出来查看当前系统最耗时的内核函数或某个用户进程

perf top

在这里插入图片描述

   该指令可以看出进程中哪个函数消耗资源比较多

第一列显示给定函数正使用的CPU百分比
第二列显示使用函数的程序或库的名称
第三列显示函数名称或符号,内核空间中执行的功能由[k]标识,用户空间中执行的功能则用[.]标识

   此外 perf top 还有常见的选项,如下所示:

-e: 指定要分析的性能事件
-p: 仅分析目标进程
-k: 指定带符号表信息的内核映像路径
-K: 不显示内核或者内核模块的符号
-U: 不显示属于用户态程序的符号
-g:显示函数调用关系图

3.5 perf diff使用

   当多次perf record后,当前路径会生成一个perf.dataperf.data.old文件,分别表示本次和上次的record记录,如果要看二者之间的区别,对比优化结果,那么可以使用perf diff指令

sudo perf diff perf.data perf.data.old

3.6 火焰图

   需要去github下载分析脚本

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

   下载下来后,先使用perf record生成perf.data文件,例如输入如下指令

sudo perf record -e cpu-clock -g -p 10465

   之后会根据perf.data进行解析,生成perf.unfold文件

perf script -i perf.data &> perf.unfold

   将perf.unfold中的符号进行折叠,生成perf.folded

FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded

   最后生成svg图

FlameGraph/flamegraph.pl perf.folded > perf.svg

   也可以用参数-width-height来指定每一条的宽度和高度

FlameGraph/flamegraph.pl perf.folded > perf.svg -width 1000 -height 10

在这里插入图片描述

   生成的火焰图,宽度越大表示CPU耗时越多

4. 实际操作

4.1 生成执行文件并放入设备运行

   接下来进行一段代码实战,来感受一下实际过程中如何查看代码性能并定位。

   首先在Ubuntu上写测试代码test.cpp,如下所示,即多加几个循环,foo()中调用bar()do_main()调用foo(),最后在while(1)中调用do_main()。由代码可以看出来,foo()循环时间要长一些,因此理应在该函数的时间最长,其次是bar()

#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
using namespace std;

void bar(){
  for(int i=0;i< 4000;i++)
  {

  }
}

void foo(){
  for(int i=0;i< 5700;i++)
  {
      
  }      
  bar();
}

void do_main() {
  foo();
}

int main(int argc,char** argv){
    while(1)
    {
        do_main();
        // cout << "hello" << endl;
    }
}

   然后使用编译链编译该cpp文件

g++ Desktop/test.cpp -o Desktop/testLinux

   然后我们在后台运行起这个文件

.Desktop/testLinux &

4.2 生成perf.data文件

   首先查看进程号

ps -xu | grep testLinux

在这里插入图片描述

   可以使用perf top 实时查看一下

sudo perf top -e cpu-clock -p 4502

在这里插入图片描述

   可以看到foo()函数占用的时间最多,其次是bar(),和我们最初的想法一致。按下ctrl+c即可退出返回至控制台

   下面来生成perf.data文件

perf record -e cpu-clock -g -p 4502

   使用report查看

perf report

在这里插入图片描述

4.3 生成火焰图

   解析perf.data文件

perf script -i perf.data &> FlamGraph/result/perf.unfold

   将unfold文件的字符进行压缩

FlameGraph/stackcollapse-perf.pl FlamGraph/result/perf.unfold &> FlamGraph/result/perf.folded

   生成火焰图

FlameGraph/flamegraph.pl FlamGraph/result/perf.folded > FlamGraph/result/perf.svg

   结果如下所示:

在这里插入图片描述

   火焰图上面是bar(),然后其组成了foo()的全部,如果我们要优化代码的话可以从这两个函数下手。

5. 问题

  1. 问题:输入perf record指令后且没有指定sleep时间,进程一直在阻塞状态
    解决:按下ctrl+c,即可生成perf.data文件

  2. 问题:执行FlameGraph/flamegraph.plFlameGraph/stackcollapse-perf.pl的过程中出问题
    解决:使用chmod 777 将这两个文件的权限改一下

  3. 问题:最后生成的svg中,文字显示failed to open perf.data: Permission denied
    在这里插入图片描述

    解决:将perf.data文件用chmod 777 修改一下权限

参考资料

[1] perf性能分析工具使用分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/444240.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

考研复习C语言初阶(4)+标记和BFS展开的扫雷游戏

目录 1. 一维数组的创建和初始化。 1.1 数组的创建 1.2 数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 2. 二维数组的创建和初始化 2.1 二维数组的创建 2.2 二维数组的初始化 2.3 二维数组的使用 2.4 二维数组在内存中的存储 3. 数组越界 4. 冒泡…

HarmonyOS NEXT应用开发之MpChart图表实现案例

介绍 MpChart是一个包含各种类型图表的图表库&#xff0c;主要用于业务数据汇总&#xff0c;例如销售数据走势图&#xff0c;股价走势图等场景中使用&#xff0c;方便开发者快速实现图表UI。本示例主要介绍如何使用三方库MpChart实现柱状图UI效果。如堆叠数据类型显示&#xf…

FPGA的配置状态字寄存器Status Register

目录 简介 状态字定义 Unknown Device/Many Unknow Devices 解决办法 一般原因 简介 Xilinx的FPGA有多种配置接口&#xff0c;如SPI&#xff0c;BPI&#xff0c;SeletMAP&#xff0c;Serial&#xff0c;JTAG等&#xff1b;如果从时钟发送者的角度分&#xff0c;还可以…

2024/3/10周报

文章目录 摘要Abstract文献阅读题目问题创新点方法Section1&#xff1a;运动员检测Section2&#xff1a;行为识别输入层隐藏层输出层 实验实验数据评估指标模型设置实验结果 深度学习模糊逻辑系统概念模糊化模糊规则解模糊 总结 摘要 本周阅读了一篇关于基于YOLO和深度模糊LST…

131.分割回文串

// 定义一个名为Solution的类 class Solution {// 声明一个成员变量&#xff0c;用于存储所有满足条件的字符串子序列划分结果List<List<String>> lists new ArrayList<>(); // 声明一个成员变量&#xff0c;使用LinkedList实现的双端队列&#xff0c;用于临…

【Objective -- C】—— 自引用计数

【Objective -- C】—— 自引用计数 一. 内存管理/自引用计数1.自引用计数2.内存管理的思考方式自己生成的对象&#xff0c;自己持有非自己生成的对象&#xff0c;自己也能持有不再需要自己持有的对象时释放无法释放非自己持有的对象 3.alloc/retain/release/dealloc实现4. aut…

力扣--滑动窗口438.找到字符串中所有字母异位词

思路分析&#xff1a; 使用两个数组snum和pnum分别记录字符串s和p中各字符出现的次数。遍历字符串p&#xff0c;统计其中各字符的出现次数&#xff0c;存储在pnum数组中。初始化snum数组&#xff0c;统计s的前m-1个字符的出现次数。从第m个字符开始遍历s&#xff0c;通过滑动窗…

《YOLO5Face: Why Reinventing a Face Detector》为什么要重塑人脸检测器论文阅读

正好周末的时间天气也不错出去走走精神不错&#xff0c;回来读一篇论文这个论文之前查资料的时候看到的但是没有完整看下&#xff0c;今天正好花点时间整体看一下&#xff0c;下面是我自己阅读过程中使用翻译软件结合自己理解的阅读记录&#xff0c;感兴趣的话可以看下&#xf…

知识图谱 | 2023年图书馆学、情报学CSSCI期刊论文主题透视

数据来源 检索平台来源期刊年份有效数据中国知网大学图书馆学报国家图书馆学刊情报科学情报理论与实践情报学报情报杂志情报资料工作数据分析与知识发现图书馆建设图书馆论坛图书馆学研究图书馆杂志图书情报工作图书情报知识图书与情报现代情报信息资源管理学报中国图书馆学报2…

性能测试高阶内容:了解TPS和RT之间关系

引言 在开始今天的内容讲解之前&#xff0c;我们应该回顾一下&#xff0c;在我的全链路压测专栏中的第一篇&#xff0c;我就已经介绍了当前的性能测试在互联网企业中的重要性&#xff0c;已经性能在互联网行业中的占比是多少。 这个时候是不是会有同学问我&#xff0c; 你已经…

JVM-1

目录 1.基础知识 1.栈 2.本地方法栈 3.程序计数器 4.堆 5.方法区 6.JVM内存可见性 2.虚拟机类加载机制 1.加载 2.验证 3.准备 4.解析 5.初始化 6.使用 7.卸载 1.基础知识 JVM内存模型&#xff08;5种&#xff09;&#xff1a;栈&#xff0c;本地方法栈&#xff…

Java项目:44 ssm003在线医疗服务系统+jsp(含文档)

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 主要功能 前台登录&#xff1a; 注册用户&#xff1a;用户名、密码、姓名、联系电话 注册医生&#xff1a;医生工号、密码、医生姓名、职称、联系电话…

【Python】专栏文章索引

为了方便 快速定位 和 便于文章间的相互引用等 作为一个快速准确的导航工具 Python 目录&#xff1a; &#xff08;一&#xff09;装饰器函数 &#xff08;二&#xff09;牛客网—软件开发-Python专项练习 &#xff08;三&#xff09;time模块

数据结构与算法第三套试卷

1.删除链表节点 **分析&#xff1a;**首先用指针变量q指向结点A的后继结点B&#xff0c;然后将结点B的值复制到结点A中&#xff0c;最后删除结点B。 2.时间复杂度的计算 **分析&#xff1a;**当涉及嵌套循环的时候&#xff0c;我们可以直接分析内层循环即可&#xff0c;看内…

猫头虎分享已解决Bug || 批处理错误:BatchJobFailure, ProcessingDelay

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

太阳辐射环境模拟系统系统

太阳辐射环境模拟系统是一种高度专业化的设备&#xff0c;用于模拟太阳光的全谱段辐射&#xff0c;包括紫外线、可见光和红外线。这种系统的核心功能是在实验室条件下复制太阳的辐射条件&#xff0c;以评估材料、产品或设备在实际太阳辐射影响下的性能和耐久性。 应用领域&…

“比特币深夜冲破7万美元”!华尔街押注比特币:究竟是牛市墙头草,还是加密真信徒?

比特币ETF&#xff0c;使此次加密牛市与以往的繁荣、萧条周期截然不同。以往的周期往往由热衷风险的投机者以及最终崩盘的加密项目所驱动&#xff0c;例如无实物资产支持的加密货币借贷&#xff0c;以及一地鸡毛的ICO热潮。而现在&#xff0c;传统金融已经与加密世界联姻&#…

前端手册-实现挂坠灯笼效果

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

专题一 - 双指针 - leetcode 202. 快乐数 | 简单难度

leetcode 202. 快乐数 leetcode 202. 快乐数 | 简单难度1. 题目详情1. 原题链接2. 基础框架 2. 解题思路1. 题目分析2. 算法原理3. 时间复杂度 3. 代码实现4. 知识与收获 leetcode 202. 快乐数 | 简单难度 1. 题目详情 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」…

linux守护程序

概述 周末还要加班写代码&#xff0c;偷个懒发个刚刚写的守护进程&#xff0c;有一个小bug懒得处理&#xff0c;急着要用&#xff0c;发出来记录一下成果。 守护程序 网上很多介绍的&#xff0c;大家有兴趣自己去查查 上酸菜 #include <stdio.h> #include <stdli…