一 文档说明
本文为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