ftrace学习 —— user_events的用法

news/2024/11/23 13:04:11/

参考

https://docs.kernel.org/trace/user_events.html

测试程序

samples/user_events/example.c
tools/testing/selftests/user_events/ftrace_test.c

正文

通过user_event可以实现对应用程序的跟踪,类似linux内核中的tracepoint那样。相似的方法还有借助/sys/kernel/debug/tracing/trace_marker,不过,user_event提供的方法功能更加强大,可以配合perf等工具使用。

要使用user_event,大致要经过:注册、使能跟踪、写入跟踪信息、读取跟踪信息、关闭跟踪、反注册、删除。需要用到的文件节点主要是:/sys/kernel/tracing/user_events_data

打开文件节点

	data_fd = open(data_file, O_RDWR);

注册和反注册

注册阶段用到的结构体是user_reg:

struct user_reg {/* Input:固定为sizeof(user_reg)*/__u32 size;/* Input: 使用下面的enable_addr的哪个bit来显示使能状态 */__u8 enable_bit;/* Input: 下面的enable_addr的字节长度,4或者8 */__u8 enable_size;/* Input: 目前还用不到,设置为0即可 */__u16 flags;/* Input: 应用通过这个地址来查看该user_event事件是否使能*/__u64 enable_addr;/* Input: 事件描述信息*/__u64 name_args;/* Output: 应用通过该事件索引向内核中写入事件内容 */__u32 write_index;
} __attribute__((__packed__));

反注册用到的结构体是:

struct user_unreg {/* Input: 固定为sizeof(user_unreg) */__u32 size;/* Input: Bit to unregister */__u8 disable_bit;/* Input: Reserved, set to 0 */__u8 __reserved;/* Input: Reserved, set to 0 */__u16 __reserved2;/* Input: Address to unregister */__u64 disable_addr;
} __attribute__((__packed__));

比如以下面的代码为例:

	// 这两个结构体必须初始化为0struct user_reg reg = {0};struct user_unreg unreg = {0};u32 check;reg.size = sizeof(reg);reg.name_args = (__u64)"__test_event0 u32 id; u32 age; char type; char[32] name";reg.enable_bit = 31; // 通过check的bit31来查看使能状态,不同的事件可以使用同一个变量reg.enable_addr = (__u64)✓reg.enable_size = sizeof(check);ioctl(data_fd, DIAG_IOCSREG, &reg); // 如果传入的reg的内容一样,那么返回的write_index也一样event0_index = reg.write_index;reg.size = sizeof(reg);reg.name_args = (__u64)"__test_event1 u32 money";reg.enable_bit = 30; // 通过check的bit30来查看使能状态reg.enable_addr = (__u64)check;reg.enable_size = sizeof(check);ioctl(data_fd, DIAG_IOCSREG, &reg);  // 如果传入的reg的内容一样,那么返回的write_index也一样event1_index = reg.write_index;

注册成功后,可以看到注册的事件:

  • /sys/kernel/debug/tracing/dynamic_events下面:

image

  • /sys/kernel/debug/tracing/events/user_events下面:

image

使能跟踪和关闭跟踪

/sys/kernel/debug/tracing/events/user_events/__test_event0/enable

或者

/sys/kernel/debug/tracing/events/user_events/__test_event1/enable

当改变上面的enable文件节点的值时,check变量的相应bit会随之改变。具体是:

__test_event0/enable写入0,那么check变量的bit31是0,向__test_event0/enable写入1,那么check变量的bit31是1.

__test_event1/enable写入0,那么check变量的bit30是0,向__test_event0/enable写入1,那么check变量的bit30是1.

写入事件

	char name[20] = "I am event0";io[0].iov_base = &event0_index;io[0].iov_len = sizeof(event0_index);io[1].iov_base = &id;io[1].iov_len = sizeof(id);io[2].iov_base = &age;io[2].iov_len = sizeof(age);io[3].iov_base = &type;io[3].iov_len = sizeof(type);io[4].iov_base = name;io[4].iov_len = sizeof(name);// 使能system("echo 1 > /sys/kernel/debug/tracing/events/user_events/__test_event0/enable");// 写入writev(data_fd, (const struct iovec *)io, 5);io[0].iov_base = &event1_index;io[0].iov_len = sizeof(event1_index);io[1].iov_base = &money;io[1].iov_len = sizeof(money);// 使能system("echo 1 > /sys/kernel/debug/tracing/events/user_events/__test_event1/enable");// 写入writev(data_fd, (const struct iovec *)io, 2);

读取跟踪日志

# perf trace -e user_events:__test_event0 -e user_events:__test_event1

或者

# cat /sys/kernel/debug/tracing/trace_pipe

可以看到如下日志:
image

反注册

	unreg.size = sizeof(unreg);unreg.disable_bit = 31;unreg.disable_addr = (__u64)✓ioctl(data_fd, DIAG_IOCSUNREG, &unreg);unreg.size = sizeof(unreg);unreg.disable_bit = 30;unreg.disable_addr = (__u64)✓ioctl(data_fd, DIAG_IOCSUNREG, &unreg);

删除

	// 先关闭close(data_fd);data_fd = open(data_file, O_RDWR);ioctl(data_fd, DIAG_IOCSDEL, "__test_event0");ioctl(data_fd, DIAG_IOCSDEL, "__test_event1");

下面是完整的测试程序:

#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/user_events.h>
#include <stdlib.h>#define BIT(n) 		(1ULL << (n))const char *data_file = "/sys/kernel/tracing/user_events_data";
int enabled = 0;int main(int argc, const char *argv[])
{int data_fd;struct user_reg reg = {0};struct user_unreg unreg = {0};struct iovec io[5];__u32 check, event0_index, event1_index;int id, age = 0, money = 0;char type = 'E', ch;data_fd = open(data_file, O_RDWR);if (data_fd < 0) {perror("Open failed\n");return -1;}reg.size = sizeof(reg);reg.name_args = (__u64)"__test_event0 u32 id; u32 age; char type; char[32] name";reg.enable_bit = 31; // 通过check的bit31来查看使能状态,不同的事件可以使用同一个变量reg.enable_addr = (__u64)&check;reg.enable_size = sizeof(check);if (ioctl(data_fd, DIAG_IOCSREG, &reg) < 0) {printf("reg event0 failed\n");goto out;}event0_index = reg.write_index;printf("event0_index: %d\n", event0_index);reg.name_args = (__u64)"__test_event1 u32 money; char[32] name";reg.enable_bit = 30; // 通过check的bit30来查看使能状态if (ioctl(data_fd, DIAG_IOCSREG, &reg) < 0) {printf("reg event1 failed\n");goto out;}event1_index = reg.write_index;printf("event1_index: %d\n", event1_index);system("echo 1 > /sys/kernel/debug/tracing/events/user_events/__test_event0/enable");system("echo 1 > /sys/kernel/debug/tracing/events/user_events/__test_event1/enable");loop:printf("Press enter to write trace data, enter q to exit ...");ch = getchar();if (ch == 'q') {system("echo 0 > /sys/kernel/debug/tracing/events/user_events/__test_event0/enable");system("echo 0 > /sys/kernel/debug/tracing/events/user_events/__test_event1/enable");unreg.size = sizeof(unreg);unreg.disable_bit = 31;unreg.disable_addr = (__u64)&check;if (ioctl(data_fd, DIAG_IOCSUNREG, &unreg) < 0) {printf("unreg event0 failed\n");goto out;}printf("unreg event0 success\n");unreg.disable_bit = 30;if (ioctl(data_fd, DIAG_IOCSUNREG, &unreg) < 0) {printf("unreg event1 failed\n");goto out;}printf("unreg event1 success\n");close(data_fd);data_fd = open(data_file, O_RDWR);if (ioctl(data_fd, DIAG_IOCSDEL, "__test_event0") < 0) {printf("del event0 failed\n");goto out;}printf("del event0 success\n");if (ioctl(data_fd, DIAG_IOCSDEL, "__test_event1") < 0) {printf("del event1 failed\n");goto out;}printf("del event1 success\n");close(data_fd);return 0;}if (check & BIT(31)) {char name[32] = "I am event0";id = 0x10;io[0].iov_base = &event0_index;io[0].iov_len = sizeof(event0_index);io[1].iov_base = &id;io[1].iov_len = sizeof(id);io[2].iov_base = &age;io[2].iov_len = sizeof(age);io[3].iov_base = &type;io[3].iov_len = sizeof(type);io[4].iov_base = name;io[4].iov_len = sizeof(name);printf("\t write event0\n");writev(data_fd, (const struct iovec *)io, 5);age++;}if (check & BIT(30)) {char name[32] = "I am event1";io[0].iov_base = &event1_index;io[0].iov_len = sizeof(event1_index);io[1].iov_base = &money;io[1].iov_len = sizeof(money);io[2].iov_base = &name;io[2].iov_len = sizeof(name);printf("\t write event1\n");writev(data_fd, (const struct iovec *)io, 3);money++;}goto loop;out:return 0;
}

完。


http://www.ppmy.cn/news/332418.html

相关文章

笔记本接HDMI

笔记本接HDMI后&#xff0c;过2~3分钟&#xff0c;笔记本就直接睡眠&#xff0c;屏幕变黑&#xff0c;乱按一阵鼠标键盘后&#xff0c;需要输入密码才能登陆&#xff0c;电源选项里的睡眠都已经设置在30分钟以上&#xff0c;或者从不&#xff0c;都不管用。 在网上找了一下&…

【C/C++】详解 函数重载和应用

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

DIY钢铁侠电动开合

有需要教学的部分留言 软件教程1&#xff1a;眼灯控制小熊派bearpi-HM-nano&#xff08;hi3861鸿蒙LiteOS&#xff09;点亮WS2812灯板&#xff08;spi方式&#xff09;_mialo163的博客-CSDN博客软件教程2&#xff1a;驱动舵机 待更新 软件教程2&#xff1a;无线控制 待更新

《硅谷钢铁侠》---- 读书笔记

目录 第一章 马斯克的世界&#xff1a;跨领域创造第二章 出生地非洲&#xff1a;冒险无极限的基因第三章 挺进加拿大&#xff1a;追寻太阳的人第四章 第一次创业&#xff1a;征服网络世界第五章 PayPal黑帮大佬&#xff1a;发动国际金融革命第六章 太空召唤&#xff1a;建立Spa…

钢铁侠马斯克,当上了美国院士

美国国家工程院&#xff08;NAE&#xff09;院士名单公布了&#xff01; 谁知道&#xff0c;「狂人」马斯克也入选了&#xff0c;头衔1&#xff0c;我们以后得称他「马院士」。 马斯克发文表示&#xff0c;「非常感激&#xff01;」 此外&#xff0c;22名当选的海外院士中&…

航空母舰与钢铁侠助阵,这么硬核的智能锁你见过么

当威风凛凛的航空母舰映入眼帘&#xff1b;当帅气逼人的钢铁侠亮相现场&#xff0c;你肯定也会和我一样发出由衷的惊叹声。 不过大家不要误会&#xff0c;这可不是漫威又一部电影大片的拍摄现场&#xff0c;而是鹿客智能锁举办的一场新品发布会。 5月21日&#xff0c;鹿客在天津…

钢铁侠与现实生活的结合。

一天时间&#xff0c;把钢铁侠从第一步看到第三部。 我个人看到的是&#xff0c;钢铁侠一次一次的升级&#xff0c;从能源来说&#xff0c;从钯元素升级到最新的新元素&#xff0c;历经了革命性的突破。一点一滴&#xff0c;引人入胜。 从开始的一个简陋的钢铁机器人&#xf…