理解并使用Linux 内核中的 Tracepoint
理解并使用Linux 内核中的 Tracepoint
1. 引言
1.1 为什么需要 Tracepoint?
在内核调试与性能分析中,传统的 printk 方法虽然简单直接,但存在几个显著的局限性:
- 日志噪音:printk 会将所有输出无差别地记录到系统日志或控制台,这会导致大量无关紧要的信息混杂其中,增加了排查问题的难度。
- 性能开销:频繁调用 printk 可能会对系统的实时性能造成负面影响,特别是在高并发场景下。
- 侵入性强:为了添加或移除 printk,往往需要修改源代码,重新编译并加载新的内核模块,这不仅增加了工作量,还可能引入新的错误。
相比之下,Tracepoint 提供了一种更为高效、灵活且低侵入性的方法来跟踪特定事件。它允许开发者和系统管理员在不影响正常业务逻辑的前提下,动态地开启或关闭跟踪功能,收集精确的时间戳和上下文信息,从而有效地减少了对系统性能的影响,并且能够更好地定位和解决复杂的问题。
1.2 什么是 Tracepoint?
Tracepoint 是 Linux 内核提供的一个轻量级机制,用于在不改变代码逻辑的情况下,通过预先定义好的钩子点(hook points)监控内核行为。这些钩子点是在内核编译时静态定义的,作为源码的一部分存在于特定的关键路径上。当内核执行流经过这些位置时,如果事先注册了监听器,则会触发对应的回调函数,使得用户可以在不修改内核代码的情况下,灵活地收集所需的数据或执行额外的操作。
每个 Tracepoint 实际上代表了一个可以被激活或停用的开关,这意味着它们可以在运行时根据需要选择性地启用,以最小化不必要的性能损失。此外,由于 Tracepoint 的设计考虑到了多处理器环境下的同步问题,因此它们也适用于 SMP(对称多处理)系统中的并发事件追踪。
1.3 内核中内置的 Tracepoint 简介
Linux 内核中已经内置了大量的 Tracepoint,涵盖了从文件系统操作到网络协议栈等多个方面。要查看当前系统中存在的所有 Tracepoint,可以使用如下命令:
ls /sys/kernel/debug/tracing/events/
该目录下的每一个子文件夹对应着一个不同的子系统或功能区域,例如 ext4 文件夹包含了 ext4 文件系统相关的所有 Tracepoint。进一步深入到具体的子文件夹中,可以看到一系列以 .enable 结尾的文件,这些文件控制着相应 Tracepoint 的启用状态;而以 .format 结尾的文件则描述了该 Tracepoint 所携带的数据结构及其格式说明。
对于想要深入了解某个特定 Tracepoint 的用户来说,可以通过阅读其 .format 文件了解如何解析由这个 Tracepoint 产生的数据。同时,也可以利用其他工具如 trace-cmd 或者 Ftrace 来更方便地管理和分析 Tracepoint 数据。
2. Tracepoint 的工作原理
Tracepoint 是一种在内核编译阶段静态定义的机制,作为内核源码的一部分存在。这些预先定义的钩子点(hook points)位于内核代码的关键路径上。当内核运行到这些位置时,如果该位置被注册了监听器,则会触发预先设定的回调函数。Tracepoint 允许开发者或管理员在不修改内核逻辑的情况下动态地附加回调函数,以便收集所需信息或执行额外操作。
为了更清楚地理解 Tracepoint 的工作方式,我们以 ext4/ext4_drop_inode 跟踪点为例来说明。下面的代码片段展示了如何在 ext4 文件系统中定义一个名为 ext4_drop_inode 的 Tracepoint:
// 定义 ext4_drop_inode Tracepoint
TRACE_EVENT(ext4_drop_inode,TP_PROTO(struct inode *inode, int drop), // 参数列表TP_ARGS(inode, drop), // 参数传递TP_STRUCT__entry(__field(dev_t, dev) // 定义记录字段__field(ino_t, ino)__field(int, drop)),TP_fast_assign(__entry->dev = inode->i_sb->s_dev; // 快速赋值__entry->ino = inode->i_ino;__entry->drop = drop;),TP_printk("dev %d,%d ino %lu drop %d", // 格式化输出MAJOR(__entry->dev), MINOR(__entry->dev),(unsigned long) __entry->ino, __entry->drop)
);// 在 ext4_drop_inode 函数中调用 Tracepoint
static int ext4_drop_inode(struct inode *inode)
{int drop = generic_drop_inode(inode);if (!drop)drop = fscrypt_drop_inode(inode);trace_ext4_drop_inode(inode, drop); // 触发 Tracepointreturn drop;
}
在这个例子中,TRACE_EVENT 宏用于创建一个新的 Tracepoint,具体步骤如下:
- 参数声明 (
TP_PROTO):指定 Tracepoint 接受的参数类型。 - 参数传递 (
TP_ARGS):将实际参数传递给 Tracepoint。 - 结构体定义 (
TP_STRUCT__entry):定义 Tracepoint 将保存的数据结构及其成员。 - 快速赋值 (
TP_fast_assign):提供一个简短的代码块,用于快速填充上述结构体中的字段。 - 格式化输出 (
TP_printk):定义如何将 Tracepoint 数据格式化为人类可读的字符串形式。
每当 ext4_drop_inode 函数被执行时,都会调用 trace_ext4_drop_inode() 来触发相应的 Tracepoint。此时,如果有任何监听器注册到了这个 Tracepoint 上,那么这些监听器所关联的回调函数就会被执行,从而可以进行日志记录或其他操作。
3. 如何在内核模块中使用 Tracepoint
为了让用户能够方便地利用 Tracepoint 进行监控,内核模块提供了一种机制来注册和注销回调函数,从而实现对特定事件的监听。
3.1 注册和注销回调函数
- 注册:通过
tracepoint_probe_register()函数。 - 注销:通过
tracepoint_probe_unregister()函数。
3.2 示例代码
下面的例子演示了如何创建一个简单的内核模块来捕捉 ext4/ext4_drop_inode 事件:
#include <linux/module.h>
#include <linux/tracepoint.h>
#include <linux/fs.h>
#include <linux/ext4.h>/* 用于管理感兴趣的tracepoint,即我要使用的tracepoint */
struct interest_tracepoint
{void *callback; /* 指向tracepoint要执行的回调函数 */struct tracepoint *ptr; /* 对应tracepoint的指针 */char is_registered; /* 记录回调函数是否已注册 */
};/* 用于生成一个struct interest_tracepoint结构体并初始化,参数: tracepoint_name */
#define INIT_INTEREST_TRACEPOINT(tracepoint_name) \static struct interest_tracepoint tracepoint_name##_tracepoint = {.callback = NULL, .ptr = NULL, .is_registered = 0};/* 该宏用于生成for_each_kernel_tracepoint的回调函数,前者用于遍历整个内核的tracepoint表 */
#define TRACEPOINT_FIND(tracepoint_name) \static void tracepoint_name##_tracepoint_find(struct tracepoint *tp, void *priv) \{ \if (!strcmp(#tracepoint_name, tp->name)) \{ \((struct interest_tracepoint *)priv)->ptr = tp; \return; \} \}/* 用于注销一个tracepoint的回调函数 */
static void clear_tracepoint(struct interest_tracepoint *interest)
{if (interest->is_registered){tracepoint_probe_unregister(interest->ptr, interest->callback, NULL);}
}/* 生成并初始化struct interest_tracepoint ext4_drop_inode */
INIT_INTEREST_TRACEPOINT(ext4_drop_inode)/* 生成ext4_drop_inode_tracepoint_find函数 */
TRACEPOINT_FIND(ext4_drop_inode)/* tracepoint: ext4_drop_inode触发时的回调函数 */
static void ext4_drop_inode_tracepoint_callback(void *data, struct inode *inode)
{/* 这里可以插入你需要的自定义逻辑,例如打印inode的详细信息 */pr_info("ext4_drop_inode called for inode: %ld\n", inode->i_ino);
}static int __init tracepoint_init(void)
{/* 在我们自己的struct interest_tracepoint中记录管理的tracepoint要调用的回调函数 */ext4_drop_inode_tracepoint.callback = ext4_drop_inode_tracepoint_callback;/* 使用for_each_kernel_tracepoint遍历并查找ext4_drop_inode的tracepoint */for_each_kernel_tracepoint(ext4_drop_inode_tracepoint_find, &ext4_drop_inode_tracepoint);/* 判断是否找到目标tracepoint */if (!ext4_drop_inode_tracepoint.ptr){pr_info("ext4_drop_inode's struct tracepoint not found\n");return 0;}/* 注册回调函数到tracepoint */tracepoint_probe_register(ext4_drop_inode_tracepoint.ptr, ext4_drop_inode_tracepoint.callback, NULL);ext4_drop_inode_tracepoint.is_registered = 1; /* 记录回调函数已注册 */return 0;
}static void __exit tracepoint_exit(void)
{clear_tracepoint(&ext4_drop_inode_tracepoint);
}module_init(tracepoint_init);
module_exit(tracepoint_exit);
MODULE_LICENSE("GPL");
注意,上述代码中的输出信息采用了更加直观的命名方式,以便于理解和维护。
3.3 验证
加载模块后,可以通过 dmesg 命令检查内核消息缓冲区,验证是否成功捕捉到了 ext4_drop_inode 事件:
dmesg | grep ext4_drop_inode
这一步骤有助于确认我们的模块是否按预期工作。
4. 在用户空间使用 Tracepoint
除了内核模块之外,用户还可以借助一系列强大的工具,如 trace-cmd 和 perf,轻松捕获并分析 Tracepoint 事件。
4.1 使用 trace-cmd 捕获事件
以下是使用 trace-cmd 工具捕捉 ext4/ext4_drop_inode 事件的具体步骤:
-
启动事件捕获
sudo trace-cmd record -e ext4:ext4_drop_inode -
触发事件(例如删除一个文件)
rm /path/to/file -
查看捕获结果
trace-cmd report
输出示例:
rm-137270 [005] 333384.754465: ext4_drop_inode: device=8,2 inode=1357167 drop=1
5. 总结与延伸
与其他调试技术对比
| 技术 | 特点 | 应用场景 |
|---|---|---|
| Tracepoint | 静态定义、低开销、易于集成 | 实时性能监控、事件追踪 |
| Kprobe | 动态插入、高度灵活 | 探索未知问题、深入调试 |
| Ftrace | 全面而强大的跟踪框架 | 广泛的功能剖析与故障排除 |
| eBPF | 高性能、动态编程 | 复杂业务逻辑下的实时响应 |
核心回顾
Tracepoint 作为一种轻量级的跟踪解决方案,在保证系统稳定性的同时,提供了极大的灵活性。它特别适用于那些需要持续监测和优化的应用场景,帮助开发者更好地理解系统行为。
扩展方向
- 结合
ftrace使用,进一步挖掘内核活动的细节。 - 利用
bpftrace或其他 eBPF 工具,探索更为复杂的监控策略,包括跨层数据关联和实时反馈。
相关文章:
理解并使用Linux 内核中的 Tracepoint
理解并使用Linux 内核中的 Tracepoint 1. 引言 1.1 为什么需要 Tracepoint? 在内核调试与性能分析中,传统的 printk 方法虽然简单直接,但存在几个显著的局限性: 日志噪音:printk 会将所有输出无差别地记录到系统日…...
centos7中Gbase8s数据库安装,以及数据导入遇到的一系列问题
centos7中Gbase8s数据库安装,以及遇到的一系列问题 以下是我在centos7上安装gbase8s数据库遇到的一系列问题,包括数据库安装,数据导入,数据连接,不能完全作为标准,只可作为类似问题参考,有问题…...
AW36518芯片手册解读(3)
接前一篇文章:AW36518芯片手册解读(2) 二、详述 3. 功能描述 (1)上电复位 当电源电压VIN降至预定义电压VPOR(典型值为2.0V)以下时,该设备会产生复位信号以执行上电复位操作&#x…...
MySQL的REPEATABLE READ事务隔离级别
本文隔离级别: T1内读T2的update数据 首先开两个事务(左二) 事务1修改成李四,提交 事务2再读还是张三,也就是说,记录的数据从事务开始时一直到结束,读的都是同一个版本,读不到T2未提交的此条记录修改&…...
sqoop的参数有哪些?
Sqoop 是一款用于在 Hadoop 与关系型数据库之间进行数据传输的工具,它有很多参数,可分为通用参数、导入参数和导出参数等,以下是一些常见的参数介绍: 通用参数 --connect 说明:指定要连接的关系型数据库的 JDBC URL。…...
动态规划<四> 回文串问题(含对应LeetcodeOJ题)
目录 引例 其余经典OJ题 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 引例 OJ 传送门Leetcode<647>回文子串 画图分析: 使用动态规划解决 原理:能够将所有子串是否是回文的信息保存在dp表中 在使用暴力方法枚举出所有子串,是…...
跨模态知识迁移:基于预训练语言模型的时序数据建模
在NLP和CV领域,通常通过在统一的预训练模型上进行微调,能够在各自领域的下游任务中实现SOTA(最先进)的结果。然而,在时序预测领域,由于数据量相对较少,难以训练出一个统一的预训练模型来覆盖所有…...
重温设计模式--职责链模式
文章目录 职责链模式的详细介绍C 代码示例C示例代码2 职责链模式的详细介绍 定义与概念 职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它旨在将请求的发送者和多个接收者解耦,让多个对象都有机会处理请求&a…...
git冲突解决
git冲突解决 最近遇到了一次git冲突的问题 起因是因为最近公司数据推送部分重构,负责重构的同事就改动了我的一小部分推送的代码,然后等我开发完合并到远程master的时候,报了merge冲突。我对于git工具确实不是很熟练,只是学习了…...
Java学习笔记(14)--面向对象编程
面向对象基础 学习资料来自多态 - Java教程 - 廖雪峰的官方网站 目录 面向对象基础 Override 多态 举个例子 覆写Object方法 调用super final 练习 小结 Override 在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为覆写&…...
《Swift 字面量》
《Swift 字面量》 介绍 在 Swift 编程语言中,字面量是一种表示源代码中固定值的表达方式。字面量可以直接表示数字、字符串、布尔值等基本数据类型,为编程提供了简洁和直观的方式。Swift 支持多种类型的字面量,包括整数字面量、浮点数字面量…...
数据库 SQL 常用语句全解析
数据库 SQL 常用语句全解析 在数据库领域,SQL(Structured Query Language)作为标准语言,掌控着数据的查询、插入、更新与删除等关键操作。无论是新手入门数据库,还是经验丰富的开发者日常工作,熟练掌握 SQ…...
SQLite 命令
关于《SQLite 命令》的文章,我可以为您概述一些关键点。SQLite是一个轻量级的数据库管理系统,它被广泛用于各种应用程序中。SQLite命令主要分为两类:一类是SQL命令,另一类是SQLite特定的点命令。 SQL命令:这些命令用于…...
本地如何启动casdoor
1、下载代码 GitHub - casdoor/casdoor at v1.777.0 下载对应tag的代码,我这里选择的时v1.777.0版本 通过网盘分享的文件:casdoor-1.777.0.zip 链接: https://pan.baidu.com/s/1fPNqyJYeyfZnem_LtEc0hw 提取码: avpd 2、启动后端 1、使用goland编译…...
目标检测-R-CNN
R-CNN在2014年被提出,算法流程可以概括如下: 候选区域生成:利用选择性搜索(selective search)方法找出图片中可能存在目标的候选区域(region proposal) CNN网络提取特征:对候选区域进行特征提取(可以使用AlexNet、VGG等网络) 目…...
【持续更新】Github实用命令
Intro 最近高强度使用github,遂小计于此作为备忘。 Basic github是一个代码管理软件,能够track文件变动并且管理版本,是当代coding必不可少的工具。当你安装好github在本地以后,你可以通过以下命令初始化当前文件夹(…...
docker 容器的基本使用
docker 容器 一、docker是什么? 软件的打包技术,就是将算乱的多个文件打包为一个整体,打包技术在没有docker容器之前,一直是有这种需求的,比如上节课我把我安装的虚拟机给你们打包了,前面的这种打包方式是…...
css让按钮放在最右侧
要将 el-button 按钮放在最右侧,可以使用多种方法,具体取决于使用的布局方式和样式库。以下是几种常见的解决方案: 方法 1:使用 CSS Flexbox Flexbox 是一种非常灵活的布局方式,可以轻松实现水平或垂直对齐。你可以将…...
8K+Red+Raw+ProRes422分享5个影视级视频素材网站
Hello,大家好,我是后期圈! 在视频创作中,电影级的视频素材能够为作品增添专业质感,让画面更具冲击力。无论是广告、电影短片,还是品牌宣传,高质量的视频素材都是不可或缺的资源。然而ÿ…...
Linux网络——UDP的运用
Linux网络——UDP的运用 文章目录 Linux网络——UDP的运用一、引入二、服务端实现2.1 创建socket套接字2.2 指定网络接口并bind2.3 接收数据并处理2.4 整体代码2.5 IP的绑定的细节 三、用户端实现3.1 创建套接字3.2 指定网络接口3.3 发生数据并接收3.4 绑定问题 四、代码五、UD…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
