再看內核的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函數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM