Linux中常用的性能分析工具

news2024/11/19 9:31:30

1 明确目标

进行性能分析时,需要明确优化的目标,例如,是优化整体的性能,还是某个功能的性能。

明确优化目标后就需要能够知道当前的性能瓶颈,性能消耗在什么地方,以及如何去衡量,这样也能够在优化过程中以及优化完成后用相同的方式去衡量效果。

2 基础命令

2.1 基本指标查看

CPU

  • mpstat -P ALL 1:查看CPU的各种状态下的时间,可以用于查找CPU时间分布不均衡的问题
  • pidstat 1:展示进程的CPU使用情况
  • top:查看当前的负载以及占用CPU和内存较高的进程

内存

  • free -m
  • vmstat 1:查看内存、swap、cpu等使用情况

磁盘:

  • df -h:查看磁盘使用情况
  • iostat -xz 1:查看磁盘的读写情况

错误

  • dmesg |tail:查看内核的相关日志
  • grep ERROR /var/log/messages:查看系统和服务的错误信息

其他:

  • sar:用于输出系统行为的信息,例如,sar -w 1可以用于查看创建进程的速度
2.2 线程

上面的命令默认情况下都是查看进程的情况,现在很多程序都是多线程,因此,需要能够查看线程的情况。

  • top -H -p 6666:查看6666进程下面所有线程的cpu和内存情况
  • pidstat -p:后面既可以指定进程ID,也可以指定线程ID

因此,通常的方式是,通过top查看到占用较高的某个线程,然后通过pidstat持续观察该线程的cpu占用情况,如果持续飙高,再通过日志或者代码定位该线程对应的逻辑模块。

3 perf命令

3.1 perf的基本原理

每隔固定时间,CPU产生一个中断,看当前是哪个进程、哪个函数,就更新相应的进程和函数的计数器,通过这种定时采集的方式,就知道CPU有多少时间在某个进程或者某个函数上了。

3.2 基本使用方法
  • perf list:查看可用的采样点
  • perf record:采集程序运行的特征,配合perf script生成trace的数据,然后就可以用于生成火焰图
  • perf top:可以查看函数级别的占用情况
  • perf probe:在可执行文件或者so种插入监测点,然后再通过perf record进行数据采集
3.3 火焰图分析

生成火焰图,除了使用perf工具,还需要生成火焰图的脚本:FlameGraph

然后用下面的方式生成火焰图:

# -F 100表示采样频率,每秒100次
# -p 31955表示对31599进程进行采样
# -g表示记录调用栈
# sleep 180表示总共采样180s
perf record -F 100 -p 31955 -g -- sleep 180
perf script -i perf.data &> perf.unfold
./FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
./FlameGraph/flamegraph.pl perf.folded > perf.svg

然后就可以用浏览器打开perf.svg进行分析。

火焰图的特点:

  • 每个小方块表示一个函数
  • 方块的颜色深浅没有关系,是随机取的颜色
  • 纵轴表示调用栈的深度,调用的方向是从下往上,也就是下面的函数调用了上面的函数,因此,函数越往上则越底层
  • 横轴的宽度表示占用时间,但是从左到右并不表示时间顺序,而只是按照字母表顺序排列

怎么用火焰图查找性能问题呢?

横轴的宽度表示占用时间,因此,方块越宽表示占用时间越多,所以,我们的目的就是找到比较宽的方块。

在最下面找比较宽的方块,当找到一个比较宽的方块时,再在这个方块的上面的方块中找比较宽的方块,这样一步一步往上找,根据代码分析出性能出现问题的地方,然后对这部分代码进行优化。

4 ftrace

内核文档:ftrace - Function Tracer

ftrace提供tracefs的接口供用户使用,4.1内核以前的版本,tracing所有的控制文件都在debugfs中,tracefs通常会挂载到/sys/kernel/debug/tracing,为了向后兼容,新的内核在挂载debugfs时,会同时将tracefs挂载到/sys/kernel/debug/tracing和/sys/kernel/tracing。

  • current_tracer:当前使用的tracer
  • available_tracers:可用的tracer类型
  • tracing_on:打开(1)和关闭(0)tracer
  • trace & trace_pipe:两个文件都可以查看tracer采集的数据,但是trace是个静态的文件,每次读取该文件展示的都是当前缓冲区中的数据,而trace_pipe是个动态的文件,每次读取只能读取到新的数据,已经读取的数据不会被输出
  • trace_options:控制数据采集的选项,例如,数据的展示和tracer的工作方式
  • options/:可用的选项,可以通过修改下面的文件控制,也可以将文件名写入trace_options控制
  • kprobe_events:开启kprobe_events
  • uprobe_events:uprobe tracers
  • uprobe_profile:
  • events/:所有的监测点,按照分组进行组织
  • available_events:可用的events,将上面events目录中的所有文件都列在这里
  • trace_marker:
4.1 Tracers
  • function:可以用于监测所有的内核函数
  • function_graph:function类型的tracer只是在函数的入口添加监测点,而function_graph类型的tracer会在函数的入口和出口添加监测点,可以用于绘制函数调用关系图
  • blk:块设备的检测点,被blktrace命令使用
  • hwlat:用于检测硬件是否有延迟
4.2 perf-tools

从上面可以看到,ftrace基本就是通过tracefs提供操作的接口,但是里面的目录和文件又很多,而某个功能其实一般也只用到了几个文件而已,为了方便对某个功能的使用,perf-tools用shell脚本的方式对这些功能进行了封装,可以通过命令的方式使用。

用例1:uprobe

uprobe脚本可以对用户态的程序添加监测点:./uprobe 'p:/lib64/libdl-2.28.so:dlopen +0(%di):string'对libdl-2.28.so里面的dlopen添加监测点,当系统中有程序使用dlopen调用so时,就会打印一个事件,表明某个程序调用了dlopen,并且调用的so的路径。

用例2:kprobe

kprobe脚本可以对内核的函数添加监测点,可以添加监测点的函数列表位于/sys/kernel/debug/tracing/available_filter_functions中。使用./kprobe 'p:do_sys_open filename=+0(%si):string'可以监测open系统调用,并且打印出文件名。

用例3:tracepoint

tpoint脚本可以列出内核现在的tracepoint,然后进行监测。使用./tpoint syscalls:sys_enter_openat可以打印有哪些进程在调用打开文件。

4.3 日常使用

使用日志进行性能分析时,除了使用火焰图从整体上看时间的分布,经常会有需要看某个函数占用的耗时。

perf-tools中的funcgraph脚本可以监测到函数从进入到出来的耗时,但是该功能只能对内核函数使用,无法对用户态使用。

5 再看perf probe

perf probe可以操作监测点,执行perf probe -x /lib64/libdl-2.28.so 'dlopen\@\@GLIBC_2.2.5'可以增加监测点probe_libdl:dlopen,然后通过perf record -e probe_libdl:dlopen -a -- sleep 5可以采集dlopen的调用。

然后执行perf script可以直接查看采集到的数据:

请添加图片描述

通过对perf probe进行strace发现,它也是通过操作ftrace中的tracefs实现的。

请添加图片描述

perf也对ftrace进行了简单的封装,提供了perf ftrace命令,可以通过perf ftrace进行内核函数监测,使用命令perf ftrace -p 53901 -t function -T do_sys_open监测某个进程对open系统调用的情况。

6 perf_event_open

使用perf probe只是增加监测点,但是要获取实际的数据,就需要通过perf record命令,而perf record就是使用perf_event_open进行数据的获取。

下面是perf_event_open中的示例程序,用于统计printf的指令的数量:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>

// hw_event:perf_event_attr的指针
// pid:要进行trace的进程
// cpu:要进行trace的cpu
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                            int cpu, int group_fd, unsigned long flags) {
    int ret;

    ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
    return ret;
}

int main(int argc, char **argv) {
    struct perf_event_attr pe;
    long long count;
    int fd;

    memset(&pe, 0, sizeof(struct perf_event_attr));
    pe.type = PERF_TYPE_HARDWARE; // 指定事件类型
    pe.size = sizeof(struct perf_event_attr);
    pe.config = PERF_COUNT_HW_INSTRUCTIONS; // 失效指令?
    pe.disabled = 1; // 默认关闭,后续可以通过ioctl或者prctl进行开启
    pe.exclude_kernel = 1; // 忽略内核空间的事件
    pe.exclude_hv = 1; // 忽略hypervisor的事件

    // pid=0,表示对当前进程进行trace
    // cpu=-1,表示对所有cpu进行trace
    fd = perf_event_open(&pe, 0, -1, -1, 0);
    if (fd == -1) {
        fprintf(stderr, "Error opening leader %llx\n", pe.config);
        exit(EXIT_FAILURE);
    }

    // 通过ioctl控制perf_event的运行
    // PERF_EVENT_IOC_RESET:重置事件的统计值
    // PERF_EVENT_IOC_ENABLE:启用事件
    ioctl(fd, PERF_EVENT_IOC_RESET, 0);
    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

    // 执行printf,这次统计的就是该printf的指令数量
    printf("Measuring instruction count for this printf\n");

    // PERF_EVENT_IOC_DISABLE:停用事件
    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);

    // 读取统计值
    read(fd, &count, sizeof(long long));

    printf("Used %lld instructions\n", count);

    close(fd);
}

通过上面的示例可以看出,整个逻辑不复杂,就是通过perf_event_open打开一个fd,并且需要告知需要获取的是什么数据,然后通过ioctl开启内核统计,再执行用例并关闭统计,最后调用read读取需要的数据。

因此,这里重要的是:我们需要获取什么数据,然后对应到perf_event_attr中的type和config。

上面的代码只是对某个事件进行了统计,得到某个事件发生了多少次,这种对应了perf-tools和bcc-tools中的*count工具。但是,有时候我们除了想知道事件发生了多少次,还需要对事件的某个属性进行分类的统计,或者分析函数的调用栈,总之,希望可以得到更多详细的数据。

这被称为“采样”:设定相应的频率/定时时间,当定时时间到,就会收集一些数据,然后进行相应的分析。

在perf_event_attr中有几个跟采样相关的字段:

  • sample_period、sample_freq:采样周期是指多少个事件溢出一次,当溢出时,采集的数据就会放到mmap的buffer中;采样频率则通过时钟中断进行定时采样
  • sample_type:指定要采样的数据,PERF_SAMPLE_TIME(记录时间)、PERF_SAMPLE_READ(记录所有事件的计数)、PERF_SAMPLE_CPU(记录CPU编号)、PERF_SAMPLE_REGS_USER(记录用户态的寄存器的状态)、PERF_SAMPLE_STACK_USER(记录用户态的栈)
  • sample_regs_user:设置要采样的寄存器
  • sample_stack_user:设置要采样的栈大小

用C程序计算C代码执行了多少条机器指令

7 bcc & bpftrace

由于eBPF程序的编写门槛太高,于是就出现了一些高级语言,能够帮助快速编写eBPF程序:

  • bcc:一套工具集,用户可以直接用高级语言(python、C++、lua)编写用户态程序
  • bpftrace:用户可以使用类似awk的方式编写eBPF程序

总之,上述两种方式都是基于eBPF的跟踪工具,bcc可以用于编写复杂逻辑,而bpftrace可以用于快速编写单行程序。

下面的bcc程序用于统计块IO的分布直方图:

#!/usr/bin/env python

from bcc import BPF
from time import sleep

# 定义加载到eBPF虚拟机的内核代码
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/blkdev.h>

struct proc_key_t {
    char name[TASK_COMM_LEN];
    u64 slot;
};

// 定义一个histogram类型的BPF map对象,它的名字为dist
// key的类型为proc_key_t,里面包含进程的名称和计算范围
BPF_HISTOGRAM(dist, struct proc_key_t);

// 定义tracepoint的跟踪点
// block:跟踪块这个类别
// block_rq_issue:要跟踪的函数,这个函数的含义是发起IO请求
// block/block_rq_issue位于/sys/kernel/tracing/events子目录中
// 也可以通过perf list|grep block_rq_issue得到
TRACEPOINT_PROBE(block, block_rq_issue)
{
    // 从bytes参数中得到要读取的数据,然后求log
    struct proc_key_t key = {.slot = bpf_log2l(args->bytes / 1024)};

    // 从内核空间中读取进程名,然后保存到key中
    bpf_probe_read_kernel(&key.name, sizeof(key.name), args->comm);

    // 将刚才计算的值追加到直方图中
    dist.increment(key);
    return 0;
}
"""

# 将上述的内核代码载入,相当于执行bpf_prog_load
b = BPF(text=bpf_text)

print("Tracing block I/O... Hit Ctrl-C to end.")

# trace until Ctrl-C
dist = b.get_table("dist")

try:
    sleep(99999999)
except KeyboardInterrupt:
    # 打印直方图
    dist.print_log2_hist("Kbytes", "Process Name", section_print_fn=bytes.decode)

从上面的例子中,我们知道,要想编写bcc程序,最关键是要知道要跟踪的点以及对获取的数据如何处理。例如,这里的内核代码是跟踪block_rq_issue这个tracepoint,然后根据参数得到对应的数据,再将数据计算后更新map,而在用户代码中只有map的获取和打印逻辑。

下面的代码实现了跟上述代码一样的目的:获取块IO的调用直方图

#!/usr/bin/bpftrace

BEGIN
{
    printf("Tracing block device I/O... Hit Ctrl-C to end.\n");
}

tracepoint:block:block_rq_issue
{
    @[args->comm] = hist(args->bytes);
}

END
{
    printf("\nI/O size (bytes) histograms by process name:");
}
  • BEGIN表示加载完eBPF程序后执行的动作,通常用于打印表头或者提示信息。
  • tracepoint:block:block_rq_issue表示跟踪block:block_rq_issue的tracepoint
  • 当跟踪某个函数时,一个关键的点是,该函数有哪些参数,例如,这里使用的是args->bytes,那么,block_rq_issue是否有其他参数呢?通过bpftrace -vl tracepoint:block:block_rq_issue可以查看该跟踪点的所有参数
  • hist()是一个map函数,输出行以2次方的间隔开始
  • END在跟踪结束后执行

8 关系

上面提到了很多名词,例如,uprobe、kprobe、perf、perf_event_open等,下面对这些词汇的关系进行整理:

请添加图片描述

内核提供的能力:

  • kprobe:动态探针,用于跟踪内核函数
  • uprobe:动态探针,用于跟踪用户态函数
  • tracepoint:静态探针,内核已经预先定义了一些跟踪点,可以通过perf list tracepoint查看
  • usdt:
  • eBPF:扩展的BPF机制

接口层:

  • ftrace:一套trace系统,对用户提供debugfs的接口
  • perf_event_open:系统调用,用于读取内核的统计和采样数据

应用层:

  • perf/perf_events:用于性能分析,FlameGraph
  • trace-cmd:trace-cmd: A front-end for Ftrace
  • perf-tools:基于ftrace的分析工具
  • BCC:基于eBPF的用于开发内核跟踪程序的工具集,能够简化eBPF程序的编写,用户态的语言可以使用python、C++、lua
  • bcc-tools:使用bcc编写的工具
  • bpftrace:基于bcc进行更高层的抽象,能够使用类似于awk的语言快速编写eBPF工具,特别是单行程序

参考文档

  • 译|2008|User-Space Probes (Uprobes)
  • The bpftrace One-Liner Tutorial
  • bpftrace Reference Guide

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二叉树题目:最大二叉树

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;最大二叉树 出处&#xff1a;654. 最大二叉树 难度 5 级 题目描述 要求 给定一个没有重复元素的整数数组 num…

一键操作,高效管理!个微管理系统

在微信日益普及的今天&#xff0c;越来越多的人使用微信进行交流。然而&#xff0c;在工作中&#xff0c;我们往往需要处理大量的消息&#xff0c;手动回复不仅效率低下&#xff0c;还容易出错。还有朋友圈转发&#xff0c;不能一键转发&#xff0c;需要手动保存添加再一个个图…

架构风格区别-架构案例(五十九)

管道-过滤器和仓库的区别&#xff1f; 独立的数据仓库&#xff0c;处理流独立&#xff0c;处理数据用连接仓库工具数据与处理在一起&#xff0c;改动的话需要重启系统需要仓库工具与仓库连接&#xff0c;数据与处理分离&#xff0c;性能差可以支持并发连接访问仓库&#xff0c…

如何判断要不要用振动技术来进行设备预测性维护

在现代工业设备运行过程中&#xff0c;及时发现设备故障并进行维修对于确保生产线的正常运行至关重要。振动分析技术作为一种先进的设备监测和预测性维护方法&#xff0c;通过实时监测和分析设备的振动信号&#xff0c;可以提前发现潜在故障&#xff0c;降低停机时间和维护成本…

最全的图床集合(国内外,站长必备)

“heosu每月不定时更新嗷&#xff0c;防止错过消息推送&#xff0c;建议小伙伴添加到星标⭐喔” 为了减少服务器的压力不少站长还是选择图床存放图片的。所以就搜集一些比较好用的免费的图床&#xff08;收费的在最后标出&#xff09;以及我目前在用的图床。 为什么需要图床&am…

Biotech - 环状 mRNA 的 LNP 递送系统 与 成环框架

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/133992971 环状 RNA&#xff08;或 circRNA &#xff09;是一种单链 RNA&#xff0c;与线性 RNA 不同&#xff0c;形成一个共价闭合的连续环。在环…

如何使用Pritunl搭建OpenVPN服务器,实现远程连接【内网穿透】

文章目录 前言1.环境安装2.开始安装3.访问测试4.创建连接5.局域网测试连接6.安装cpolar7.配置固定公网访问地址8.远程连接测试 前言 Pritunl是一款免费开源的 VPN 平台软件&#xff08;但使用的不是标准的开源许可证&#xff0c;用户受到很多限制&#xff09;。这是一种简单有…

vue 生命周期钩子函数 created()案例

通过发请求来获取数据。在数据响应化之后&#xff0c;dom搭建之前&#xff0c;通过发送axios来获取数据并初始化。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible"…

DFT和ATE岗位前景薪资对比,手把手教你如何选择岗位?

ATE测试和DFT可测性设计&#xff0c;虽然二者都对芯片测试至关重要&#xff0c;但是两个岗位的区别还是很大的。 两个岗位应该如何做选择&#xff1f; 先讲产业环节 我们知道芯片设计、芯片制造、芯片封测每个环节都是大工程&#xff0c;且每个环节都关键且重要。测试是芯片诞…

纳米软件电源模块测试系统助力电压输入缓慢变动测试 解决测试痛点

输入缓慢变动测试是电源模块测试项目之一&#xff0c;其目的是为了验证当输入电压偏低情形发生时&#xff0c;待测品能够自我保护&#xff0c;而且不会被损坏。用纳米软件电源模块测试系统测试电源模块输入电压缓慢变动&#xff0c;解决传统测试程序繁琐、速度慢、效率低难点。…

不会用PS抠图?教你懒人抠图法,必须学会!

相信很多小伙伴都有遇到这样的窘境——好不容易找到得素材图片&#xff0c;中间的图案很好看&#xff0c;可是特别想去掉后面的背景&#xff0c;应该如何抠图呢&#xff1f; 能够将图片中的物品或人物抠出来是一种很有用的技巧&#xff0c;可以在很多场景下应用&#xff0c;比…

数据库连接池有什么用?它有哪些关键参数?

首先&#xff0c;数据库连接池是一种池化技术&#xff0c;池化技术的核心思想是实现资源的复用&#xff0c;避免资源重复创建销毁的开销。而在数据库的应用场景里面&#xff0c;应用程序每次向数据库发起 CRUD 操作的时候&#xff0c;都需要创建连接.在数据库访问量较大的情况下…

DB-GPT发布:用私有LLM技术彻底改革数据库互动

01 项目介绍 随着大模型的发布迭代&#xff0c;大模型变得越来越智能&#xff0c;在使用大模型的过程当中&#xff0c;遇到极大的数据安全与隐私挑战。在利用大模型能力的过程中我们的私密数据跟环境需要掌握自己的手里&#xff0c;完全可控&#xff0c;避免任何的数据隐私泄…

【问题思考总结】已知对角矩阵怎么求原矩阵?原矩阵唯一吗?【相似对角化】

问题 这个问题起源于2010年数一真题&#xff1a; 给定一个对角阵&#xff0c;说QTAQ对角阵&#xff0c;然后Q矩阵实际上是能求出来无穷个的&#xff0c;在这种情况下&#xff0c;A矩阵该怎么求&#xff1f;或者说&#xff0c;Q矩阵不同的时候&#xff0c;A矩阵唯一吗&#xf…

uniapp水果海鲜生鲜商城系统小程序H5源码APP 同城配送、自提、拼单、多门店商城

外卖多门店小程序开源版开发 能够更好的适用于瑜伽馆、健身房、美容美发店、鲜花店、水果店、宠物店、母婴店、教育培训机构&#xff0c;送奶站、送水站&#xff0c;足疗按摩店、儿童摄影馆、上门服务&#xff08;如&#xff1a;家政、维修&#xff09;、无人售货超市、新零售会…

分治法,动态规划法,贪心法,回溯法主要概括

目录 分治法&#xff0c;动态规划法&#xff0c;贪心法&#xff0c;回溯法主要概括 1.前言2.分治法2.1基本思想&#xff1a;2.2适用条件&#xff1a;2.3时间复杂度&#xff1a;2.4主要解决&#xff1a;2.5关键字&#xff1a;2.6其他&#xff1a; 3.动态规划法3.1基本思想&…

2023/10/23学习记录

1.VS2019中sln对应解决方案 修改sln的文件名&#xff0c;对应的解决方案名称也会变化。 2.如何修改生成的exe文件名呢&#xff1f; 属性--->杂项--->&#xff08;名称) 3.这是任务管理器&#xff0c;这里红色部分显示的是“这是文件描述”。 当通过属性查看详细信息的时…

朋友圈推广如何做?

为什么在朋友圈做推广是如此重要&#xff0c;以及如何充分利用这个平台来推动你的业务增长。 不仅仅是分享生活点滴&#xff0c;朋友圈也可以成为你的事业起飞的跳板。快来了解一下吧&#xff01; 为什么在朋友圈做推广&#xff1f; 1、人脉力量&#xff1a;朋友圈是一个连接…

生成式AI - 基于大模型的应用架构与方案

这篇文章探讨了使用文档加载器、嵌入、向量存储和提示模板构建基于语言模型(LLM)应用程序的过程。由于其生成连贯且上下文相关的文本的能力&#xff0c;LLM在自然语言处理任务中变得越来越受欢迎。本文讨论了LLM的重要性&#xff0c;比较了微调和上下文注入方法&#xff0c;介绍…