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
#include <trace/events/fuse.h>

if (!strncmp(current->comm, "stat", strlen("stat"))) {
    trace_fuse_lookup_pre_inode(entry->d_inode, entry->d_name.name);
}

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 */
#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_inode的模板 */

DECLARE_EVENT_CLASS(fuse_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_STRUCT__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("fuse inode info:file=%s ino=%llu count=%d nlink=%u",
              __entry->name, __entry->ino, __entry->count, __entry->nlink)
);

/* 定义一个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,
 
     TP_PROTO(struct inode *inode, const unsigned char *name),
 
     TP_ARGS(inode, name)
 );


#endif /* _TRACE_FUSE_H */

 /* This part must be outside protection */
#include <trace/define_trace.h>

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

}

posted @ 2023-03-15 07:45  geshifei  阅读(137)  评论(0编辑  收藏  举报  来源