当前位置: 首页 > article >正文

linux tracepoint系列宏定义(TRACE_EVENT,DEFINE_TRACE等)展开过程分析之三 define_trace.h头文件

        在linux tracepoint系列宏定义(TRACE_EVENT,DEFINE_TRACE等)展开过程分析之二 文章中,我们知道trace-events-sample.h 文件在包含了tracepoint.h后第一次对TRACE_EVENT(...)等系列宏定义进行了展开,主要是构建tracepoint 调用钩子函数,注册/注销函数。展开的第二阶段,则是包含了define_trace.h头文件,那么在本阶段这些宏定义又会进行怎样的展开呢?

1、包含define_trace.h头文件

        在trace-events-sample.h文件的结尾使用#include <trace/define_trace.h> 包含了define_trace.h有文件,意味着在

预编译阶段该头文件会在此位置进行展开。

/** TRACE_INCLUDE_FILE is not needed if the filename and TRACE_SYSTEM are equal*/#define TRACE_INCLUDE_FILE trace-events-sample/*包含define_trace.h头文件,里面对TRACE_EVENT,TRACE_EVENT_CONDITION等宏进行重定义那么包含trace-events-sample.hwn头文件的文件中后续使用的TRACE_EVENT,TRACE_EVENT_CONDITION等宏定义则来自define_trace.h文件*/#include <trace/define_trace.h>

        而在define_trace.h中会去包含包含trace-events-sample.h文件。因为define_trace.h中对TRACE_EVENT(...)等系列宏定义进行了#unset 后又#define 重新定义,所以包含trace-events-sample.h后,其中的TRACE_EVENT系列宏定义会被重新展开,本阶段的展开主要TRACE_EVENT调用DEFINE_TRACE定义并初始化struct tracepoint __tracepoint_##name变量

/* #include "./trace-events-sample.h" */
#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

2、define_trace.h 头文件注释:

        注意:define_trace.h头文件在每个定义tracepoint的.h头文件中只有第一次的包含是有效的,因为 #undef CREATE_TRACE_POINTS会使define_trace.h再出进入时无效,除非明确定义CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS才有效。这个很重要,否则会给后面的理解造成困惑。

        下面张贴出对define_trace.h头文件的详细注释:

/* SPDX-License-Identifier: GPL-2.0 */
/** Trace files that want to automate creation of all tracepoints defined* in their file should include this file. The following are macros that the* trace file may define:** TRACE_SYSTEM defines the system the tracepoint is for** TRACE_INCLUDE_FILE if the file name is something other than TRACE_SYSTEM.h*     This macro may be defined to tell define_trace.h what file to include.*     Note, leave off the ".h".** TRACE_INCLUDE_PATH if the path is something other than core kernel include/trace*     then this macro can define the path to use. Note, the path is relative to*     define_trace.h, not the file including it. Full path names for out of tree*     modules must be used.*/
/*在子系统tracepoint所在的.c文件中定义(trace-events-sample.c)*/
#ifdef CREATE_TRACE_POINTS/* Prevent recursion */
/*意味着define_trace.h文件只能进入一次,因为这里使用#undefa取消其定义,后面就无法再次进入*/
#undef CREATE_TRACE_POINTS#include <linux/stringify.h>/*在该阶段,TRACE_EVENT系列宏定义重定义为DEFINE_TRACE系列宏,用于定义并初始化struct tracepoint __tracepoint_##name变量*/
#undef TRACE_EVENT /*取消之前的TRACE_EVENT定义*/
#define TRACE_EVENT(name, proto, args, tstruct, assign, print)	\DEFINE_TRACE(name) /*DEFINE_TRACE在tracepoint.h中定义,内部调用DEFINE_TRACE_FN*/#undef TRACE_EVENT_CONDITION
#define TRACE_EVENT_CONDITION(name, proto, args, cond, tstruct, assign, print) \TRACE_EVENT(name,						\PARAMS(proto),						\PARAMS(args),						\PARAMS(tstruct),					\PARAMS(assign),						\PARAMS(print))#undef TRACE_EVENT_FN
#define TRACE_EVENT_FN(name, proto, args, tstruct,		\assign, print, reg, unreg)			\DEFINE_TRACE_FN(name, reg, unreg)#undef TRACE_EVENT_FN_COND
#define TRACE_EVENT_FN_COND(name, proto, args, cond, tstruct,		\assign, print, reg, unreg)			\DEFINE_TRACE_FN(name, reg, unreg)#undef DEFINE_EVENT
#define DEFINE_EVENT(template, name, proto, args) \DEFINE_TRACE(name)#undef DEFINE_EVENT_FN
#define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg) \DEFINE_TRACE_FN(name, reg, unreg)#undef DEFINE_EVENT_PRINT
#define DEFINE_EVENT_PRINT(template, name, proto, args, print)	\DEFINE_TRACE(name)#undef DEFINE_EVENT_CONDITION
#define DEFINE_EVENT_CONDITION(template, name, proto, args, cond) \DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))#undef DECLARE_TRACE 	/*在该阶段DECLARE_TRACE重定义为DEFINE_TRACE*/
#define DECLARE_TRACE(name, proto, args)	\DEFINE_TRACE(name)#undef TRACE_INCLUDE
#undef __TRACE_INCLUDE/*在定义TRACE_EVNET所在的.h头文件中已定义TRACE_INCLUDE_FILE为trace-events-sample(trace-events-sample.h)*/
#ifndef TRACE_INCLUDE_FILE
/*如果没有定义TRACE_INCLUDE_FILE,就设置其值为TRACE_SYSTEM*/
# define TRACE_INCLUDE_FILE TRACE_SYSTEM
# define UNDEF_TRACE_INCLUDE_FILE
#endif/*在定义TRACE_EVNET所在的.h头文件中已定义TRACE_INCLUDE_PATH为 . (trace-events-sample.h)*/
#ifndef TRACE_INCLUDE_PATH
# define __TRACE_INCLUDE(system) <trace/events/system.h>
# define UNDEF_TRACE_INCLUDE_PATH
#else/*./trace-events-sample.h*/
# define __TRACE_INCLUDE(system) __stringify(TRACE_INCLUDE_PATH/system.h)
#endif
/*TRACE_INCLUDE宏用于包含 trace-events-sample.h文件*/
# define TRACE_INCLUDE(system) __TRACE_INCLUDE(system)/* Let the trace headers be reread */
#define TRACE_HEADER_MULTI_READ/*由于上面修改了大量关键宏定义,如TRACE_EVENT由之前tracepoint.h中的调用DECLARE_TRACE来声明实现tracepoint的注册/注销函数,钩子函数调用接口的功能修改为在该阶段TRACE_EVENT调用DEFINE_TRACE定义并初始化struct tracepoint __tracepoint_##name变量。所以需要再次包含头文件(trace-events-sample.h)对其中的宏定义重性进行展开,当然定义的作用也不相同。#include "./trace-events-sample.h"
*/
/* #include "./trace-events-sample.h" */
#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)/* Make all open coded DECLARE_TRACE nops *//*取消DECLARE_TRACE的定义,定义为空,因为在前面两个阶段已经完成了声明实现tracepoint的注册/注销函数,钩子函数调用接口以及义并初始化struct tracepoint __tracepoint_##name变量。因为在tracepoint.h中会判断DECLARE_TRACE是否定义,如果未定义则会重新定义,为了避免再次定义,所以这里设置为空。
*/
#undef DECLARE_TRACE
/*注意,DECLARE_TRACE设置为空*/
#define DECLARE_TRACE(name, proto, args) /*空*/#ifdef TRACEPOINTS_ENABLED
/*包含trace/trace_events.h头文件,在trace_events.h头文件中会多次包含trace-events-sample.h,并对其进行多次展开*/
#include <trace/trace_events.h>
/*包含trace/perf.h头文件*/
#include <trace/perf.h>
#endif/*取消下面的宏定义*/
#undef TRACE_EVENT
#undef TRACE_EVENT_FN
#undef TRACE_EVENT_FN_COND
#undef TRACE_EVENT_CONDITION
#undef DECLARE_EVENT_CLASS
#undef DEFINE_EVENT
#undef DEFINE_EVENT_FN
#undef DEFINE_EVENT_PRINT
#undef DEFINE_EVENT_CONDITION
#undef TRACE_HEADER_MULTI_READ
#undef DECLARE_TRACE/* Only undef what we defined in this file */
#ifdef UNDEF_TRACE_INCLUDE_FILE
# undef TRACE_INCLUDE_FILE
# undef UNDEF_TRACE_INCLUDE_FILE
#endif#ifdef UNDEF_TRACE_INCLUDE_PATH
# undef TRACE_INCLUDE_PATH
# undef UNDEF_TRACE_INCLUDE_PATH
#endif/* We may be processing more files */
#define CREATE_TRACE_POINTS#endif /* CREATE_TRACE_POINTS */

3、define_trace.h文件中包含trace-events-sample.h后,TRACE_EVENT的展开

以trace-events-sample.h中的TRACE_EVENT为例,说明其在本阶段的展开

TRACE_EVENT(foo_bar,/*trace_foo_bar函数原型*/TP_PROTO(const char *foo, int bar, const int *lst,const char *string, const struct cpumask *mask),/*trace_foo_bar参数列表*/TP_ARGS(foo, bar, lst, string, mask),TP_STRUCT__entry(__array(	char,	foo,    10		) /*char foo[10]*/__field(	int,	bar			)		/*int bar*/__dynamic_array(int,	list,   __length_of(lst)) /*int list[]*/__string(	str,	string			)	/*str的值为string的内容*/__bitmask(	cpus,	num_possible_cpus()	)),/*如何给上述变量赋值*/TP_fast_assign(strlcpy(__entry->foo, foo, 10);__entry->bar	= bar;/*__get_dynamic_array获取list的起始地址*/memcpy(__get_dynamic_array(list), lst,__length_of(lst) * sizeof(int));__assign_str(str, string);__assign_bitmask(cpus, cpumask_bits(mask), num_possible_cpus());),TP_printk("foo %s %d %s %s %s %s (%s)", __entry->foo, __entry->bar,__print_flags(__entry->bar, "|",{ 1, "BIT1" },{ 2, "BIT2" },{ 4, "BIT3" },{ 8, "BIT4" }),__print_array(__get_dynamic_array(list),__get_dynamic_array_len(list) / sizeof(int),sizeof(int)),__get_str(str), __get_bitmask(cpus))
);

 展开后的内容如下:

TRACE_EVENTfoo_bar,宏开始展开,本阶段TRACE_EVENT主要用于 struct tracepoint __tracepoint_##name 结构体定义
static const char __tpstrtab_foo_bar[] __attribute__((section("__tracepoints_strings"))) = "foo_bar"; 
struct tracepoint __tracepoint_foo_bar __attribute__((section("__tracepoints"))) = { __tpstrtab_foo_bar, { .enabled = { 0 }, { .entries = (void *)0UL } }, ((void *)0), ((void *)0), ((void *)0) }; 
static struct tracepoint * const __tracepoint_ptr_foo_bar __attribute__((__used__)) __attribute__((section("__tracepoints_ptrs"))) = &__tracepoint_foo_bar;;

4、在define_trace.h中包含trace_events.h头文件

 如下:

/*包含trace/trace_events.h头文件,在trace_events.h头文件中会多次包含trace-events-sample.h,并对其进行多次展开*/
#include <trace/trace_events.h>

在trace_events.h头文件中,会再次使用老套路#unset和#define来重定义TRACE_EVENT(...)等一系列宏定义后再包含trace-events-sample.h,这样trace-events-sample.h中的宏定义又被再次展开为不同的内容。其实在trace_events.h中会使用#include来包含trace-events-sample.h 七次且每次的展开对应的目的都是不一样的。所以对trace_events.h的分析将是一个体力活儿和脑力活儿。

相关文章:

linux tracepoint系列宏定义(TRACE_EVENT,DEFINE_TRACE等)展开过程分析之三 define_trace.h头文件

在linux tracepoint系列宏定义(TRACE_EVENT,DEFINE_TRACE等)展开过程分析之二 文章中&#xff0c;我们知道trace-events-sample.h 文件在包含了tracepoint.h后第一次对TRACE_EVENT(...)等系列宏定义进行了展开,主要是构建tracepoint 调用钩子函数,注册/注销函数。展开的第二阶段…...

TDengine 与其他时序数据库对比:InfluxDB/TimescaleDB 选型指南(二)

四、应用场景分析 &#xff08;一&#xff09;TDengine 适用场景 TDengine 适用于对写入性能和存储效率要求极高的物联网设备数据采集场景。在一个拥有数百万个传感器的智能工厂中&#xff0c;每个传感器每秒都会产生多条数据&#xff0c;TDengine 能够高效地处理这些高并发的…...

华为OD机试真题——攀登者2(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析&#xff1b; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式&#xff01; 华为OD机试真题《攀登者2》&#xff1a; 目录 题目名称&#xff1a;攀登者2…...

Windows卸载重装Docker

卸载 删除C:\Program Files\Docker &#xff0c;如果更改了路径的就找到相关位置进行删除 删除 C:\Users\<用户名>\.docker 清理注册表&#xff0c;不然重装会报错 Exising installation is up to date 按下WindowR唤起命令输入界面&#xff0c;输入regedit打开注…...

JVM 为什么需要即时编译器?

JVM之所以需要即时编译器 (JIT Compiler)&#xff0c;是为了提高 Java 程序的执行性能&#xff0c;弥补纯解释器执行的不足。 我们可以从以下几个角度来分析一下这个问题&#xff1a; 1. 解释器的性能瓶颈: 逐条解释的开销: 解释器需要逐条读取 Java 字节码指令&#xff0c;并…...

双目视觉中矩阵等参数说明及矫正

以下是标定文件中各个参数的详细解释&#xff1a; 1. 图像尺寸 (imageSize) 参数值: [1280, 1024]含义: 相机的图像分辨率&#xff0c;宽度为1280像素&#xff0c;高度为1024像素。 2. 相机内参矩阵 (leftCameraMatrix / rightCameraMatrix) 结构: yaml data: [fx, 0, cx, 0,…...

Android Compose 框架的列表与集合模块之滑动删除与拖拽深入分析(四十八)

Android Compose 框架的列表与集合模块之滑动删除与拖拽深入分析 一、引言 本人掘金号&#xff0c;欢迎点击关注&#xff1a;https://juejin.cn/user/4406498335701950 1.1 Android Compose 简介 在 Android 开发领域&#xff0c;界面的交互性和用户体验至关重要。传统的 A…...

一、LLM 大语言模型初窥:起源、概念与核心原理

一、初识大模型 1.1 人工智能演进与大模型兴起:从A11.0到A12.0的变迁 AI 1.0时代&#xff08;2012-2022年&#xff09; 感知智能的突破&#xff1a;以卷积神经网络&#xff08;CNN&#xff09;为核心&#xff0c;AI在图像识别、语音处理等感知任务中超越人类水平。例如&#…...

PyTorch核心函数详解:gather与where的实战指南

PyTorch中的torch.gather和torch.where是处理张量数据的关键工具&#xff0c;前者实现基于索引的灵活数据提取&#xff0c;后者完成条件筛选与动态生成。本文通过典型应用场景和代码演示&#xff0c;深入解析两者的工作原理及使用技巧&#xff0c;帮助开发者提升数据处理的灵活…...

《Operating System Concepts》阅读笔记:p636-p666

《Operating System Concepts》学习第 58 天&#xff0c;p636-p666 总结&#xff0c;总计 31 页。 一、技术总结 1.system and network threats (1)attack network traffic (2)denial of service (3)port scanning 2.symmetric/asymmetric encryption algorithm (1)symm…...

Go:接口

接口既约定 Go 语言中接口是抽象类型 &#xff0c;与具体类型不同 &#xff0c;不暴露数据布局、内部结构及基本操作 &#xff0c;仅提供一些方法 &#xff0c;拿到接口类型的值 &#xff0c;只能知道它能做什么 &#xff0c;即提供了哪些方法 。 func Fprintf(w io.Writer, …...

ESP32+Arduino入门(三):连接WIFI获取当前时间

ESP32内置了WIFI模块连接WIFI非常简单方便。 代码如下&#xff1a; #include <WiFi.h>const char* ssid "WIFI名称"; const char* password "WIFI密码";void setup() {Serial.begin(115200);WiFi.begin(ssid,password);while(WiFi.status() ! WL…...

FastAPI用户认证系统开发指南:从零构建安全API

前言 在现代Web应用开发中&#xff0c;用户认证系统是必不可少的功能。本文将带你使用FastAPI框架构建一个完整的用户认证系统&#xff0c;包含注册、登录、信息更新和删除等功能。我们将采用JWT&#xff08;JSON Web Token&#xff09;进行身份验证&#xff0c;并使用SQLite作…...

CSS高度坍塌?如何解决?

一、什么是高度坍塌&#xff1f; 高度坍塌&#xff08;Collapsing Margins&#xff09;是指当父元素没有设置边框&#xff08;border&#xff09;、内边距&#xff08;padding&#xff09;、内容&#xff08;content&#xff09;或清除浮动时&#xff0c;其子元素的 margin 会…...

【数据结构】之散列

一、定义与基本术语 &#xff08;一&#xff09;、定义 散列&#xff08;Hash&#xff09;是一种将键&#xff08;key&#xff09;通过散列函数映射到一个固定大小的数组中的技术&#xff0c;因为键值对的映射关系&#xff0c;散列表可以实现快速的插入、删除和查找操作。在这…...

空地机器人在复杂动态环境下,如何高效自主导航?

随着空陆两栖机器人(AGR)在应急救援和城市巡检等领域的应用范围不断扩大&#xff0c;其在复杂动态环境中实现自主导航的挑战也日益凸显。对此香港大学王俊铭基于阿木实验室P600无人机平台自主搭建了一整套空地两栖机器人&#xff0c;使用Prometheus开源框架完成算法的仿真验证与…...

python小记(十二):Python 中 Lambda函数详解

Python 中 Lambda函数详解 Lambda函数详解&#xff1a;从入门到实战一、什么是Lambda函数&#xff1f;二、Lambda的核心语法与特点1. 基础语法2. 与普通函数对比 三、Lambda的六大应用场景&#xff08;附代码示例&#xff09;1. 基本数学运算2. 列表排序与自定义规则3. 数据映射…...

第二十一讲 XGBoost 回归建模 + SHAP 可解释性分析(利用R语言内置数据集)

下面我将使用 R 语言内置的 mtcars 数据集&#xff0c;模拟一个完整的 XGBoost 回归建模 SHAP 可解释性分析 实战流程。我们将以预测汽车的油耗&#xff08;mpg&#xff09;为目标变量&#xff0c;构建 XGBoost 模型&#xff0c;并用 SHAP 来解释模型输出。 &#x1f697; 示例…...

数据分析实战案例:使用 Pandas 和 Matplotlib 进行居民用水

原创 IT小本本 IT小本本 2025年04月15日 18:31 北京 本文将使用 Matplotlib 及 Seaborn 进行数据可视化。探索如何清理数据、计算月度用水量并生成有价值的统计图表&#xff0c;以便更好地理解居民的用水情况。 数据处理与清理 读取 Excel 文件 首先&#xff0c;我们使用 pan…...

Asp.NET Core WebApi 创建带鉴权机制的Api

构建一个包含 JWT&#xff08;JSON Web Token&#xff09;鉴权的 Web API 是一种常见的做法&#xff0c;用于保护 API 端点并验证用户身份。以下是一个基于 ASP.NET Core 的完整示例&#xff0c;展示如何实现 JWT 鉴权。 1. 创建 ASP.NET Core Web API 项目 使用 .NET CLI 或 …...

hash.

Redis 自身就是键值对结构 Redis 自身的键值对结构就是通过 哈希 的方式来组织的 哈希类型中的映射关系通常称为 field-value&#xff0c;用于区分 Redis 整体的键值对&#xff08;key-value&#xff09;&#xff0c; 注意这里的 value 是指 field 对应的值&#xff0c;不是键…...

记录鸿蒙应用上架应用未配置图标的前景图和后景图标准要求尺寸1024px*1024px和标准要求尺寸1024px*1024px

审核报错【①应用未配置图标的前景图和后景图,标准要求尺寸1024px*1024px且需下载HUAWEI DevEco Studio 5.0.5.315或以上版本进行图标再处理、②应用在展开状态下存在页面左边距过大的问题, 应用在展开状态下存在页面右边距过大的问题, 当前页面左边距: 504 px, 当前页面右边距…...

golang-常见的语法错误

https://juejin.cn/post/6923477800041054221 看这篇文章 Golang 基础面试高频题详细解析【第一版】来啦&#xff5e; 大叔说码 for-range的坑 func main() { slice : []int{0, 1, 2, 3} m : make(map[int]*int) for key, val : range slice {m[key] &val }for k, v : …...

Google最新《Prompt Engineering》白皮书全解析

近期有幸拿到了Google最新发布的《Prompt Engineering》白皮书&#xff0c;这是一份由Lee Boonstra主笔&#xff0c;Michael Sherman、Yuan Cao、Erick Armbrust、Antonio Gulli等多位专家共同贡献的权威性指南&#xff0c;发布于2025年2月。今天我想和大家分享这份68页的宝贵资…...

如何快速部署基于Docker 的 OBDIAG 开发环境

很多开发者对 OceanBase的 SIG社区小组很有兴趣&#xff0c;但如何将OceanBase的各类工具部署在开发环境&#xff0c;对于不少开发者而言都是比较蛮烦的事情。例如&#xff0c;像OBDIAG&#xff0c;其在WINDOWS系统上配置较繁琐&#xff0c;需要单独搭建C开发环境。此外&#x…...

[LeetCode 1306] 跳跃游戏3(Ⅲ)

题面&#xff1a; LeetCode 1306 思路&#xff1a; 只要能跳到其中一个0即可&#xff0c;和跳跃游戏1/2完全不同了&#xff0c;记忆化暴搜即可。 时间复杂度&#xff1a; O ( n ) O(n) O(n) 空间复杂度&#xff1a; O ( n ) O(n) O(n) 代码&#xff1a; dfs vector<…...

spring-ai-alibaba使用Agent实现智能机票助手

示例目标是使用 Spring AI Alibaba 框架开发一个智能机票助手&#xff0c;它可以帮助消费者完成机票预定、问题解答、机票改签、取消等动作&#xff0c;具体要求为&#xff1a; 基于 AI 大模型与用户对话&#xff0c;理解用户自然语言表达的需求支持多轮连续对话&#xff0c;能…...

STM32平衡车开发实战教程:从零基础到项目精通

STM32平衡车开发实战教程&#xff1a;从零基础到项目精通 一、项目概述与基本原理 1.1 平衡车工作原理 平衡车是一种基于倒立摆原理的两轮自平衡小车&#xff0c;其核心控制原理类似于人类保持平衡的过程。当人站立不稳时&#xff0c;会通过腿部肌肉的快速调整来维持平衡。平…...

使用DeepSeek AI高效降低论文重复率

一、论文查重原理与DeepSeek降重机制 1.1 主流查重系统工作原理 文本比对算法:连续字符匹配(通常13-15字符)语义识别技术:检测同义替换和结构调整参考文献识别:区分合理引用与不当抄袭跨语言检测:中英文互译内容识别1.2 DeepSeek降重核心技术 深度语义理解:分析句子核心…...

linux多线(进)程编程——(7)消息队列

前言 现在修真界大家的沟通手段已经越来越丰富了&#xff0c;有了匿名管道&#xff0c;命名管道&#xff0c;共享内存等多种方式。但是随着深入使用人们逐渐发现了这些传音术的局限性。 匿名管道&#xff1a;只能在有血缘关系的修真者&#xff08;进程&#xff09;间使用&…...