七张图看懂 Linux profiling 机制
1 图 1 Linux profiling 手段一览
软件埋点:
- 手动埋点:主动调用 trace 函数来实现埋点。
Android systrace 即是这样一个例子,如图 2 和 图 3 所示 - 自动埋点:借助工具链,自动埋点,对函数的 entry 和 return 进行 hook。
Linux ftrace 即是这样一个例子,图 4 简示了其实现原理 - 动态埋点:运行时刻,在指定位置上加断点,断点触发时执行相应 handler。
Handler 为注入内核的 eBPF 字节码
Linux kprobe / uprobe 就是这样的例子,图 5 和 图 6 简示了 uprobe 以及 uretprobe 的实现原理
- 手动埋点:主动调用 trace 函数来实现埋点。
硬件统计
- 计数累加:统计一段时间内,某个性能监控单元(PMU)的计数。
例如:perf stat -e cache-misses -p PID
,参见 brendangregg.com/perf.html ,Counting Events 一节
函数接口:参见 libperf 的封装,fd = perf_event_open(...); read(fd, …) - 采样:计数达标,产生中断,伴随 Backtrace 对应到代码行。
例如:perf record -F 99 -p PID sleep 10
,以及对应图形化展示 FlameGraph
函数接口:参见perf_event_open,fd = perf_event_open(…); void *addr = mmap(…, fd, …);
图 7 简示了其实现原理
- 计数累加:统计一段时间内,某个性能监控单元(PMU)的计数。
2 图 2 Android systrace 工作原理
User space,分为两部分
- 埋点处:通过嵌入代码中的 Trace API 调用,向 Linux kernel 的 tracing buffer 写日志。
上图中,裸示了写 tracing buffer 的过程 - atrace:读取 tracing buffer,存于磁盘文件,以免 tracing buffer 溢出丢失信息。
- 埋点处:通过嵌入代码中的 Trace API 调用,向 Linux kernel 的 tracing buffer 写日志。
Kernel space,通过 scheduler 嵌入的 tracepoint,将调度事件,写入 tracing buffer。
tracing buffer 犹如一段 in-memory 的日志流,对齐了写入的各个标记和事件。
3 图 3 Android atrace 输出文件及图形化展示
atrace 转储的 tracing buffer 内容,以及载入到 Chrome 浏览器,进行图形化分析。
Discuss:想象一个进程同时播放两段视频,视频解码库是多线程的,线程来自全局的 thread pool。通过 systrace,能区分这两个视频播放任务的 CPU 时间片吗?
4 图 4 Linux ftrace 实现原理回顾
- 通过 gcc -pg 选项,编译时,函数开头自动插入 _mcount 调用。
- _mcount 处:除了 hook entry ,还通过修改返回地址,来 hook return。
Linux kernel 热补丁方案,”kernel livepatch“,便借用了 ftrace 的原理:替换有漏洞的函数实现,从而实现热补丁。
更多关于 ftrace 使用,参考「Advanced Features of Ftrace」
5 图 5 uprobe 的实现原理
注:上图修改自 dev.framing.life/tracing/kernel-and-user-probes-magic
指定位置上的指令,头部修改为软件中断指令(同时原指令存档他处):
- 当执行到该位置时,触发软件中断,陷入内核
- 在内核,执行以 eBPF 字节码形式注入的 Handler
- 单步执行原指令
- 修正寄存器和栈,回到原有指令流
Discuss:这与 gdb 中设断点有什么区别?
断点的 Handler 运行于 Kernel space,无需多次的 User space Kernel space 通信
Discuss:用户空间注入的 Handler 在 Kernel space 执行,安全性如何保证?
听说过 eBPF 吗?
简单介绍下 extended Berkeley Packet Filter(eBPF)
- 一种功能有限、沙箱化的字节码。
- 由 User space 注入到 Kernel space 执行。
- 基于 BPF 扩展。
原始的 BPF 用于网路包过滤,下面是一个 BPF 裸用的例子:
/**
* 通过 netlink socket,获得关心进程的消亡信息
*/
int sock_fd = socket (PF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_CONNECTOR);
union {
struct sockaddr sa;
struct sockaddr_nl nl;
} addr = { .nl.nl_family = AF_NETLINK, .nl.nl_pid = getpid(), .nl.nl_groups = CN_IDX_PROC };
enum proc_cn_mcast_op op = PROC_CN_MCAST_LISTEN;
struct cn_msg cn_msg = { .id.idx = CN_IDX_PROC, .id.val = CN_VAL_PROC, .len = sizeof(op) };
struct iovec iov[3] = {
[0] = { .iov_base = nlmsghdrbuf, .iov_len = NLMSG_LENGTH(0) },
[1] = { .iov_base = &cn_msg, .iov_len = sizeof(cn_msg) },
[2] = { .iov_base = &op, .iov_len = sizeof(op) }
};
bind(sock_fd, &addr.sa, sizeof(addr.nl));
/* start proc connector */
writev (sock_fd, iov, 3);
/* 借助 BPF,从 Process Events 中,滤出「进程消亡事件」 */
struct sock_filter filter[] = {
...
/* 6-7: filter out proc connector message other than 'PROC_EVENT_EXIT' */
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
NLMSG_LENGTH(0) + offsetof(struct cn_msg, data)
+ offsetof(struct proc_event, what)),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K,
htonl(PROC_EVENT_EXIT), 0 /* true offset */, 1 /* false offset */),
/* 8: the @ret_cmd_idx */
BPF_STMT (BPF_RET|BPF_K, 0xffffffff),
/* 9: the @drop_cmd_idx */
BPF_STMT (BPF_RET|BPF_K, 0)
};
struct sock_fprog fprog = { .filter = filter, .len = 10 };
setsockopt (sock_fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof (fprog)) < 0)
eBPF 形式上类似,裸用相当不方便,好在有编译器 bcc,以及高级语言 bpftrace。
6 图 6 uretprobe 工作原理
图 5 展示的是 User level 埋点,故而叫做 uprobe。Kernel level 对应款叫做 kprobe。
uprobe 和 kprobe 的通常用法中,以函数入口地址,进行埋点。而对于函数返回,其位置可能有多处:
int foo(..) {
size_t n_written = 0;
if (cond1) return -EINVAL;
if (cond2) goto fail;
n_written = do_io(...);
return n_written;
fail:
free(...); return -EIO;
}
于是就有了 kretprobe 以及 uretprobe。下图展示了 uretprobe 工作原理,同样修改自dev.framing.life/tracing/kernel-and-user-probes-magic
uprobe 的工作流中,需要指定位置方能埋点。除了上述提及的函数 entry & return,在函数中间某处埋点,意味着要反汇编,找到源代码行对应汇编地址,有些反人类。
于是,可以预先在代码中埋“标记”,再通过 uprobe 找到“标记”,进行埋点 —— USDT(User Statically-Defined Tracing) 就是这样一个技术,其实现简介参见这个链接。
节末,再提一个 uprobe 应用 “malloc() Flame Graph” ,通过埋点 malloc() / free() 来剖析目标进程的内存使用情况,分析是否存在泄漏。
7 图 7 性能计数采样工作原理
云上: 服务端程序需要扛住超高的并发请求;手机上:需要有效降低延时;计算密集型的神经网络中:GPU 需要极致优化的 kernel。
借助诸如硬件性能监控单元(PMU),可以统计高速硬件上的各种 “塞车” 事件,指出程序为何跑的慢。进一步对其采样,还可将 “塞车事件”,对应到造成 “塞车” 的热点代码行上。
“Cache Line 伪共享发现与优化“一文,介绍了如何发现名为 “Cache Line 伪共享” 的 “塞车事件”,并对应到代码行上。
下图简示了采样的工作原理:当 “塞车” 计数达到采样频率时,产生一次中断,转储现场,从而回溯到代码行和相关上下文。
七张图看懂 Linux profiling 机制的更多相关文章
- 一张图看懂开源许可协议,开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
一张图看懂开源许可协议,开源许可证GPL.BSD.MIT.Mozilla.Apache和LGPL的区别 首先借用有心人士的一张相当直观清晰的图来划分各种协议:开源许可证GPL.BSD.MIT.Mozi ...
- [转帖]两张图看懂GDT、GDTR、LDT、LDTR的关系
两张图看懂GDT.GDTR.LDT.LDTR的关系 2018-06-09 18:13:53 Six_666A 阅读数 2044更多 分类专栏: 深入理解linux内核 转自:http://ju.o ...
- 一张图看懂ANSYS17.0 流体 新功能与改进
一张图看懂ANSYS17.0 流体 新功能与改进 提交 我的留言 加载中 已留言 一张图看懂ANSYS17.0 流体 新功能与改进 原创2016-02-03ANSYS模拟在线模拟在线 模拟在线 ...
- FUNMVP:几张图看懂区块链技术到底是什么?(转载)
几张图看懂区块链技术到底是什么? 本文转载自:http://www.cnblogs.com/behindman/p/8873191.html “区块链”的概念可以说是异常火爆,好像互联网金融峰会上没人 ...
- 4张图看懂delphi 10生成ipa和在iPhone虚拟器上调试(教程)
4张图看懂delphi 10生成ipa和在iPhone虚拟器上调试(教程) (2016-02-01 03:21:06) 转载▼ 标签: delphi ios delphi10 教程 编程 分类: 编程 ...
- 一张图看懂css的position里的relative和absolute的区别
position有以下属性:static.inherit.fixed.absolute.relative前三个好理解好区分:static:是默认状态,没有定位,元素出现在正常的流中(忽略 top, b ...
- 一张图看懂Function和Object的关系及简述instanceof运算符
我在写一篇图解prototype和__proto__的区别时,搜资料搜到了一个有意思的现象,下面这两个运算返回的结果是一样的: Function instanceof Object;//true Ob ...
- Nodejs学习笔记(三)——一张图看懂Nodejs建站
前言:一条线,竖着放,如果做不到精进至深,那就旋转90°,至少也图个幅度宽广. 通俗解释上面的胡言乱语:还没学会爬,就学起走了?! 继上篇<Nodejs学习笔记(二)——Eclipse中运行调试 ...
- 一张图看懂Rxjava的原理
前言 Rxjava是NetFlix出品的Java框架, 官方描述为 a library for composing asynchronous and event-based programs usin ...
- 12 张图看懂 CPU 缓存一致性与 MESI 协议,真的一致吗?
本文已收录到 GitHub · AndroidFamily,有 Android 进阶知识体系,欢迎 Star.技术和职场问题,请关注公众号 [彭旭锐] 进 Android 面试交流群. 前言 大家好 ...
随机推荐
- 2023/4/16 SCRUM个人博客
1.我昨天的任务 大体学习并了解初始化pyqt5的一些可视化问题 2.遇到了什么困难 对于py的字典使用 3.我今天的任务 学习了easydict库的基本操作
- 使用update-alternatives管理GCC版本
目录 简介 操作过程 简介 当操作系统中存在多个版本的GCC时,可以使用使用update-alternatives管理默认使用的编译器版本. 本文使用gcc-9和gcc-11做演示,操作系统为ubun ...
- Fidder响应数据SyntaxView乱码的处理方法
当Fidder查看响应数据"SyntaxView"出现乱码时,可以点击上方菜单栏的"Decode"按钮,等"Decode"出现蓝色边框后再重 ...
- (持续更新)国内计算机领域相关的SCI和EI期刊,以及好中的SCI和EI期刊(不限国内外)
好中的: SCI刊: EI刊: EI会议: 参考: CCF发布计算领域高质量科技期刊分级目录 国内的: SCI-Expanded 1. <Journal of Computer Scie ...
- 强化学习的REIINFORCE算法和交叉熵RL算法
注意: 本文并不讲REINFORCE算法,而是讲强化学习的交叉熵算法,关于REINFORCE算法可以参看: https://www.cnblogs.com/devilmaycry812839668/p ...
- maven项目打包时排除依赖包
1.背景 为了快速上传jar包到服务器,很多时候我们需要把依赖包单独独立出来,避免每次修改都传依赖包 2.实现方式 maven的pom文件,没有独立依赖包时配置如下: <build> &l ...
- C语言基础- Hello World
第一个C语言程序 Hello World # include <stdio.h> //#关键标识符,表示用用头文件:include:引入都文件关键字 // stdio.h:系统标准输入.输 ...
- 处理一直显示npm WARN using –force Recommended protections disabled.的问题
使用 npm config set force false 可以消除.
- MJUCTF—WP
1.猫娘 点开发现有两个文件, 一个加密压缩包, 一个word文档 点开word发现是兽音加密, 点开在线网站进行解密 # 得到一段文本, 先进行分割 小小年内则伏勤, 阵阵寒风刺骨寒. 是处寂寞无人 ...
- 部署在阿里云上的项目收到了阿里云发送的shiro漏洞
编辑 还记得在十月份凯哥发布过一篇修改若依系统编辑器的文章,然后为了方便大家浏览,凯哥就部署在服务器上了,结果,没想到最近收到了阿里云漏洞扫描通知: 编辑 如果不修改的话:对于长期存在安全隐患 ...