再看内核的frace架构, tracepoint宏扩展

再看内核的ftrace架构

如何在tracepoint上注册函数

在上面这篇文章中,我们知道了如何在函数中tracepoint上注册函数,那么是谁搭建的这个平台呢?内核中ftrace平台

register_trace_##name  

tracepoint_probe_register_prio

__DECLARE_TRACE

DEFINE_TRACE

把所有注册tracepoint的函数都抽象出来了做成了宏。

trace_##name 函数是真正的trace函数

trace_sched_switch后面是如何扩展开来的?

trace_sched_switch并不是系统的函数,包括在最后的符号表中也没有trace_sched_switch这个函数存在,其实trace_sched_switch是个宏里,

扩展trace_sched_switch

1) step1: include/trace/events/sched.h函数中, TRACE_EVENT(sched_switch...)
2)step2: TARCE_EVENT(line 483)-->DECLARE_TRACE(347)-->__DECLARE_TRACE(181),逐渐就把整个宏给扩展开来了,
__DECLARE_TRACE中生成了许多的函数:包括
   static inline void trace_sched_switch
           static inline int register_trace_prio_sched_switch
           static inline int unregister_trace_prio_sched_switch
           static inline void check_trace_callback_type_##name(void (*cb)(data_proot)
           static inline bool trace_sched_switch_enable(void);
所以呢,在函数kernel/sched/core.c函数中当有下面的#include <sched.h>函数时,其实在这个文件中新增加了这样三个函数,所以在sched/sched/core.c中函数中直接调用了trace_sched_switch函数是可以的,看下这个函数的内容是啥
183     static inline void trace_##name(proto)              
184     {                               
185         if (static_key_false(&__tracepoint_##name.key))     
186             __DO_TRACE(&__tracepoint_##name,        
187                 TP_PROTO(data_proto),           
188                 TP_ARGS(data_args),         
189                 TP_CONDITION(cond),,);          
190         if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) {     
191             rcu_read_lock_sched_notrace();          
192             rcu_dereference_sched(__tracepoint_##name.funcs);
193             rcu_read_unlock_sched_notrace();        
194         }                           
195     }                               

static key机制就是在这里生效的,这个tracpoing的结构体是在在哪里注册的呢?

所以呢,在哪个地方肯定是生成了static key, __tracepoint_sched_switch了,到这里都是trace point机制,那么这个tracepoint结构体的定义以及初始化是在哪里完成的呢?,

然后在每个include/trace/events/sched.h文件的最末尾都会有:include<trace/define_trace.h>,这个文件中又会对TRACE_EVENT 进一步扩展,首先上来,TRACE_EVENT会被扩展成tracepoint结构体

3) DEFINE_TRACE->DEFINE_TRACE_FN,(include/linux/tracepint.h)

在这个函数中,所有的tracepoint结构被初始化了, struct tracepoint __tracepoint_sched_swtich

/*
 * We have no guarantee that gcc and the linker won't up-align the tracepoint
 * structures, so we create an array of pointers that will be used for iteration
 * on the tracepoints.
 */
#define DEFINE_TRACE_FN(name, reg, unreg)                
    static const char __tpstrtab_##name[]                
    __attribute__((section("__tracepoints_strings"))) = #name;   
    struct tracepoint __tracepoint_##name                
    __attribute__((section("__tracepoints"))) =          
        { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };
    static struct tracepoint * const __tracepoint_ptr_##name __used  
    __attribute__((section("__tracepoints_ptrs"))) =         
        &__tracepoint_##name;

 看下tracepoint的结构体长啥样子,

 29 struct tracepoint {
 30     const char *name;       /* Tracepoint name */
 31     struct static_key key;
 32     void (*regfunc)(void);
 33     void (*unregfunc)(void);
 34     struct tracepoint_feveunc __rcu *funcs;
 35 };

 所以在这里算是声明好了这个tracepoint。

综合上面两部分,tracepoint相关的注册函数等都设置好了,包括tracepoint结构体,还有该tracepoint相关的注册函数,但是缺少怎么使能tracetpoint,已经tracepoint输出函数是怎么导入到ftrace缓冲区

4)step4:)在文件trace/ trace_events.h文件中,还没完呢,还有include <trace/trace_events.h>

结果在这个函数中,还有include<linux/trace_events.h>

TRACE_EVENT->DEFINE_EVENT

define_event包含两个宏,一个是DECLARE_EVENT_CLASS,一个是DEFINE_EVENT,

这里是直接把函数给调用

#undef DEFINE_EVENT
#define DEFINE_EVENT(template, call, proto, args)           
                                    
static struct trace_event_call __used event_##call = {          
    .class          = &event_class_##template,      
    {                               
        .tp         = &__tracepoint_##call,     
    },                              
    .event.funcs        = &trace_event_type_funcs_##template,   
    .print_fmt      = print_fmt_##template,         
    .flags          = TRACE_EVENT_FL_TRACEPOINT,        
};                                  
static struct trace_event_call __used                   
__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call

 这里出现了一个新的结构体叫trace_event_call

#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)  
static notrace enum print_line_t                    
trace_raw_output_##call(struct trace_iterator *iter, int flags,     
            struct trace_event *trace_event)        
{                                   
    struct trace_seq *s = &iter->seq;               
    struct trace_seq __maybe_unused *p = &iter->tmp_seq;        
    struct trace_event_raw_##call *field;               
    int ret;                            
                                    
    field = (typeof(field))iter->ent;               
                                    
    ret = trace_raw_output_prep(iter, trace_event);         
    if (ret != TRACE_TYPE_HANDLED)                  
        return ret;                     
                                    
    trace_seq_printf(s, print);                 
                                    
    return trace_handle_return(s);                  
}                                   
static struct trace_event_functions trace_event_type_funcs_##call = {   
    .trace          = trace_raw_output_##call,      
};

 这个文件中果然都是和trace的输出相关的,主要生成的函数包括:

static void trace_event_raw_event_sched_switch(void *_data, proto);

enum print_line_t trace_raw_output_sched_switch(struct trace_iterator *iter, int flags);

struct trace_event_data_offset_sched_switch {

  pid_t pid;

       ......

}

struct trace_event_raw_sched_switch {

  struct trace_entry ent;

      .....

}

都是和输出相关的。

这些函数都是怎么联系到一起的呢?trace_raw_output_sched_switch函数在哪里会使用呢

struct trace_event_functions trace_event_type_funcs_sched_switch 函数

大boss要出现了:

static struct trace_event_call __used event_##call = {          
    .class          = &event_class_##template,      
    {                               
        .tp         = &__tracepoint_##call,     
    },                              
    .event.funcs        = &trace_event_type_funcs_##template,   
    .print_fmt      = print_fmt_##template,         
    .flags          = TRACE_EVENT_FL_TRACEPOINT,        
};                                  
static struct trace_event_call __used                   
__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call

在__ftrace_events段中这个函数,那么这个段应该是个数组吧,所有的tracepoint事件都会放到一个数组里,将来是怎么索引的呢?

event_trace_enable函数

原文地址:https://www.cnblogs.com/honpey/p/9256279.html