linux trace point机制2--增加trace event
为fuse模块新增trace event,执行stat命令时,记录trace,输出inode的信息。
一、trace event定义
include\trace\events目录下新增fuse.h文件
/* SPDX-License-Identifier: GPL-2.0 */ #undef TRACE_SYSTEM /* 在/d/tracing(软链接指向/sys/kernel/debug/tracing)生成fuse目录,对应fuse子系统 */ #define TRACE_SYSTEM fuse /* _TRACE_FUSE_H尾缀与本头文件名fuse.h对应*/ #if !defined(_TRACE_FUSE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_FUSE_H #include <linux/types.h> #include <linux/tracepoint.h> /* fuse_lookup_pre_inode对应trace event函数名 即通过trace_fuse_lookup_pre_inode可以调用本trace */ TRACE_EVENT(fuse_lookup_pre_inode,
/* TP_PROTO定义trace_fuse_lookup_pre_inode的参数类型 TP_ARGS定义trace_fuse_lookup_pre_inode的参数名称 */ TP_PROTO(struct inode *inode, const unsigned char *name), TP_ARGS(inode, name), /* TP_STRUCT__entry定义待输出的信息字段 */ TP_STRUCT__entry( __field(const unsigned char *, name) __field(ino_t, ino) __field(int, count) __field(unsigned int, nlink) ), /* TP_fast_assign设置entry字段的值 */ TP_fast_assign( __entry->name = name; __entry->ino = inode->i_ino; __entry->count = atomic_read(&inode->i_count); __entry->nlink = inode->i_nlink; ), /* TP_printk输出entry信息 ,即trace log*/ TP_printk("inode info:file=%s ino=%llu count=%d nlink=%u", __entry->name, __entry->ino, __entry->count, __entry->nlink) ); #endif /* _TRACE_FUSE_H */ /* This part must be outside protection */ #include <trace/define_trace.h> |
二、c源文件调用trace函数
首先定义CREATE_TRACE_POINTS及include相关头文件。
然后再源文件中需要trace的地方,调用函数“trace_定义的event名”即可。
#define CREATE_TRACE_POINTS if (!strncmp(current->comm, "stat", strlen("stat"))) { |
NOTE:
务必要定义#define CREATE_TRACE_POINTS,并且要在#include <trace/events/fuse.h>前(多个c文件include该头文件,只需在一个c文件中定义CREATE_TRACE_POINTS,不需要在每个c文件中都定义),否则会出现下面的错误。
CC [M] kernel/kheaders.o GEN .version CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o AR init/built-in.o AR built-in.o LTO vmlinux.o MODPOST vmlinux.o ld.lld: error: undefined symbol: __tracepoint_fuse_lookup_pre_inode >>> referenced by compiler.h:183 (/work/android11/kernel-4.14/include/linux/compiler.h:183) >>> vmlinux.o:(fuse_lookup$2d8041ac8bc8b814b20f8728a0064873) >>> referenced by compiler.h:183 (/work/android11/kernel-4.14/include/linux/compiler.h:183) >>> vmlinux.o:(fuse_lookup$2d8041ac8bc8b814b20f8728a0064873) >>> referenced by compiler.h:183 (/work/android11/kernel-4.14/include/linux/compiler.h:183) >>> vmlinux.o:(fuse_lookup$2d8041ac8bc8b814b20f8728a0064873) >>> referenced by compiler.h:183 (/work/android11/kernel-4.14/include/linux/compiler.h:183) >>> vmlinux.o:(fuse_lookup$2d8041ac8bc8b814b20f8728a0064873) >>> referenced by win_minmax.c >>> vmlinux.o:(__ksymtab___tracepoint_fuse_lookup_pre_inode) |
三、抓trace log
cp15:/ # cd /d/tracing 或者 cd /sys/kernel/debug/tracing
cp15:/d/tracing # echo fuse:* > set_event
cp15:/d/tracing # echo "" > trace
cp15:/d/tracing # echo 1 > tracing_on
然后执行stat命令查看一个文件属性。
cp15:/d/tracing # echo 0 > tracing_on
adb pull /d/tracing/trace 把trace从手机上pull出来,即可看到增加的trace log。
四、DECLARE_EVENT_CLASS增加多个同类型trace event
上面展示了用TRACE_EVENT增加一个trace event,如果需要在源文件多个地方trace相同的信息,是不是多次调用trace event定义的那个函数就可以了?
答案是不可以。注意看trace输出的log:
stat-5228 [006] .... 191.175084: fuse_lookup_pre_inode: pre inof:file=Camera ino=13666 count=1 nlink=2
log中仅有func name字段即fuse_lookup_pre_inode可以识别出该log是哪里输出的,不同的地方调用trace_fuse_lookup_pre_inode,输出的log都是上面那样的,我们没法识别出该条log对应源码的哪个位置。
内核提供了DECLARE_EVENT_CLASS可以方便地满足我们的需求。
include\trace\events\fuse.h文件改成:
/* SPDX-License-Identifier: GPL-2.0 */ /* _TRACE_FUSE_H尾缀与本头文件名fuse.h对应*/ #if !defined(_TRACE_FUSE_H) || defined(TRACE_HEADER_MULTI_READ) #include <linux/types.h> /* 定义了一个名为fuse_inode的模板 */ DECLARE_EVENT_CLASS(fuse_inode, /* 模板的参数类型、参数名称 */ TP_PROTO(struct inode *inode, const unsigned char *name), /* TP_STRUCT__entry定义待输出的信息字段 */ TP_STRUCT__entry( /* TP_STRUCT__entry定义待输出的信息字段 */ TP_fast_assign( /* TP_printk输出entry信息,即trace log */ TP_printk("fuse inode info:file=%s ino=%llu count=%d nlink=%u", /* 定义一个trace event,注意宏的名称跟第一节中的TRACE_EVENT名称不同 */ DEFINE_EVENT(fuse_inode, fuse_lookup_pre_inode, TP_PROTO(struct inode *inode, const unsigned char *name), TP_ARGS(inode, name) /* 另一个trace event */ DEFINE_EVENT(fuse_inode, fuse_lookup_post_inode,
/* This part must be outside protection */ |
c源文件示例:
#define CREATE_TRACE_POINTS #include <trace/events/fuse.h> if (entry->d_inode) { struct kstat stat trace_fuse_lookup_pre_inode(entry->d_inode, entry->d_name.name); fuse_update_get_attr(entry->d_inode, NULL, &stat, entry->d_name.name); trace_fuse_lookup_post_inode(entry->d_inode, entry->d_name.name); } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步