perf 常见使用方法
perf的使用场景
1、分析CPU cache、CPU迁移,分支预测、指令周期等各种硬件事件。
2、寻找程序运行过程中的热点函数,做性能分析,从而定位性能问题,具体的做法是对事件进行采样,然后再根据采样数,评估调用流程中各个函数的调用频率。
3、自定义追踪感兴趣的事件。
perf list
列出所有能够出发Perf采样点的事件,类似于ftrace中/sys/kernel/debug/tracing/available_events中包含的事件,但Perf支持的事件比ftrace要多。
perf trace
类似于strace跟踪进程系统调用,相较于strace有更好的性能。
$ perf strace ls? ( ): ls/7996 ... [continued]: execve()) = 00.078 ( 0.004 ms): ls/7996 brk() = 0x556e616e70000.090 ( 0.003 ms): ls/7996 arch_prctl(option: 0x3001, arg2: 0x7ffd2d59b9f0) = -1 EINVAL (Invalid argument)0.130 ( 0.012 ms): ls/7996 access(filename: 0x4895c9e0, mode: R) = -1 ENOENT (No such file or directory)0.154 ( 0.010 ms): ls/7996 openat(dfd: CWD, filename: 0x48959b80, flags: RDONLY|CLOEXEC) = 3
kernel-hook-framework_4.x text_poke yin0.168 ( 0.005 ms): ls/7996 fstat(fd: 3, statbuf: 0x7ffd2d59abf0) = 00.177 ( 0.010 ms): ls/7996 mmap(len: 75723, prot: READ, flags: PRIVATE, fd: 3) = 0x7fae489210000.190 ( 0.003 ms): ls/7996 close(fd: 3) = 00.209 ( 0.007 ms): ls/7996 openat(dfd: CWD, filename: 0x48963e10, flags: RDONLY|CLOEXEC) = 30.221 ( 0.006 ms): ls/7996 read(fd: 3, buf: 0x7ffd2d59ad98, count: 832) = 8320.231 ( 0.003 ms): ls/7996 fstat(fd: 3, statbuf: 0x7ffd2d59ac40) = 0
....
perf start
运行命令并收集性能统计信息。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(void)
{printf("hello, pid=%d\n", getpid());while(1) {printf("begin sleep...\n");sleep(1);}
}
// gcc main.c -o main
$ perf stat ./main
hello, pid=8119
begin sleep...
begin sleep...
begin sleep...
^C./main: InterruptPerformance counter stats for './main':0.84 msec task-clock # 0.000 CPUs utilized 3 context-switches # 3.576 K/sec 1 cpu-migrations # 1.192 K/sec 54 page-faults # 64.373 K/sec 1,364,290 cycles # 1.626 GHz 848,212 instructions # 0.62 insn per cycle 172,372 branches # 205.482 M/sec 8,017 branch-misses # 4.65% of all branches 3.000841844 seconds time elapsed0.001547000 seconds user0.000000000 seconds sys# task-clock:用于执行程序的cpu时间;
# context-switches:程序在运行过程中经历的上下文切换次数;
# page-faults:进程运行过程中产生的缺页次数;
# cpu-migrations:程序在运行过程中发生的CPU迁移次数,即被调度器从一个CPU转移到另外一个CPU上运行;
# instructions:该进程在这段时间内完成的CPU指令数;
# cycles:CPU时钟周期;
perf record
运行命令并将产生的数据写入perf.data文件。
# -p $pid 记录进程pid的events
# -a 采集所有cpu上的events
# -e $event 指定PMU(处理器监控单元)event,默认是cycles:app(cpu周期数)
# -g 启动堆栈/栈回溯功能
# -F $freq 采用频率
# -o $path 指定采样文件输出路径
#include <iostream>
#include <math.h>
#include <sys/types.h>
#include <unistd.h>using namespace std;void for_loop()
{for (int i = 0; i < 1000; i++) {for (int j = 0; j < 10000; j++) {int x = sin(i) + cos(j);}}
}void loop_small()
{for (int i = 0; i < 10; i++) {for_loop();}
}void loop_big()
{for (int i = 0; i < 100; i++) {for_loop();}
}int main(void)
{printf("pid=%d\n", getpid());loop_big();loop_small();return 0;}// g++ test.c -p test
# 使用示例
# 采样时间10,采样频率99,可以采集到约1000个事件
$ perf record -p 10086 -a -g -F 100 --sleep 10
$ perf record -p 10086 -a -g -F 1000 --sleep 10
$ perf record -g -e cpu-clock ./test
perf report
对perf record采样的数据进行分析,可视化显示。
--no-childern:不统计chiledren开销Self:Self记录的是最后一列符号(可以理解为函数)本身采样数占总采样数的百分比,从而找到热点函数Children:记录的是这个符号调用的其他符号(理解为子函数,包括间接调用和直接调用)的采样数之和占总采样数的百分比,从而找到较高层热点函数
perf script
从perf.data读取数据并显示详细的采样信息,一般有多少个时间,就有多少条记录。
perf kmem
跟踪/测量内核内存属性
- record:记录kmem events
–slab:记录slab申请器的events
–page:记录page申请器的events - stat:报告内核内存统计信息
–slab:记录slab申请器的events
–page:记录page申请器的events
perf mem
分析内存访问
perf lock
分析锁的性能
perf kvm
针对kvm虚拟化分析
perf sched
分析内核调度器性能
# record:采集和记录scheduling events
$ perf sched record --sleep 10
$ pref sched record -p 10086 --sleep 10# script:报告采集到的事件
# latency:报告每个任务的调度延迟和进程的其他调度事件
# timehist:提供调度事件分析报告
时间格式:msec.usecwait timetime between sched-out and next sched-in events for the task;task scheduling delaytime between wakeup and actually running;run timerun time for the task;
perf probe
用于自定义添加函数的probe点,可以用perf list来看支持的tracepoint,自定义添加probe点会自动去找内核符号表中的函数,来判断函数是否存在,如果不存在,在添加probe的时候会报错,在内核符号表中找不到需要添加的符号信息,这种方法相较于Kprobe来说免去了驱动编写的过程,提高了效率。
# 查看所有以及注册的probe函数
$ perf probe --list# 添加自定义probe函数
$ perf probe --add submit_bio# 追踪submit_bio probe事件
# -g表示记录函数的调用栈,sleep标志采样事件
# -g enables call-graph recording
# -a, --all-cpus system-wide collection from all CPUs
# -R, --raw-samples collect raw sample records from all opened counters
$ perf record -e probe:submit_bio -aR -g sleep 10# 删除自定义的probe点
$ perf probe --del
简单使用 -g 参数存在大量的Unkown函数,从perf record产生的结果来看,这部分对应的地址大部分是非法地址。
perf 支持集中栈回溯和栈追踪的集中方法,可以添加一下几个参数,详细信息看以下帮助信息:
$ perf record -h
--call-graph <record_mode[,record_size]> //设置栈回溯的方式setup and enables call-graph (stack chain/backtrace):record_mode: call graph recording mode (fp|dwarf|lbr)record_size: if record_mode is 'dwarf', max size of stack recording (<bytes>)default: 8192 (bytes)Default: fp
栈回溯支持三种模式,(fp|dwarf|lbr),默认为fp模式,三种模式的说明:
fp
fp 就是 Frame Pointer,即 x86 中的 EBP 寄存器,fp 指向当前栈帧栈底地址,此地址保存着上一栈帧的 EBP 值,具体可参考此文章的介绍,根据 fp 就可以逐级回溯调用栈。然而这一特性是会被优化掉的,而且这还是 GCC 的默认行为,在不手动指定 -fno-omit-frame-pointer 时默认都会进行此优化,此时 EBP 被当作一般的通用寄存器使用,以此为依据进行栈回溯显然是错误的。不过尝试指定 -fno-omit-frame-pointer 后依然没法获取到正确的调用栈,根据 GCC 手册的说明,指定了此选项后也并不保证所有函数调用都会使用 fp…… 看来只有放弃使用 fp 进行回溯了。
dwarf
dwarf 是一种调试文件格式,GCC 编译时附加的 -g 参数生成的就是 dwarf 格式的调试信息,其中包括了栈回溯所需的全部信息,使用 libunwind 即可展开这些信息。dwarf 的进一步介绍可参考 “关于 DWARF”,值得一提的是,GDB 进行栈回溯时使用的正是 dwarf 调试信息。实际测试表明使用 dwarf 可以很好的获取到准确的调用栈。
lbr
最后 perf 还支持通过 lbr 获取调用栈,lbr 即 Last Branch Records,是较新的 Intel CPU 中提供的一组硬件寄存器,其作用是记录之前若干次分支跳转的地址,主要目的就是用来支持 perf 这类性能分析工具,其详细说明可参考 “An introduction to last branch records” & “Advanced usage of last branch records”。此方法是性能与准确性最高的手段,然而它存在一个很大的局限性,由于硬件 Ring Buffer 寄存器的大小是有限的,lbr 能记录的栈深度也是有限的,具体值取决于特定 CPU 实现,一般就是 32 层,若超过此限制会得到错误的调用栈。
perf 常见使用方法相关推荐
- git原理及常见使用方法
Git 原理入门-来自阮一峰 Git 是最流行的版本管理工具,也是程序员的必备技能之一. 即使天天使用它,很多人也未必了解它的原理.Git 为什么可以管理版本?git add.git commit这些 ...
- ueditor上传图片回调_(常见解决方法)UEditor报错“后端配置项没有正常加载,上传插件不能正常使用”...
(常见解决方法)UEditor报错"后端配置项没有正常加载,上传插件不能正常使用"_向来萧瑟也无畏-CSDN博客blog.csdn.net 报错信息 详见此文的"排错过 ...
- 学JS的心路历程 -数组常见处理方法
昨天我们有提到说for-of和forEach可以用来处理数组,但其实还有很多方法可以更快速及精简代码的达到你要的效果. 话不多说,我们赶紧来看吧! Array.prototype.map() 会回传一 ...
- Android开发环境搭建及常见问题解决方法
Android开发环境搭建及常见问题解决方法 参考文章: (1)Android开发环境搭建及常见问题解决方法 (2)https://www.cnblogs.com/rwxwsblog/p/476978 ...
- python装饰器函数-Python函数装饰器常见使用方法实例详解
本文实例讲述了Python函数装饰器常见使用方法.分享给大家供大家参考,具体如下: 一.装饰器 首先,我们要了解到什么是开放封闭式原则? 软件一旦上线后,对修改源代码是封闭的,对功能的扩张是开放的,所 ...
- 100m和1000m网线的常见制作方法
100m和1000m网线的常见制作方法 100m和1000m网线的常见制作方法: 5类线(100m)的制作: a: 绿白(3).绿(6).橙白(1).蓝(4).蓝白(5).橙(2).棕白(7).棕(8 ...
- PHP几种常见魔术方法与魔术变量解析
PHP几种常见魔术方法与魔术变量解析 先不多说,直接上代码,如下: 1 class Demo 2 { 3 private $str = 'str'; 4 5 //实例化时自动加载function 6 ...
- DL框架之MXNet :神经网络算法简介之MXNet 常见使用方法总结(神经网络DNN、CNN、RNN算法)之详细攻略(个人使用)
DL框架之MXNet :神经网络算法简介之MXNet 常见使用方法总结(神经网络DNN.CNN.RNN算法)之详细攻略(个人使用) 相关文章 DL框架之MXNet :深度学习框架之MXNet 的简介. ...
- DKhadoop安装配置教程与常见问题解决方法
上周分别就DKHadoop的安装准备工作以及服务器操作系统配置写了两篇分享的文章,这是个人第一次尝试写一个系统性的分享文章,必然会有很多疏漏的地方,还望见谅吧.今天分享的是DKHadoop安装以及常见 ...
最新文章
- dhcp报文_动态地址分配DHCP,IP地址管理方式及分配原则,一分钟了解下
- 通过Python的__slots__节省9GB内存
- post基础-百度翻译接口测试
- css button 四种状态,css中按钮的四种状态
- elasticsearch删除索引_一文带您了解 Elasticsearch 中,如何进行索引管理(图文教程)
- linux db2表空间目录,db2 表空间的一些知识
- 前端系统化学习【JS篇】:(二)Javascript、变量和值的简述
- android Tabhost 组件
- 试题4 基础练习 闰年判断
- C#操作mongodb的一些总结
- Windows中字体库的安装方法
- android 反编译去会员,反编译教程
- 移动广告平台Android SDK接入指南
- Euclid最大公因数算法及其扩展求逆元
- 接口测试用例设计:常见问题和风险
- 程序人生 - 如何绘制二维码?
- ASAM XCP及驱动代码、ISO 11898+CANFD,ISO 14229,ISO 15031,ISO 15765相关标准文档
- 怎样做一次好的活动策划?
- Stratifyd入驻腾讯云市场,AI赋能品牌数字化升级
- 【python】opencv教程CV2模块——图片处理,HSV、色调、亮度调节