理解并使用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…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...
jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...
【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析
1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器(TI)推出的一款 汽车级同步降压转换器(DC-DC开关稳压器),属于高性能电源管理芯片。核心特性包括: 输入电压范围:2.95V–6V,输…...
