• 再看内核的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函数

  • 相关阅读:
    jQuery 从无到有.一天完成.
    JavaScript从无到有(一天完成)
    HTML(第一篇)
    前端认识
    三元表达式,列表推导是,字典生成式
    ORM之youku项目小练习(上)
    高逼格壁纸
    pymysql 基操全套
    怎么学好编程?
    mysql 事务
  • 原文地址:https://www.cnblogs.com/honpey/p/9256279.html
Copyright © 2020-2023  润新知