301 lines
12 KiB
Markdown
301 lines
12 KiB
Markdown
## 背景
|
||
|
||
linux性能监测主要是关于Linux系统上程序的性能跟踪。
|
||
|
||
**前排提示**: 如果你只想要一个可监测linux性能的工具,并且有可视化的web,并且开源且持续更新,那么你可以查看 [Performance Co-Pilot](https://link.segmentfault.com/?enc=I8PbLahWDovcH2lDY1AzRw%3D%3D.Rp26m8avBzRv%2BendMImpEALexFgfk7xCQMe2M%2B1z8bKyvClWxAoKbSUDyEFWrE8D),比较不错。如果你需要更深入的了解linux性能监测,或者希望降低监测所带来的性能消耗,那么可以往下看。
|
||
|
||
从广义上讲, linux跟踪系统由三层组成
|
||
|
||
- 信息源
|
||
- 对接信息源的追踪框架
|
||
- 前端操作界面
|
||
|
||

|
||
|
||
## 信息源(event_sources)
|
||
|
||

|
||
|
||
**事件源是性能监测的基础**,**是跟踪数据的来源**,跟踪框架运行在内核中,负责数据收集、计数。
|
||
|
||
信息源主要分为以下三类:
|
||
|
||
1. 硬件事件
|
||
2. 静态探针
|
||
3. 动态探针
|
||
|
||

|
||
|
||
### 1.硬件事件
|
||
|
||
**性能监控计数器(PMCs**)是处理器上的可编程硬件计数器,用于测量处理器中发生的事件。
|
||
|
||
**PMCs是CPU自带的功能**,因此能得到最底层的、用别的手段得不到的性能信息,例如只有通过PMC才能测量CPU指令执行的效率、CPU缓存命中率、内存/数据互联和设备总线的利用率,以及阻塞的指令周期等。
|
||
|
||
由于硬件事件比较底层的,我们性能监测的时候,一般很少从此处获取可优化的数据。
|
||
|
||
### 2. 静态事件
|
||
|
||
#### 2.1 内核跟踪点(tracepoints)
|
||
|
||
即linux内核源代码中预先定义的跟踪点。
|
||
|
||
linux源码中,**有很多以 trace_ 开头的函数**, 这些都是是linux中预定义好的跟踪点。
|
||
|
||
int netif_receive_skb(struct sk_buff *skb)
|
||
|
||
{
|
||
|
||
trace_netif_receive_skb_entry(skb); // 调用netif_receive_skb对应的trace event函数
|
||
|
||
return netif_receive_skb_internal(skb);
|
||
|
||
}
|
||
|
||
如想查看这些 trace_ 开头的函数, 可到 `/sys/kernel/debug/tracing/`下查看
|
||
|
||
#### 2.2 USDT探针
|
||
|
||
USDT探针(User Statically-Defined Tracing)全称是用户级静态定义跟踪,需要在源码中插入 DTRACE_PROBE() 代码,并编译到应用程序中。这里不做详述。
|
||
|
||
### 3 动态探针
|
||
|
||
顾名思义,则是指没有事先在代码中定义,但却**可以在运行时动态添加的探针**(重点是不需要重新编译目标程序)。主要由kprobe(内核探针)和uprobe(用户态探针)组成。
|
||
|
||
#### 3.1 内核探针kprobes
|
||
|
||
kprobes(Kernel Dynamic Probes)。一种提供**内核函数动态跟踪**的 Linux 内核技术。
|
||
|
||
本质: **是在指定的探测点**(比如函数的某行, 函数的入口地址和出口地址, 或者内核的指定地址处)**插入一组处理程序**. 内核执行到这组处理程序的时候就可以获取到当前正在执行的上下文信息。
|
||
|
||
详细可查看[An introduction to KProbes](https://link.segmentfault.com/?enc=pWx1IyYTst7XSBCnoHOGUQ%3D%3D.Bh%2FQ%2BthpR863%2BLX2x%2Fn0GCiHdV7zrgDaivy%2FtWfsHQf%2FHCxB4T85A4NeZ4FTOKEi)
|
||
|
||
#### 3.2 用户态探针uprobes
|
||
|
||
一种提供**用户级函数动态跟踪**的 Linux 内核技术
|
||
|
||
详细可查看[Linux uprobe:用户级动态跟踪](https://link.segmentfault.com/?enc=RQResacFYQ84MCxrVW%2FjOQ%3D%3D.kzO2kG3zIhMH8RERHxgShB3gINabhcG63PcbFeKML9HsYCr0y0h63wIXFl3gQPDVDkQ1tmzu1ucvJaaJyARPloCVuTDdjKZVCTTsB5Hrc9E%3D)
|
||
|
||
---
|
||
|
||
总之,只需要了解**信息源主要分为硬件事件,静态探针,动态探针**
|
||
|
||
## 追踪框架
|
||
|
||
先介绍一下这方面的一个大神:[brendangregg](https://link.segmentfault.com/?enc=n4I1R0wLobR7Qm7AdSwR7g%3D%3D.UNXi6JWw%2Fem%2Fjk2NhlSxhJ7GnzYZ9MBnQyo7UEY9PFPilBg1qdGHhhdwuiaEcvF0), 很多编入内核的追踪框架都有他的贡献。
|
||
|
||
以下是他画的一张关于 linux 观察性能工具的一张图。
|
||

|
||
|
||
可以说,linux 的各方面(cpu, 磁盘,调度,网络,io)都有对应的工具。
|
||
|
||
### 基础命令
|
||
|
||
我们可以先用一些基础命令来查看一些基本信息,比如上图中的 top, free等
|
||
|
||
**top命令:**
|
||
|
||

|
||
|
||
**平均负载**:三个值分别为1分钟、5分钟、15分钟前到现在的平均值(根据cpu数量去判断。最佳状态为 平均负载约等于cpu个数)
|
||
|
||
**Cpu(s)**:
|
||
|
||
1. 32.0%us(用户使用cpu占比)
|
||
2. 2.0%sy(系统使用cpu占比)
|
||
3. 0.0%ni(用户空间内改变过优先级的进程占用CPU百分比)
|
||
4. 65.3%id(空闲cpu占比)
|
||
5. 0.1%wa(等待输入输出CPU时间百分比)
|
||
6. 0.1%hi(CPU服务于硬件中断所耗费的时间总额)
|
||
7. 0.5%si(CPU服务软中断所耗费的时间总额)
|
||
8. 0.0%st(Steal Time)
|
||
|
||
**Mem:**
|
||
|
||
1. total(物理内存总量)
|
||
2. used(已使用的物理内存)
|
||
3. free(剩余的物理内存)
|
||
4. buffers(缓冲区内存)
|
||
|
||
**free 命令:**
|
||

|
||
|
||
free命令显示内存的使用信息。默认按照k(b)的计数单位统计。也可以 -m 显示单位为 MB。更多参数可以查看 man free
|
||
|
||
**iostat命令:**
|
||
iostat主要用于监控系统设备的IO负载情况。 可以获取io读写的速度等信息。 更多参数可以查看 man iostat
|
||
|
||

|
||
|
||
---
|
||
|
||
**其实 top, free, iostat 等一些命令,** **实质上都是通过读取 linux 的 /proc/ 文件夹下的文件 来实现数据报告**。
|
||
|
||
例如
|
||
|
||
> **/proc/cpuinfo** : cpu的硬件信息,如型号、速率、核数、cache大小等
|
||
>
|
||
> **/proc/meminfo**:内存的信息,如内存总量、free空间、swap空间
|
||
>
|
||
> **/proc/stat:** 所有的CPU活动状态的信息
|
||
>
|
||
> **/proc/diskstats** :磁盘信息
|
||
>
|
||
> **/proc/loadavg** : 根据过去一段时间内CPU和IO的状态得出的负载状态
|
||
|
||

|
||
|
||
所以,**直接 cat 相应的文件无疑也是个好方法**
|
||
|
||
### 框架
|
||
|
||
在来说说框架
|
||
|
||

|
||
在这张图的左边,列出了比较常用的框架
|
||
|
||
1. perf
|
||
2. ftrace
|
||
3. lttng
|
||
4. BCC
|
||
5. bpftrace
|
||
|
||
当然也有更多:
|
||

|
||
|
||
这是 brendangregg 大神在2015年的一篇文章 [选择 Linux 跟踪器](https://link.segmentfault.com/?enc=Nzqzn3IgCMDSw6e9AmmCoA%3D%3D.GDOSgy0GFBKOaZvOTaCc9sj8ccmsaTJTol6vHs%2F6RLDlGBLtXfOm3PETHRsutr4nuK66DYDxTB2XRPnjs50FZmXYq2ae9EiVs70%2BYZ%2FGhdU%3D) 到今日也有一定的参考价值。
|
||
|
||
博主本人比较推荐了解以下框架:
|
||
|
||
1. ftrace (内置在Linux内核中),比较经典
|
||
2. perf (来源位于 Linux 内核中,通常通过 linux-tools-common 包添加)
|
||
3. bpftrace (持续开源更新中)
|
||
|
||
以下是相关这三个工具的了解
|
||

|
||
|
||
### ftrace
|
||
|
||
ftrace 在/sys/kernel/debug/tracing 位置上, 构建了一个文件系统,用户通过读写文件的方式来使用ftrace。
|
||
|
||
一切皆文件 的哲学在这里体现的淋漓尽致。
|
||
|
||
操作步骤:
|
||
|
||
#1、进入debugfs目录
|
||
$ cd /sys/kernel/debug/tracing
|
||
#如果找不到目录,执行下列命令挂载debugfs:
|
||
$ mount -t debugfs nodev /sys/kernel/debug
|
||
#2、查询支持的追踪器
|
||
$ cat available_tracers
|
||
#常用的有两种:
|
||
#
|
||
#- function 表示跟踪函数的执行;
|
||
#- function_graph 则是跟踪函数的调用关系;
|
||
#3、查看支持追踪的内核函数和事件。其中函数就是内核中的函数名,而事件,则是内核源码中预先定义的跟踪点。
|
||
#//查看内核函数
|
||
$ cat available_filter_functions
|
||
#//查看事件
|
||
$ cat available_events
|
||
#4、设置追踪函数:
|
||
$ echo do_sys_open > set_graph_function
|
||
#5、设置追踪器
|
||
$ echo function_graph > current_tracer
|
||
$ echo funcgraph-proc > trace_options
|
||
#6、开启追踪
|
||
$ echo 1 > tracing_on
|
||
#7、执行一个 ls 命令后,再关闭跟踪
|
||
$ ls
|
||
$ echo 0 > tracing_on
|
||
#8、最后一步,查看跟踪结果
|
||
$ cat trace
|
||
|
||
例如,我们上面的代码执行了如下步骤:
|
||
1 .跟踪了 `do_sys_open` 这个系统函数
|
||
|
||
2. 我们设置跟踪器为 `function_graph`
|
||
3. 开启跟踪
|
||
4. 执行ls命令,因为该命令会调用 `do_sys_open` 这个系统函数
|
||
5. 查看跟踪结果是否跟踪到这个函数
|
||
|
||

|
||
|
||
查看该跟踪结果, 可以查看 执行该命令的CPU, cmd, pid. 执行事件,调用栈。
|
||
|
||
从而函数的调用栈和调用时间,可分析出该进程在哪个函数上耗费的时间较多。
|
||
|
||
一顿操作下来,是不是感觉有点麻烦?
|
||
所以,我们后续可以尝试一下 ftrace的命令行版: trace-cmd, 亦或是 集成有 ftrace 的 perf_tools。
|
||
|
||
### perf
|
||
|
||
perf 这个工具原理比较简单,而且生成的火焰图,可迅速分析 函数的热点, 非常推荐使用,而且perf工具非常强大,如果用的好基本上可以完全满足应用程序的性能分析和调优工作的需求。
|
||
|
||
#### 原理
|
||
|
||

|
||
|
||
原理:**每隔一个固定时间(取决于采样率),看当前是哪个进程、哪个函数**,**然后给对应的进程和函数加一个统计值**,这样就知道CPU有多少时间在某个进程或某个函数上了
|
||
|
||
当 80% 的采样都落在 func1时, 我们大概率可以得出: 函数热点在 func1上。
|
||
|
||
同时我们也可以得出:**采样率越大,结果越精确**
|
||
|
||
**perf top命令:**
|
||
适合监控整个系统的性能
|
||
|
||
$ perf top --call-graph fractal
|
||
|
||

|
||
|
||
**perf stat命令:**
|
||
|
||
比较适合单个程序的性能分析
|
||
|
||
`$ sudo perf stat ls -lt`
|
||
|
||

|
||
|
||
**perf record/report:**
|
||
record/report 更适合对程序进行更细粒度的分析
|
||
|
||
#在当前目录生成perf.data文件
|
||
|
||
sudo perf record -a -g -p <pid>
|
||
|
||
#结果显示
|
||
|
||
sudo perf report
|
||
|
||

|
||
|
||
可以获取该进程的热点在哪个函数。
|
||
|
||
**火焰图:**
|
||
|
||
perf 结合 brendangregg 大神开发的 [火焰图工具](https://link.segmentfault.com/?enc=GeoHegINlCXdcGX4KUOaEw%3D%3D.RXciMNuqy7Be9Hdgsh5mmWqMYcMbhITRUqgLxScD%2BF9DyWv4gPZOp1dr%2Bxg6bH93)
|
||
|
||
可以在如下链接看看效果:
|
||
|
||
[https://www.brendangregg.com/FlameGraphs/example-perf.svg](https://link.segmentfault.com/?enc=R1ZgIG5LgTDCfHRj5lAGYg%3D%3D.RJM2xvK%2B5z1gGxmmCWdIJtJUrthxFAIJ9Xmy6xmhDt%2BUvgVg%2BE8D9yVo6oMnGu2aEzftVXv1TdZwENdwj7YJCw%3D%3D)
|
||
|
||
当某一长块占下方长块大部分长度时,该长块所代表的函数就是该进程的cpu热点。
|
||
|
||
### bpftrace
|
||
|
||
开源并持续更新的仓库,可以看看。
|
||
[bpftrace github仓库](https://link.segmentfault.com/?enc=DIdHI6Oy2U1SqkLV61Lb0Q%3D%3D.GNfaefztZX%2Fi3g01ChGPqkw%2FVoHWzTcplGYJ75oVQipxaE9xJwqc3Oa4WsblXZN0)
|
||
|
||
## 总结
|
||
|
||
可以按自己需求选择需要自己需要的工具。
|
||
|
||
希望内容可以帮助到一些人。
|
||
|
||
参考:
|
||
[https://leezhenghui.github.io/linux/2019/03/05/exploring-usdt...](https://link.segmentfault.com/?enc=y5fC2NVDakGEtGWSCaOR6w%3D%3D.IMtuAi5iXo2OrNmyhd4ojMAWPsXjs429urlZe9q56v9HHR8G9HKuraMVT%2FXqifCBbxW4BsvPLion7uOVH419BROqYpS5pQHGhnz3ReRy8cA%3D)
|
||
[https://www.brendangregg.com/index.html](https://link.segmentfault.com/?enc=yUkOSWeJ3X%2Fb%2F8uTB0mMNg%3D%3D.nsqfWFD8kKMzdQu9dKao%2Fuvhn3q%2B5S75iX0mvhAPb%2BLCX00f6%2BInwDU9BomaHuVE)
|
||
[https://www.brendangregg.com/blog/2015-07-08/choosing-a-linux...](https://link.segmentfault.com/?enc=vzTGAWjOCULAZyajlUctUg%3D%3D.ZXFZAO4i7cr7R%2F4gVXowkNHETTWFCzSvLlPd2Qq1CAS1OwUCj2ktwwoncHFtpS0fddTaNRwakBi%2BS7kT4NYlJKzicwH%2Bb1diE0JeRyDkJew%3D)
|
||
[https://zhuanlan.zhihu.com/p/672872237](https://link.segmentfault.com/?enc=FTig72OfaU5CkdyGHLCOEA%3D%3D.2uHpKmD6bDeAgu5XKltM0RtD9KB8Wnq96DUCzvsRaNGHmj1IgGNj1fJSTb8kH9gS)
|
||
|
||
[linux](https://segmentfault.com/t/linux) |