Bootstrap

linux ftrace追踪一(基本技术结构粗略剖析)


一   文档说明

本文为2.6.32下trace机制(以下简称trace)的调研文档。trace实现的基础为tracepoint机制,存放数据的缓存实现为ring buffer。

阅读代码路径:

samples/tracepoints

kernel/trace

include/trace

二   tracepoint

tracepoint是实现ftrace架构的基础。在内核代码路径samples/tracepoint下对tracepoint有个简单的实例。

struct tracepoint {

       constchar *name;          /* Tracepoint name */

       intstate;                /* State. */

       void(*regfunc)(void);

       void(*unregfunc)(void);

       void**funcs;

} __attribute__((aligned(32)));

2.1 两个宏定义

这两个宏传递的name是一致的。

2.1.1   DEFINE_TRACE(name);

该宏定义如下:

#define DEFINE_TRACE_FN(name, reg,unreg)                            \

       staticconst char __tpstrtab_##name[]                        \

       __attribute__((section("__tracepoints_strings")))= #name; \

       structtracepoint __tracepoint_##name                       \

       __attribute__((section("__tracepoints"),aligned(32))) =     \

              {__tpstrtab_##name, 0, reg, unreg, NULL }

 

#define DEFINE_TRACE(name)                                     \

    DEFINE_TRACE_FN(name, NULL,NULL);

在内核初始化时分配了__tracepoints_strings,__tracepoints这两个section。当利用DEFINE_TRACE定义一个tracepoint后,整个内核将可以看到该tracepoint。

2.1.2   DECLARE_TRACE(name, proto, args)

#define DECLARE_TRACE(name, proto,args)                       \

       externstruct tracepoint __tracepoint_##name;                   \

       staticinline void trace_##name(proto)                       \

       {                                                      \

              if(unlikely(__tracepoint_##name.state))             \

                     __DO_TRACE(&__tracepoint_##name,             \

                            TP_PROTO(proto),TP_ARGS(args));  \

       }                                                      \

       staticinline int register_trace_##name(void (*probe)(proto))     \

       {                                                      \

              returntracepoint_probe_register(#name, (void *)probe);    \

       }                                                      \

       staticinline int unregister_trace_##name(void (*probe)(proto))  \

       {                                                      \

              returntracepoint_probe_unregister(#name, (void *)probe);\

           }

       该宏定义了三个函数:

       trace_##name:放在想抓trace的代码路径中。

       register_trace_##name:注册一个钩子函数,这个钩子函数在trace_##name执行的时候被调用。

       unregister_trace_##name:注销一个钩子函数。

2.2钩子函数是怎样被注册的

当用以上两个宏定义并声明了一个tracepoint之后,在抓取trace之前调用上文的register_trace_##name函数,完成钩子函数的注册。但是如果仅仅是注册了针对某一个tracepoint的钩子函数,目前内核中的处理是更新内核中目前所有的tracepoint。感觉这一点是不合理的。

函数原型:int tracepoint_probe_register(const char *name, void *probe)

tracepoint钩子函数的注册与撤销是通过一个哈希表来维护的。当注册或撤销钩子函数结束后,同步到tracepoint中。至于这个哈希表和tracepoint的联系完全依赖于定义tracepoint时的名字。在哈希表中存放的数据结构:

struct tracepoint_entry {

       structhlist_node hlist;

       void**funcs;

       intrefcount;    /* Number of times armed. 0

;