ftrace学习 —— user_events的用法

news2024/11/16 15:56:17

参考

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__));

比如以下面的代码为例:

	// 这两个结构体必须初始化为0
	struct 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.coloradmin.cn/o/634814.html

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

相关文章

走进docker

一、Docker 概述 1、Docker的概念 • Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源 • Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机” • Docker 的容器技术可以在一台主机上轻松为任何应用创建一…

异常数据检测 | Python实现基于高斯概率分布的异常数据检测

文章目录 文章概述模型描述源码分享学习小结参考资料文章概述 高斯分布也称为正态分布。它可以被用来进行异常值检测,不过我们首先要假设我们的数据是正态分布的。不过这个假设不能适应于所有数据集。但如果我们做了这种假设那么它将会有一种有效的方法来发现异常值。 模型描述…

asp.net审计项目管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net审计项目管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言 开发 二、功能介绍 (1)科室管理&…

GIT远程仓库(随笔)

目录 前言 一、GIt常见命令 二、概念原理 三、常见的代码托管平台 四、配置SSH公钥 五、操作 1、注册账号 2、在gitee中&#xff0c;创建远程仓库 3、Git命令创建本地仓库 4、Git命令创建第一个版本提交 5、Git命令添加远程仓库 6、推送 7、修改开源项目 ​编辑 8、…

浅谈数据库系统:MySQL的简介与安装配置

前言 ✨文末送书&#xff0c;小K赠书活动第一期 目录 前言一、数据库系统概述数据(Data)数据库(Database)数据库管理系统(Database Management System,DBMS)数据库系统(Database System,DBS)什么是SQL 二、MySQL的简介与安装MySQL简介MySQL下载与安装下载解压版安装配置安装版安…

前端 vue 自定义导航栏组件高度及返回箭头 自定义 tabbar 图标

前端vue自定义导航栏组件高度及返回箭头 自定义tabbar图标, 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id12986 效果图如下: # #### 使用方法 使用方法 // page.json 采用矢量图标设置返回箭头 ,{ "path" : "pages/Home/Ho…

2023.06.11 学习周报

文章目录 摘要文献阅读1.题目2.问题3.介绍4.Problem definition5.Method5.1 Feature Extractor5.2 Synthetic Node Generation5.3 Edge Generator5.4 GNN Classifier5.5 Optimization Objective5.6 算法 6.实验6.1 数据集6.2 基线6.3 实验结果 7.结论 数学建模1.欧式距离2.切比…

leetcode174. 地下城游戏(java)

地下城游戏 leetcode174. 地下城游戏题目描述 动态规划解题思路代码 动态规划专题 leetcode174. 地下城游戏 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/dungeon-game 题目描述 恶魔们抓住了公主并将她关在了地下城 …

python基础知识(十一):matplotlib的基本用法一

目录 1. matplotlib库和numpy库2. matplotlib绘图的简单示例3. 设置窗口的尺寸比例&#xff0c;线宽和颜色4. 坐标轴设置5. 去除坐标轴边框和坐标轴原点化6. 图例7. 文本标注 1. matplotlib库和numpy库 matplotlib库是python的绘图库&#xff0c;numpy库是numpy是python中基于…

如何使用Docker实现分布式Web自动化!

1、前言 顺着docker的发展&#xff0c;很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试&#xff0c;这篇文章主要讲述在docker中使用浏览器进行自动化测试如果可以实现可视化&#xff0c;同时可以对浏览器进行相关的操作。 如果你想学习自动化测…

【动态规划专栏】-- 回文串问题 -- 动态规划经典题型

目录 动态规划 动态规划思维&#xff08;基础&#xff09; 状态表示&#xff08;最重要&#xff09; 状态转移方程&#xff08;最难&#xff09; 初始化&#xff08;细节&#xff09; 填表顺序&#xff08;细节&#xff09; 返回值&#xff08;结果&#xff09; 回文子串…

浮点型进制转换 和 与或非(逻辑短路)

正数的反码是其本身 负数的补码是其反码1 原码 十进制数据的二进制表现形式 byte b 13 1101&#xff08;13的十进制&#xff09;byte代表占存储的一个字节&#xff08;1字节等于8位&#xff09; 此时13的在存储里的形式 0000 1101 &#xff08;原码最左边0为正&#…

物联网Lora模块从入门到精通(六)OLED显示屏

一、前言 获取到数据后我们常需要在OLED显示屏上显示&#xff0c;本文中我们需要使用上一篇文章(光照与温湿度数据获取)的代码&#xff0c;在其基础上继续完成本文内容。 基础代码&#xff1a; #include <string.h> #include "board.h" #include "hal_ke…

Spring boot之WEB 开发-静态资源访问--自定义转换器--处理JSON--内容协商

Spring boot之WEB 开发-静态资源访问 官方文档 在线文档: https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.develo\ping-web-applications 基本介绍 1. 只要静态资源放在类路径下&#xff1a; /static 、/public 、/resources 、/M…

2023-06-11:redis中,如何在100个亿URL中快速判断某URL是否存在?

2023-06-11&#xff1a;redis中&#xff0c;如何在100个亿URL中快速判断某URL是否存在&#xff1f; 答案2023-06-11&#xff1a; 传统数据结构的不足 当然有人会想&#xff0c;我直接将网页URL存入数据库进行查找不就好了&#xff0c;或者建立一个哈希表进行查找不就OK了。 …

【Java】数组是引用类型

【Java】数组是引用类型 Java虚拟机运行时的数据区基本类型变量与引用类型变量的区别 Java虚拟机运行时的数据区 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址。 虚拟机栈(JVM Stack): 与方法调用相关的一些信息&#xff0c;每个方法在执行时&a…

【算法系列 | 5】深入解析排序算法之——快速排序

序言 你只管努力&#xff0c;其他交给时间&#xff0c;时间会证明一切。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级论点蓝色&#xff1a;用来标记二级论点 决定开一个算法专栏&#xff0c;希望能帮助大…

【日志解析】【频率分析】ULP:基于正则表达式和本地频率分析进行日志模板提取

An Effective Approach for Parsing Large Log Files 文章目录 An Effective Approach for Parsing Large Log Files1 论文出处2 背景2.1 背景介绍2.2 针对问题2.3 创新点 3 主要设计思路3.1 预处理3.2 日志事件分组3.3 通过频率分析生成日志模板 4 实验设计4.1 准确性4.2 效率…

物联网Lora模块从入门到精通(八)Lora无线通信

一、前言 在某些环境下&#xff0c;无法通过有线传输数据&#xff0c;这时候我们需要使用Lora无线通信传输数据&#xff0c;Lora无线数据传输具有低功耗、距离长的特点&#xff0c;常用于工厂内等&#xff0c;需要Lora基站。 我曾做过距离测试&#xff1a;Lora模块距离测试-物联…

【Pytest实战】pytest 基本概念及使用大全

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想…