• tracer ftrace笔记(8)—— TRACE_EVENT 展开 Hello


    基于Linux-5.10,与解析相关的环境是默认使能 CONFIG_PERF_EVENTS CONFIG_MODULES CONFIG_TRACEPOINTS。默认关闭的是 CONFIG_HAVE_STATIC_CALL


    一、用户trace头文件格式说明

    1. 一般用户定义的trace头文件格式如下,这是精简只保留原生内核 sched.h 的一个 TRACE_EVENT 的例子。

    /*----摘取 include/trace/events/sched.h ----*/
    
    /* 1. 需要和头文件名相同,在后面包含头文件的宏中有使用到 */
    #undef TRACE_SYSTEM
    #define TRACE_SYSTEM sched
    
    /*
     * 2. 头文件放递归包含需要在定义 TRACE_HEADER_MULTI_READ 宏的情况下网开一面,
     * 因为后续会通过多次#include此头文件并配合#def/#undef来进行展开。
     */
    #if !defined(_TRACE_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
    #define _TRACE_SCHED_H
    
    /* 3. 包含这个文件,里面保存有最初的define */
    #include <linux/tracepoint.h>
    
    /* 4. 定义自己的 TRACE_EVENT */
    /*
     * Tracepoint for recording the cause of uninterruptible sleep.
     */
    TRACE_EVENT(sched_blocked_reason,
    
        TP_PROTO(struct task_struct *tsk),
    
        TP_ARGS(tsk),
    
        TP_STRUCT__entry(
            __field( pid_t,    pid    )
            __field( void*, caller    )
            __field( bool, io_wait    )
        ),
    
        TP_fast_assign(
            __entry->pid    = tsk->pid;
            __entry->caller = (void *)get_wchan(tsk);
            __entry->io_wait = tsk->in_iowait;
        ),
    
        TP_printk("pid=%d iowait=%d caller=%pS", __entry->pid, __entry->io_wait, __entry->caller)
    );
    
    /* 5. 防递归包含结束位置 */
    #endif /* _TRACE_SCHED_H */
    
    /*
     * 6. 在防递归保护之外包含 define_trace.h 文件,它会多次包含次头文件,
     * 并对 TRACE_EVENT 宏进行不同的解析
     */
    /* This part must be outside protection */
    #include <trace/define_trace.h>

    2. TRACE_SYSTEM 用于定义跟踪点系统,若是它和trace头文件名不同的话,还需要定义 TRACE_INCLUDE_FILE 宏还指定trace头文件名(不包括.h),若是用户定义的trace头文件不是放在 include/trace/events/ 目录下的,还需要定义 TRACE_INCLUDE_PATH 宏来指定trace头文件的路径,注意这个路径是相对于define_trace.h 的,也有些文件定义为.(当前路径)。可参考 drivers/gpu/drm/drm_trace.h 中的定义。

    3. linux/tracepoint.h 中定义了一些宏,但是这些宏在下面 trace/define_trace.h 中可能会重新定义。

    4. CREATE_TRACE_POINTS 宏若是没有定义 include/trace/define_trace.h 就是空文件,define_trace.h 在处理中会 #undef CREATE_TRACE_POINTS,在编译处理完退出时又重新定义上 CREATE_TRACE_POINTS 宏,也就是说 define_trace.h 文件处理时是屏蔽这个宏的,处理完就还原为之前状态。若.c在包含用户trace文件之前没有定义 CREATE_TRACE_POINTS 宏,那么 TRACE_EVENT() 宏只按 linux/tracepoint.h 中的define解析一次,下面会列出解析结果。

    没有定义 CREATE_TRACE_POINTS 就包好用户trace头文件的C文件只是使用端,定义 CREATE_TRACE_POINTS 的是实现端。也就是说用户指定的trace头文件,只能有一个.c文件中可以在包含之前定义 CREATE_TRACE_POINTS 宏。举例如下:

    /*---- kernel/sched/core.c ----*/
    #define CREATE_TRACE_POINTS
    #include <trace/events/sched.h>
    #undef CREATE_TRACE_POINTS
    
    /*---- 其它所有文件中都是没有定义的 ----*/
    //kernel/exit.c
    #include <trace/events/sched.h>
    //kernel/fork.c
    #include <trace/events/sched.h>
    ...

    5. 在 trace/define_trace.h 中有如下定义,对于上面举例的 trace/sched.h 头文件,里面没有定义 TRACE_INCLUDE_FILE 和 TRACE_INCLUDE_PATH,因此#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) 就是 #include <trace/events/system.h>。

    /*---- linux/define_trace.h ----*/
    #ifndef TRACE_INCLUDE_FILE
    # define TRACE_INCLUDE_FILE TRACE_SYSTEM
    # define UNDEF_TRACE_INCLUDE_FILE
    #endif
    
    #ifndef TRACE_INCLUDE_PATH
    # define __TRACE_INCLUDE(system) <trace/events/system.h>
    # define UNDEF_TRACE_INCLUDE_PATH
    #else
    # define __TRACE_INCLUDE(system) __stringify(TRACE_INCLUDE_PATH/system.h)
    #endif
    
    # define TRACE_INCLUDE(system) __TRACE_INCLUDE(system)
    
    /* 就是通过它来多次包含用户的trace头文件的 */
    #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

    对于 drm/drm_trace.h,定义了这两个宏,#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) 就是 #include "../../drivers/gpu/drm/drm_trace.h"

    #undef TRACE_SYSTEM
    #define TRACE_SYSTEM drm
    #define TRACE_INCLUDE_FILE drm_trace
    ...
    #undef TRACE_INCLUDE_PATH
    #define TRACE_INCLUDE_PATH ../../drivers/gpu/drm
    /* 在包含这个头文件之前定义 */
    #include <trace/define_trace.h>

    6. 注意:

    (1) include/linux/tracepoint.h 中只是部分位置有防递归包含保护,没有防递归保护的位置通过 "#ifndef DECLARE_TRACE" 和 "#ifndef TRACE_EVENT" 来防止重复define。
    (2) demo_trace.h 中也只是部分位置有防递归包含保护,并且对有 TRACE_HEADER_MULTI_READ 定义时网开一面。
    (3) trace/define_trace.h 中没有递归保护,但是若未定义 CREATE_TRACE_POINTS 就会空文件。

    二、TRACE_EVENT 宏在没有定义 CREATE_TRACE_POINTS 的情况下展开

    1. 实验 demo_trace.h 文件

    /* 1. 需要和头文件名相同,在后面包含头文件的宏中有使用到 */
    #undef TRACE_SYSTEM
    #define TRACE_SYSTEM demo_sfl
    /*
     * 加这个宏表示用户trace头文件是 demo_trace.h,若不定义就表
     * 示用户trace头文件是 TRACE_SYSTEM.h。此时 TRACE_SYSTEM 宏
     * 就要和用户trace头文件同名。
     */
    #define TRACE_INCLUDE_FILE demo_trace
    /*
     * 2. 头文件放递归包含需要在定义 TRACE_HEADER_MULTI_READ 宏的情况下网开一面,
     * 因为后续会通过多次#include此头文件并配合#def/#undef来进行展开。
     */
    #if !defined(_TRACE_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
    #define _TRACE_SCHED_H
    
    /* 3. 包含这个文件,里面保存有最初的define */
    #include <linux/tracepoint.h>
    
    /* 4. 定义自己的 TRACE_EVENT */
    /*
     * Tracepoint for recording the cause of uninterruptible sleep.
     */
    TRACE_EVENT(sched_blocked_reason,
    
        TP_PROTO(struct task_struct *tsk),
    
        TP_ARGS(tsk),
    
        TP_STRUCT__entry(
            __field( pid_t,    pid    )
            __field( void*, caller    )
            __field( bool, io_wait    )
        ),
    
        TP_fast_assign(
            __entry->pid    = tsk->pid;
            __entry->caller = (void *)get_wchan(tsk);
            __entry->io_wait = tsk->in_iowait;
        ),
    
        TP_printk("pid=%d iowait=%d caller=%pS", __entry->pid, __entry->io_wait, __entry->caller)
    );
    
    
    /* 5. 防递归包含结束位置 */
    #endif /* _TRACE_SCHED_H */
    
    /*
     * 指定用户trace头文件路径是当前路径,若不指定,在重复解析用户trace头文件时,
     * 就去 include/trace/events 目录下找用户trace头文件了。
     */
    #undef TRACE_INCLUDE_PATH
    #define TRACE_INCLUDE_PATH    .
    /*
     * 6. 在防递归保护之外包含 define_trace.h 文件,它会多次包含次头文件,
     * 并对 TRACE_EVENT 宏进行不同的解析
     */
    /* This part must be outside protection */
    #include <trace/define_trace.h>

    2. 实验 tmp.c 文件

    #define CONFIG_HAVE_SYSCALL_TRACEPOINTS 1
    #define CONFIG_HAVE_ARCH_PREL32_RELOCATIONS 1
    #define CONFIG_TRACING 1
    //#define MODULE 1 //编译成ko才定义
    /*
     * 在没有define CREATE_TRACE_POINTS 的情况下,
     * 这三个无论是否define了解析出来是完全一样的。
     */
    #define CONFIG_PERF_EVENTS 1
    #define CONFIG_KPROBE_EVENTS 1
    #define CONFIG_UPROBE_EVENTS 1
    #define CONFIG_BPF_EVENTS 1 //-------------------------------------------- //#define CREATE_TRACE_POINTS #include "demo_trace.h" //#undef CREATE_TRACE_POINTS int main() { return 0; }

    3. 先 export C_INCLUDE_PATH=. 然后 gcc -E 解析整理结果

    struct static_call_key;
    
    struct trace_print_flags {
        unsigned long mask;
        const char *name;
    };
    
    struct trace_print_flags_u64 {
        unsigned long long mask;
        const char *name;
    };
    
    struct tracepoint_func {
        void *func;
        void *data;
        int prio;
    };
    
    struct tracepoint {
        const char *name;
        struct static_key key;
        struct static_call_key *static_call_key;
        void *static_call_tramp;
        void *iterator;
        int (*regfunc)(void);
        void (*unregfunc)(void);
        struct tracepoint_func __rcu *funcs;
    };
    
    typedef const int tracepoint_ptr_t;
    
    
    struct bpf_raw_event_map {
        struct tracepoint *tp;
        void *bpf_func;
        u32 num_args;
        u32 writable_size;
    } __aligned(32);
    
    static inline int static_call_init(void) { return 0; }
    
    struct static_call_key {
        void *func;
    };
    
    static inline void __static_call_nop(void) { }
    
    static inline void __static_call_update(struct static_call_key *key, void *tramp, void *func)
    {
        WRITE_ONCE(key->func, func);
    }
    
    static inline int static_call_text_reserved(void *start, void *end)
    {
        return 0;
    }
    
    struct module;
    struct tracepoint;
    struct notifier_block;
    
    struct trace_eval_map {
        const char *system;
        const char *eval_string;
        unsigned long eval_value;
    };
    
    extern struct srcu_struct tracepoint_srcu;
    
    extern int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);
    extern int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, int prio);
    extern int tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, void *data, int prio);
    extern int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data);
    static inline int tracepoint_probe_register_may_exist(struct tracepoint *tp, void *probe, void *data)
    {
        return tracepoint_probe_register_prio_may_exist(tp, probe, data, 10);
    }
    extern void for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), void *priv);
    
    
    struct tp_module {
        struct list_head list;
        struct module *mod;
    };
    
    bool trace_module_has_bad_taint(struct module *mod);
    extern int register_tracepoint_module_notifier(struct notifier_block *nb);
    extern int unregister_tracepoint_module_notifier(struct notifier_block *nb);
    
    static inline void tracepoint_synchronize_unregister(void)
    {
        synchronize_srcu(&tracepoint_srcu);
        synchronize_rcu();
    }
    
    
    extern int syscall_regfunc(void);
    extern void syscall_unregfunc(void);
    
    static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
    {
        return offset_to_ptr(p);
    }
    
    
    
    
    /* .c文件在没有define CREATE_TRACE_POINTS 的情况下,TRACE_EVENT 只展开一次,从这里开始,如下:*/
    
    extern int __traceiter_sched_blocked_reason(void *__data, struct task_struct *tsk);
    DECLARE_STATIC_CALL(tp_func_sched_blocked_reason, __traceiter_sched_blocked_reason);
    extern struct tracepoint __tracepoint_sched_blocked_reason;
    
    static inline void __nocfi trace_sched_blocked_reason(struct task_struct *tsk)
    {
        if (static_key_false(&__tracepoint_sched_blocked_reason.key))
            do {
                struct tracepoint_func *it_func_ptr;
                int __maybe_unused __idx = 0;
                void *__data;
                if (!(cpu_online(raw_smp_processor_id())))
                    return;
                WARN_ON_ONCE(0 && in_nmi());
                preempt_disable_notrace();
                if (0) {
                    __idx = srcu_read_lock_notrace(&tracepoint_srcu);
                    rcu_irq_enter_irqson();
                }
                it_func_ptr = rcu_dereference_raw((&__tracepoint_sched_blocked_reason)->funcs);
                if (it_func_ptr) {
                    __data = (it_func_ptr)->data;
                    __traceiter_sched_blocked_reason(__data, tsk);
                }
                if (0) {
                    rcu_irq_exit_irqson();
                    srcu_read_unlock_notrace(&tracepoint_srcu, __idx);
                } preempt_enable_notrace();
            } while (0);
            
        if (IS_ENABLED(CONFIG_LOCKDEP) && (cpu_online(raw_smp_processor_id()))) {
            rcu_read_lock_sched_notrace();
            rcu_dereference_sched(__tracepoint_sched_blocked_reason.funcs);
            rcu_read_unlock_sched_notrace();
        }
    }
    
    /*
     * 这个 MODULE 宏判断是解析后手动添加上去的,只有编译成ko才会有这个宏定义,
     * 编译进内核是没有这个宏定义的
     */
    #ifndef MODULE
    static inline void trace_sched_blocked_reason_rcuidle(struct task_struct *tsk)
    {
        if (static_key_false(&__tracepoint_sched_blocked_reason.key))
            do {
                struct tracepoint_func *it_func_ptr;
                int __maybe_unused __idx = 0;
                void *__data;
    
                if (!(cpu_online(raw_smp_processor_id())))
                    return;
                WARN_ON_ONCE(1 && in_nmi());
                preempt_disable_notrace();
                if (1) {
                    __idx = srcu_read_lock_notrace(&tracepoint_srcu);
                    rcu_irq_enter_irqson();
                }
                it_func_ptr = rcu_dereference_raw((&__tracepoint_sched_blocked_reason)->funcs);
                if (it_func_ptr) {
                    __data = (it_func_ptr)->data;
                    __traceiter_sched_blocked_reason(__data, tsk);
                }
                if (1) {
                    rcu_irq_exit_irqson();
                    srcu_read_unlock_notrace(&tracepoint_srcu, __idx);
                }
                preempt_enable_notrace();
            } while (0);
    }
    #endif
    
    static inline int register_trace_sched_blocked_reason(
        void (*probe)(void *__data, struct task_struct *tsk), void *data)
    {
        return tracepoint_probe_register(&__tracepoint_sched_blocked_reason, (void *)probe, data);
    }
    
    static inline int register_trace_prio_sched_blocked_reason(
        void (*probe)(void *__data, struct task_struct *tsk), void *data, int prio)
    {
        return tracepoint_probe_register_prio(&__tracepoint_sched_blocked_reason, (void *)probe, data, prio);
    }
    
    static inline int unregister_trace_sched_blocked_reason(
        void (*probe)(void *__data, struct task_struct *tsk), void *data)
    {
        return tracepoint_probe_unregister(&__tracepoint_sched_blocked_reason, (void *)probe, data);
    }
    
    static inline void check_trace_callback_type_sched_blocked_reason(
        void (*cb)(void *__data, struct task_struct *tsk)){ }
    
    static inline bool trace_sched_blocked_reason_enabled(void)
    {
        return static_key_false(&__tracepoint_sched_blocked_reason.key);
    }
    
    
    /* tmp.c 的 */
    int main()
    {
        return 0;
    }

    三、TRACE_EVENT 宏在定义了 CREATE_TRACE_POINTS 的情况下展开

    1. 实验 demo_trace.h 文件保持不变

    2. 实验 tmp.c 变为

    /* 拷贝内核中的配置事先定义好 */
    #define CONFIG_MODULES 1
    #define CONFIG_TRACEPOINTS 1
    #define CONFIG_HAVE_SYSCALL_TRACEPOINTS 1
    #define CONFIG_HAVE_ARCH_PREL32_RELOCATIONS 1
    #define CONFIG_TRACING 1
    #define MODULE 1 //编译成ko才定义
    /*
     * 在没有define CREATE_TRACE_POINTS 的情况下,
     * 这三个无论是否define了解析出来是完全一样的。
     */
    #define CONFIG_PERF_EVENTS 1
    #define CONFIG_KPROBE_EVENTS 1
    #define CONFIG_UPROBE_EVENTS 1
    #define CONFIG_BPF_EVENTS 1
    //--------------------------------------------
    
    
    #define CREATE_TRACE_POINTS
    #include "demo_trace.h"
    #undef CREATE_TRACE_POINTS
    
    int main()
    {
        return 0;
    }

    3. gcc -E 解析整理结果

    struct static_call_key;
    
    struct trace_print_flags {
        unsigned long mask;
        const char *name;
    };
    
    struct trace_print_flags_u64 {
        unsigned long long mask;
        const char *name;
    };
    
    struct tracepoint_func {
        void *func;
        void *data;
        int prio;
    };
    
    struct tracepoint {
        const char *name;
        struct static_key key;
        struct static_call_key *static_call_key;
        void *static_call_tramp;
        void *iterator;
        int (*regfunc)(void);
        void (*unregfunc)(void);
        struct tracepoint_func __rcu *funcs;
    };
    
    
    typedef const int tracepoint_ptr_t;
    
    
    
    
    struct bpf_raw_event_map {
        struct tracepoint *tp;
        void *bpf_func;
        u32 num_args;
        u32 writable_size;
    } __aligned(32);
    
    static inline int static_call_init(void) { return 0; }
    
    struct static_call_key {
        void *func;
    };
    
    static inline void __static_call_nop(void) { }
    
    static inline void __static_call_update(struct static_call_key *key, void *tramp, void *func)
    {
        WRITE_ONCE(key->func, func);
    }
    
    static inline int static_call_text_reserved(void *start, void *end)
    {
        return 0;
    }
    
    struct module;
    struct tracepoint;
    struct notifier_block;
    
    struct trace_eval_map {
        const char *system;
        const char *eval_string;
        unsigned long eval_value;
    };
    
    
    
    extern struct srcu_struct tracepoint_srcu;
    
    extern int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);
    extern int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, int prio);
    extern int tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, void *data, int prio);
    extern int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data);
    
    static inline int tracepoint_probe_register_may_exist(struct tracepoint *tp, void *probe, void *data)
    {
        return tracepoint_probe_register_prio_may_exist(tp, probe, data, 10);
    }
    extern void for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), void *priv);
    
    
    struct tp_module {
        struct list_head list;
        struct module *mod;
    };
    
    bool trace_module_has_bad_taint(struct module *mod);
    extern int register_tracepoint_module_notifier(struct notifier_block *nb);
    extern int unregister_tracepoint_module_notifier(struct notifier_block *nb);
    
    static inline void tracepoint_synchronize_unregister(void)
    {
        synchronize_srcu(&tracepoint_srcu);
        synchronize_rcu();
    }
    
    
    
    
    
    
    extern int syscall_regfunc(void);
    extern void syscall_unregfunc(void);
    
    static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
    {
        return offset_to_ptr(p);
    }
    
    
    
    
    
    /* 1. TRACE_EVENT 第一次展开 */
    extern int __traceiter_sched_blocked_reason(void *__data, struct task_struct *tsk);
    DECLARE_STATIC_CALL(tp_func_sched_blocked_reason, __traceiter_sched_blocked_reason);
    extern struct tracepoint __tracepoint_sched_blocked_reason;
    
    static inline void __nocfi trace_sched_blocked_reason(struct task_struct *tsk)
    {
        if (static_key_false(&__tracepoint_sched_blocked_reason.key))
            do {
                struct tracepoint_func *it_func_ptr;
                int __maybe_unused __idx = 0;
                void *__data;
                if (!(cpu_online(raw_smp_processor_id())))
                    return;
                WARN_ON_ONCE(0 && in_nmi());
                preempt_disable_notrace();
                if (0) {
                    __idx = srcu_read_lock_notrace(&tracepoint_srcu);
                    rcu_irq_enter_irqson();
                }
                it_func_ptr = rcu_dereference_raw((&__tracepoint_sched_blocked_reason)->funcs);
                if (it_func_ptr) {
                    __data = (it_func_ptr)->data;
                    __traceiter_sched_blocked_reason(__data, tsk);
                }
                if (0) {
                    rcu_irq_exit_irqson();
                    srcu_read_unlock_notrace(&tracepoint_srcu, __idx);
                } preempt_enable_notrace();
            } while (0);
    
        if (IS_ENABLED(CONFIG_LOCKDEP) && (cpu_online(raw_smp_processor_id()))){
            rcu_read_lock_sched_notrace();
            rcu_dereference_sched(__tracepoint_sched_blocked_reason.funcs);
            rcu_read_unlock_sched_notrace();
        }
    }
    
    static inline int register_trace_sched_blocked_reason(
        void (*probe)(void *__data, struct task_struct *tsk), void *data)
    {
        return tracepoint_probe_register(&__tracepoint_sched_blocked_reason, (void *)probe, data);
    }
    
    static inline int register_trace_prio_sched_blocked_reason(
        void (*probe)(void *__data, struct task_struct *tsk), void *data, int prio)
    {
        return tracepoint_probe_register_prio(&__tracepoint_sched_blocked_reason, (void *)probe, data, prio);
    }
    
    static inline int unregister_trace_sched_blocked_reason(
        void (*probe)(void *__data, struct task_struct *tsk), void *data)
    {
        return tracepoint_probe_unregister(&__tracepoint_sched_blocked_reason, (void *)probe, data);
    }
    
    static inline void check_trace_callback_type_sched_blocked_reason(
        void (*cb)(void *__data, struct task_struct *tsk)) { }
    
    static inline bool trace_sched_blocked_reason_enabled(void)
    {
        return static_key_false(&__tracepoint_sched_blocked_reason.key);
    }
    
    
    
    
    /* 2. TRACE_EVENT 第二次展开 在 define_trace.h 中 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    static const char __tpstrtab_sched_blocked_reason[] __section("__tracepoints_strings") = "sched_blocked_reason";
    extern struct static_call_key STATIC_CALL_KEY(tp_func_sched_blocked_reason);
    int __traceiter_sched_blocked_reason(void *__data, struct task_struct *tsk);
    struct tracepoint __tracepoint_sched_blocked_reason __used __section("__tracepoints") = {
        .name = __tpstrtab_sched_blocked_reason,
        .key = STATIC_KEY_INIT_FALSE,
        .static_call_key = &STATIC_CALL_KEY(tp_func_sched_blocked_reason),
        .static_call_tramp = NULL,
        .iterator = &__traceiter_sched_blocked_reason,
        .regfunc = NULL,
        .unregfunc = NULL,
        .funcs = NULL
    };
    
    asm("    .section \"__tracepoints_ptrs\", \"a\"        \n"    \
        "    .balign 4                    \n"    \
        "    .long     __tracepoint_" sched_blocked_reason " - .        \n"    \
        "    .previous                    \n")
    
    int __nocfi __traceiter_sched_blocked_reason(void *__data, struct task_struct *tsk)
    {
        struct tracepoint_func *it_func_ptr;
        void *it_func;
        it_func_ptr = rcu_dereference_raw((&__tracepoint_sched_blocked_reason)->funcs);
        if (it_func_ptr) {
            do {
                it_func = (it_func_ptr)->func;
                __data = (it_func_ptr)->data;
                ((void(*)(void *, struct task_struct *tsk))(it_func))(__data, tsk);
            } while ((++it_func_ptr)->func);
        } return 0;
    }
    
    DECLARE_STATIC_CALL(tp_func_sched_blocked_reason, __traceiter_sched_blocked_reason);
    struct static_call_key STATIC_CALL_KEY(tp_func_sched_blocked_reason) = {
        .func = __traceiter_sched_blocked_reason,
    };
    
    
    
    
    struct trace_array;
    struct array_buffer;
    struct tracer;
    struct dentry;
    struct bpf_prog;
    
    const char *trace_print_flags_seq(struct trace_seq *p, const char *delim,
            unsigned long flags, const struct trace_print_flags *flag_array);
    
    const char *trace_print_symbols_seq(struct trace_seq *p, unsigned long val,
            const struct trace_print_flags *symbol_array);
    
    const char *trace_print_bitmask_seq(struct trace_seq *p, void *bitmask_ptr,
            unsigned int bitmask_size);
    
    const char *trace_print_hex_seq(struct trace_seq *p,
        const unsigned char *buf, int len, bool concatenate);
    
    const char *trace_print_array_seq(struct trace_seq *p,
           const void *buf, int count, size_t el_size);
    
    const char *trace_print_hex_dump_seq(struct trace_seq *p, const char *prefix_str,
            int prefix_type, int rowsize, int groupsize, const void *buf, size_t len, bool ascii);
    
    struct trace_iterator;
    struct trace_event;
    
    int trace_raw_output_prep(struct trace_iterator *iter, struct trace_event *event);
    
    
    
    
    
    struct trace_entry {
        unsigned short type;
        unsigned char flags;
        unsigned char preempt_count;
        int pid;
    };
    
    struct trace_iterator {
        struct trace_array *tr;
        struct tracer *trace;
        struct array_buffer *array_buffer;
        void *private;
        int cpu_file;
        struct mutex mutex;
        struct ring_buffer_iter **buffer_iter;
        unsigned long iter_flags;
        void *temp;
        unsigned int temp_size;
    
        struct trace_seq tmp_seq;
    
        cpumask_var_t started;
    
        bool snapshot;
    
        struct trace_seq seq;
        struct trace_entry *ent;
        unsigned long lost_events;
        int leftover;
        int ent_size;
        int cpu;
        u64 ts;
    
        loff_t pos;
        long idx;
    };
    
    enum trace_iter_flags {
        TRACE_FILE_LAT_FMT = 1,
        TRACE_FILE_ANNOTATE = 2,
        TRACE_FILE_TIME_IN_NS = 4,
    };
    
    
    typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter,
            int flags, struct trace_event *event);
    
    struct trace_event_functions {
        trace_print_func trace;
        trace_print_func raw;
        trace_print_func hex;
        trace_print_func binary;
    };
    
    struct trace_event {
        struct hlist_node node;
        struct list_head list;
        int type;
        struct trace_event_functions *funcs;
    };
    
    extern int register_trace_event(struct trace_event *event);
    extern int unregister_trace_event(struct trace_event *event);
    
    
    enum print_line_t {
        TRACE_TYPE_PARTIAL_LINE = 0,
        TRACE_TYPE_HANDLED = 1,
        TRACE_TYPE_UNHANDLED = 2,
        TRACE_TYPE_NO_CONSUME = 3
    };
    
    enum print_line_t trace_handle_return(struct trace_seq *s);
    
    void tracing_generic_entry_update(struct trace_entry *entry,
        unsigned short type, unsigned long flags, int pc);
    
    struct trace_event_file;
    
    struct ring_buffer_event *trace_event_buffer_lock_reserve(struct trace_buffer **current_buffer,
            struct trace_event_file *trace_file, int type, unsigned long len, unsigned long flags, int pc);
    
    
    void tracing_record_taskinfo(struct task_struct *task, int flags);
    void tracing_record_taskinfo_sched_switch(struct task_struct *prev, struct task_struct *next, int flags);
    
    void tracing_record_cmdline(struct task_struct *task);
    void tracing_record_tgid(struct task_struct *task);
    
    int trace_output_call(struct trace_iterator *iter, char *name, char *fmt, ...);
    
    struct event_filter;
    
    enum trace_reg {
        TRACE_REG_REGISTER,
        TRACE_REG_UNREGISTER,
        TRACE_REG_PERF_REGISTER,
        TRACE_REG_PERF_UNREGISTER,
        TRACE_REG_PERF_OPEN,
        TRACE_REG_PERF_CLOSE,
        TRACE_REG_PERF_ADD,
        TRACE_REG_PERF_DEL,
    };
    
    struct trace_event_call;
    
    
    
    struct trace_event_fields {
        const char *type;
        union {
            struct {
                const char *name;
                const int size;
                const int align;
                const int is_signed;
                const int filter_type;
            };
            int (*define_fields)(struct trace_event_call *);
        };
    };
    
    struct trace_event_class {
        const char *system;
        void *probe;
    
        void *perf_probe;
    
        int (*reg)(struct trace_event_call *event, enum trace_reg type, void *data);
        struct trace_event_fields *fields_array;
        struct list_head *(*get_fields)(struct trace_event_call *);
        struct list_head fields;
        int (*raw_init)(struct trace_event_call *);
    };
    
    extern int trace_event_reg(struct trace_event_call *event, enum trace_reg type, void *data);
    
    struct trace_event_buffer {
        struct trace_buffer *buffer;
        struct ring_buffer_event *event;
        struct trace_event_file *trace_file;
        void *entry;
        unsigned long flags;
        int pc;
        struct pt_regs *regs;
    };
    
    void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer,
          struct trace_event_file *trace_file, unsigned long len);
    
    void trace_event_buffer_commit(struct trace_event_buffer *fbuffer);
    
    enum {
        TRACE_EVENT_FL_FILTERED_BIT,
        TRACE_EVENT_FL_CAP_ANY_BIT,
        TRACE_EVENT_FL_NO_SET_FILTER_BIT,
        TRACE_EVENT_FL_IGNORE_ENABLE_BIT,
        TRACE_EVENT_FL_TRACEPOINT_BIT,
        TRACE_EVENT_FL_KPROBE_BIT,
        TRACE_EVENT_FL_UPROBE_BIT,
    };
    
    enum {
        TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT),
        TRACE_EVENT_FL_CAP_ANY = (1 << TRACE_EVENT_FL_CAP_ANY_BIT),
        TRACE_EVENT_FL_NO_SET_FILTER = (1 << TRACE_EVENT_FL_NO_SET_FILTER_BIT),
        TRACE_EVENT_FL_IGNORE_ENABLE = (1 << TRACE_EVENT_FL_IGNORE_ENABLE_BIT),
        TRACE_EVENT_FL_TRACEPOINT = (1 << TRACE_EVENT_FL_TRACEPOINT_BIT),
        TRACE_EVENT_FL_KPROBE = (1 << TRACE_EVENT_FL_KPROBE_BIT),
        TRACE_EVENT_FL_UPROBE = (1 << TRACE_EVENT_FL_UPROBE_BIT),
    };
    
    
    
    struct trace_event_call {
        struct list_head list;
        struct trace_event_class *class;
        union {
            char *name;
            struct tracepoint *tp;
        };
        struct trace_event event;
        char *print_fmt;
        struct event_filter *filter;
        void *mod;
        void *data;
    
        int flags;
    
        int perf_refcount;
        struct hlist_head __percpu *perf_events;
        struct bpf_prog_array __rcu *prog_array;
    
        int (*perf_perm)(struct trace_event_call *, struct perf_event *);
    };
    
    
    static inline bool bpf_prog_array_valid(struct trace_event_call *call)
    {
        return !!READ_ONCE(call->prog_array);
    }
    
    
    static inline const char *trace_event_name(struct trace_event_call *call)
    {
        if (call->flags & TRACE_EVENT_FL_TRACEPOINT)
            return call->tp ? call->tp->name : NULL;
        else
            return call->name;
    }
    
    static inline struct list_head *trace_get_fields(struct trace_event_call *event_call)
    {
        if (!event_call->class->get_fields)
            return &event_call->class->fields;
        return event_call->class->get_fields(event_call);
    }
    
    struct trace_array;
    struct trace_subsystem_dir;
    
    enum {
        EVENT_FILE_FL_ENABLED_BIT,
        EVENT_FILE_FL_RECORDED_CMD_BIT,
        EVENT_FILE_FL_RECORDED_TGID_BIT,
        EVENT_FILE_FL_FILTERED_BIT,
        EVENT_FILE_FL_NO_SET_FILTER_BIT,
        EVENT_FILE_FL_SOFT_MODE_BIT,
        EVENT_FILE_FL_SOFT_DISABLED_BIT,
        EVENT_FILE_FL_TRIGGER_MODE_BIT,
        EVENT_FILE_FL_TRIGGER_COND_BIT,
        EVENT_FILE_FL_PID_FILTER_BIT,
        EVENT_FILE_FL_WAS_ENABLED_BIT,
    };
    
    extern struct trace_event_file *trace_get_event_file(const char *instance,
               const char *system, const char *event);
    extern void trace_put_event_file(struct trace_event_file *file);
    
    
    
    enum dynevent_type {
        DYNEVENT_TYPE_SYNTH = 1,
        DYNEVENT_TYPE_KPROBE,
        DYNEVENT_TYPE_NONE,
    };
    
    struct dynevent_cmd;
    
    typedef int (*dynevent_create_fn_t)(struct dynevent_cmd *cmd);
    
    struct dynevent_cmd {
        struct seq_buf seq;
        const char *event_name;
        unsigned int n_fields;
        enum dynevent_type type;
        dynevent_create_fn_t run_command;
        void *private_data;
    };
    
    extern int dynevent_create(struct dynevent_cmd *cmd);
    
    extern int synth_event_delete(const char *name);
    
    extern void synth_event_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen);
    
    extern int __synth_event_gen_cmd_start(struct dynevent_cmd *cmd,
            const char *name, struct module *mod, ...);
    
    
    
    
    struct synth_field_desc {
        const char *type;
        const char *name;
    };
    
    extern int synth_event_gen_cmd_array_start(struct dynevent_cmd *cmd,
            const char *name, struct module *mod, struct synth_field_desc *fields, unsigned int n_fields);
    extern int synth_event_create(const char *name,
            struct synth_field_desc *fields, unsigned int n_fields, struct module *mod);
    
    extern int synth_event_add_field(struct dynevent_cmd *cmd,
            const char *type, const char *name);
    extern int synth_event_add_field_str(struct dynevent_cmd *cmd,
            const char *type_name);
    extern int synth_event_add_fields(struct dynevent_cmd *cmd,
            struct synth_field_desc *fields, unsigned int n_fields);
    
    
    
    
    struct synth_event;
    
    struct synth_event_trace_state {
        struct trace_event_buffer fbuffer;
        struct synth_trace_event *entry;
        struct trace_buffer *buffer;
        struct synth_event *event;
        unsigned int cur_field;
        unsigned int n_u64;
        bool disabled;
        bool add_next;
        bool add_name;
    };
    
    extern int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...);
    extern int synth_event_trace_array(struct trace_event_file *file, u64 *vals, unsigned int n_vals);
    extern int synth_event_trace_start(struct trace_event_file *file, struct synth_event_trace_state *trace_state);
    extern int synth_event_add_next_val(u64 val, struct synth_event_trace_state *trace_state);
    extern int synth_event_add_val(const char *field_name, u64 val, struct synth_event_trace_state *trace_state);
    extern int synth_event_trace_end(struct synth_event_trace_state *trace_state);
    
    extern int kprobe_event_delete(const char *name);
    
    extern void kprobe_event_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen);
    
    
    extern int __kprobe_event_gen_cmd_start(struct dynevent_cmd *cmd,
         bool kretprobe, const char *name, const char *loc, ...);
    
    
    extern int __kprobe_event_add_fields(struct dynevent_cmd *cmd, ...);
    
    enum {
        EVENT_FILE_FL_ENABLED = (1 << EVENT_FILE_FL_ENABLED_BIT),
        EVENT_FILE_FL_RECORDED_CMD = (1 << EVENT_FILE_FL_RECORDED_CMD_BIT),
        EVENT_FILE_FL_RECORDED_TGID = (1 << EVENT_FILE_FL_RECORDED_TGID_BIT),
        EVENT_FILE_FL_FILTERED = (1 << EVENT_FILE_FL_FILTERED_BIT),
        EVENT_FILE_FL_NO_SET_FILTER = (1 << EVENT_FILE_FL_NO_SET_FILTER_BIT),
        EVENT_FILE_FL_SOFT_MODE = (1 << EVENT_FILE_FL_SOFT_MODE_BIT),
        EVENT_FILE_FL_SOFT_DISABLED = (1 << EVENT_FILE_FL_SOFT_DISABLED_BIT),
        EVENT_FILE_FL_TRIGGER_MODE = (1 << EVENT_FILE_FL_TRIGGER_MODE_BIT),
        EVENT_FILE_FL_TRIGGER_COND = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT),
        EVENT_FILE_FL_PID_FILTER = (1 << EVENT_FILE_FL_PID_FILTER_BIT),
        EVENT_FILE_FL_WAS_ENABLED = (1 << EVENT_FILE_FL_WAS_ENABLED_BIT),
    };
    
    struct trace_event_file {
        struct list_head list;
        struct trace_event_call *event_call;
        struct event_filter __rcu *filter;
        struct dentry *dir;
        struct trace_array *tr;
        struct trace_subsystem_dir *system;
        struct list_head triggers;
    
        unsigned long flags;
        atomic_t sm_ref;
        atomic_t tm_ref;
    };
    
    enum event_trigger_type {
        ETT_NONE = (0),
        ETT_TRACE_ONOFF = (1 << 0),
        ETT_SNAPSHOT = (1 << 1),
        ETT_STACKTRACE = (1 << 2),
        ETT_EVENT_ENABLE = (1 << 3),
        ETT_EVENT_HIST = (1 << 4),
        ETT_HIST_ENABLE = (1 << 5),
    };
    
    extern int filter_match_preds(struct event_filter *filter, void *rec);
    
    extern enum event_trigger_type event_triggers_call(struct trace_event_file *file, void *rec,
            struct ring_buffer_event *event);
    extern void event_triggers_post_call(struct trace_event_file *file, enum event_trigger_type tt);
    
    bool trace_event_ignore_this_pid(struct trace_event_file *trace_file);
    
    static inline bool trace_trigger_soft_disabled(struct trace_event_file *file)
    {
        unsigned long eflags = file->flags;
    
        if (!(eflags & EVENT_FILE_FL_TRIGGER_COND)) {
            if (eflags & EVENT_FILE_FL_TRIGGER_MODE)
                event_triggers_call(file, NULL, NULL);
            if (eflags & EVENT_FILE_FL_SOFT_DISABLED)
                return true;
            if (eflags & EVENT_FILE_FL_PID_FILTER)
                return trace_event_ignore_this_pid(file);
        }
        return false;
    }
    
    static inline unsigned int trace_call_bpf(struct trace_event_call *call, void *ctx)
    {
     return 1;
    }
    
    static inline int perf_event_attach_bpf_prog(struct perf_event *event, struct bpf_prog *prog)
    {
     return -EOPNOTSUPP;
    }
    
    static inline void perf_event_detach_bpf_prog(struct perf_event *event) { }
    
    static inline int perf_event_query_prog_array(struct perf_event *event, void __user *info)
    {
     return -EOPNOTSUPP;
    }
    static inline int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *p)
    {
     return -EOPNOTSUPP;
    }
    static inline int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *p)
    {
     return -EOPNOTSUPP;
    }
    static inline struct bpf_raw_event_map *bpf_get_raw_tracepoint(const char *name)
    {
     return NULL;
    }
    static inline void bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp)
    {
    }
    static inline int bpf_get_perf_event_info(const struct perf_event *event,
            u32 *prog_id, u32 *fd_type, const char **buf, u64 *probe_offset, u64 *probe_addr)
    {
     return -EOPNOTSUPP;
    }
    
    
    enum {
        FILTER_OTHER = 0,
        FILTER_STATIC_STRING,
        FILTER_DYN_STRING,
        FILTER_PTR_STRING,
        FILTER_TRACE_FN,
        FILTER_COMM,
        FILTER_CPU,
    };
    
    extern int trace_event_raw_init(struct trace_event_call *call);
    extern int trace_define_field(struct trace_event_call *call, const char *type,
            const char *name, int offset, int size, int is_signed, int filter_type);
    extern int trace_add_event_call(struct trace_event_call *call);
    extern int trace_remove_event_call(struct trace_event_call *call);
    extern int trace_event_get_offsets(struct trace_event_call *call);
    
    
    
    int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set);
    int trace_set_clr_event(const char *system, const char *event, int set);
    int trace_array_set_clr_event(struct trace_array *tr, const char *system, const char *event, bool enable);
    
    struct perf_event;
    
    DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);
    DECLARE_PER_CPU(int, bpf_kprobe_override);
    
    extern int perf_trace_init(struct perf_event *event);
    extern void perf_trace_destroy(struct perf_event *event);
    extern int perf_trace_add(struct perf_event *event, int flags);
    extern void perf_trace_del(struct perf_event *event, int flags);
    
    extern int perf_kprobe_init(struct perf_event *event, bool is_retprobe);
    extern void perf_kprobe_destroy(struct perf_event *event);
    extern int bpf_get_kprobe_info(const struct perf_event *event,
        u32 *fd_type, const char **symbol, u64 *probe_offset, u64 *probe_addr, bool perf_type_tracepoint);
    
    
    extern int perf_uprobe_init(struct perf_event *event, unsigned long ref_ctr_offset, bool is_retprobe);
    extern void perf_uprobe_destroy(struct perf_event *event);
    extern int bpf_get_uprobe_info(const struct perf_event *event,
        u32 *fd_type, const char **filename, u64 *probe_offset, bool perf_type_tracepoint);
    
    extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, char *filter_str);
    extern void ftrace_profile_free_filter(struct perf_event *event);
    void perf_trace_buf_update(void *record, u16 type);
    void *perf_trace_buf_alloc(int size, struct pt_regs **regs, int *rctxp);
    
    void bpf_trace_run1(struct bpf_prog *prog, u64 arg1);
    void bpf_trace_run2(struct bpf_prog *prog, u64 arg1, u64 arg2);
    void bpf_trace_run3(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3);
    void bpf_trace_run4(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4);
    void bpf_trace_run5(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5);
    void bpf_trace_run6(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5,
            u64 arg6);
    void bpf_trace_run7(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5,
            u64 arg6, u64 arg7);
    void bpf_trace_run8(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5,
            u64 arg6, u64 arg7, u64 arg8);
    void bpf_trace_run9(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5,
            u64 arg6, u64 arg7, u64 arg8, u64 arg9);
    void bpf_trace_run10(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5,
            u64 arg6, u64 arg7, u64 arg8, u64 arg9, u64 arg10);
    void bpf_trace_run11(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5,
            u64 arg6, u64 arg7, u64 arg8, u64 arg9, u64 arg10, u64 arg11);
    void bpf_trace_run12(struct bpf_prog *prog, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5,
            u64 arg6, u64 arg7, u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12);
    
    void perf_trace_run_bpf_submit(void *raw_data, int size, int rctx,
            struct trace_event_call *call, u64 count, struct pt_regs *regs, struct hlist_head *head,
            struct task_struct *task);
    
    static inline void perf_trace_buf_submit(void *raw_data, int size, int rctx, u16 type,
            u64 count, struct pt_regs *regs, void *head, struct task_struct *task)
    {
        perf_tp_event(type, count, raw_data, size, regs, head, rctx, task);
    }
    
    static const char str__demo_sfl__trace_system_name[] = "demo_sfl";
    
    
    
    /* 3. TRACE_EVENT 第三次展开,对应在 trace/trace_events.h 中第1次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    struct trace_event_raw_sched_blocked_reason {
        struct trace_entry ent;
        pid_t pid;
        void* caller;
        bool io_wait;
        char __data[0];
    };
    
    static struct trace_event_class event_class_sched_blocked_reason;
    static struct trace_event_call __used __attribute__((__aligned__(4))) event_sched_blocked_reason;
    
    
    
    /* 4. TRACE_EVENT 第四次展开,对应在 trace/trace_events.h 中第2次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    //比较诧异,的确是空!因为前面__field定义为空。
    struct trace_event_data_offsets_sched_blocked_reason { };
    
    
    
    
    
    /* 5. TRACE_EVENT 第五次展开,对应在 trace/trace_events.h 中第3次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    static notrace enum print_line_t trace_raw_output_sched_blocked_reason(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_sched_blocked_reason *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, "pid=%d iowait=%d caller=%pS" "\n", field->pid, field->io_wait, field->caller);
        return trace_handle_return(s);
    }
    
    static struct trace_event_functions trace_event_type_funcs_sched_blocked_reason = {
        .trace = trace_raw_output_sched_blocked_reason,
    };
    
    
    
    
    /* 6. TRACE_EVENT 第六次展开,对应在 trace/trace_events.h 中第4次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    static struct trace_event_fields trace_event_fields_sched_blocked_reason[] = {
        {
            .type = "pid_t",
            .name = "pid",
            .size = sizeof(pid_t),
            .align = __alignof__(pid_t),
            .is_signed = (((pid_t)(-1)) < (pid_t)1),
            .filter_type = FILTER_OTHER
        },
        {
            .type = "void*",
            .name = "caller",
            .size = sizeof(void*),
            .align = __alignof__(void*),
            .is_signed = (((void*)(-1)) < (void*)1),
            .filter_type = FILTER_OTHER
        },
        {
            .type = "bool",
            .name = "io_wait",
            .size = sizeof(bool),
            .align = __alignof__(bool),
            .is_signed = (((bool)(-1)) < (bool)1),
            .filter_type = FILTER_OTHER
        },
        {}
    };
    
    
    
    
    /* 7. TRACE_EVENT 第七次展开,对应在 trace/trace_events.h 中第5次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    static inline notrace int trace_event_get_offsets_sched_blocked_reason(
        struct trace_event_data_offsets_sched_blocked_reason *__data_offsets, struct task_struct *tsk)
    {
        int __data_size = 0;
        int __maybe_unused __item_length;
        struct trace_event_raw_sched_blocked_reason __maybe_unused *entry;
        return __data_size; //直接返回的是0,函数啥也没做!
    };
    
    
    
    
    
    /* 8. TRACE_EVENT 第八次展开,对应在 trace/trace_events.h 中第6次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    static notrace void trace_event_raw_event_sched_blocked_reason(void *__data, struct task_struct *tsk)
    {
        struct trace_event_file *trace_file = __data;
        struct trace_event_data_offsets_sched_blocked_reason __maybe_unused __data_offsets;
        struct trace_event_buffer fbuffer;
        struct trace_event_raw_sched_blocked_reason *entry;
        int __data_size;
        if (trace_trigger_soft_disabled(trace_file))
            return;
        __data_size = trace_event_get_offsets_sched_blocked_reason(&__data_offsets, tsk);
        entry = trace_event_buffer_reserve(&fbuffer, trace_file, sizeof(*entry) + __data_size);
        if (!entry)
            return;
        {
            entry->pid = tsk->pid;
            entry->caller = (void *)get_wchan(tsk);
            entry->io_wait = tsk->in_iowait;
        }
        trace_event_buffer_commit(&fbuffer);
    };
    
    static inline void ftrace_test_probe_sched_blocked_reason(void)
    {
        check_trace_callback_type_sched_blocked_reason(trace_event_raw_event_sched_blocked_reason);
    };
    
    
    
    
    
    /* 9. TRACE_EVENT 第九次展开,对应在 trace/trace_events.h 中第7次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    static notrace void perf_trace_sched_blocked_reason(void *__data, struct task_struct *tsk);
    
    static char print_fmt_sched_blocked_reason[] = "\" pid=%d iowait=%d caller=%pS \", " 
        "REC->pid, REC->io_wait, REC->caller";
    
    static struct trace_event_class __used __refdata event_class_sched_blocked_reason = {
        .system = str__demo_sfl__trace_system_name,
        .fields_array = trace_event_fields_sched_blocked_reason,
        .fields = LIST_HEAD_INIT(event_class_sched_blocked_reason.fields),
        .raw_init = trace_event_raw_init,
        .probe = trace_event_raw_event_sched_blocked_reason,
        .reg = trace_event_reg,
        .perf_probe = perf_trace_sched_blocked_reason,
    };
    
    static struct trace_event_call __used event_sched_blocked_reason = {
        .class = &event_class_sched_blocked_reason,
        {
            .tp = &__tracepoint_sched_blocked_reason,
        },
        .event.funcs = &trace_event_type_funcs_sched_blocked_reason,
        .print_fmt = print_fmt_sched_blocked_reason,
        .flags = TRACE_EVENT_FL_TRACEPOINT,
    };
    
    static struct trace_event_call __used __section("_ftrace_events") *__event_sched_blocked_reason
        = &event_sched_blocked_reason;
    
    
    
    
    /* 10. TRACE_EVENT 第十次展开,对应在 trace/perf.h 中第1次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    static notrace void perf_trace_sched_blocked_reason(void *__data, struct task_struct *tsk)
    {
        struct trace_event_call *event_call = __data;
        struct trace_event_data_offsets_sched_blocked_reason __maybe_unused __data_offsets;
        struct trace_event_raw_sched_blocked_reason *entry;
        struct pt_regs *__regs;
        u64 __count = 1;
        struct task_struct *__task = NULL;
        struct hlist_head *head;
        int __entry_size;
        int __data_size;
        int rctx;
        __data_size = trace_event_get_offsets_sched_blocked_reason(&__data_offsets, tsk);
        head = this_cpu_ptr(event_call->perf_events);
        if (!bpf_prog_array_valid(event_call) && __builtin_constant_p(!__task) && !__task && hlist_empty(head))
            return;
        __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32), sizeof(u64));
        __entry_size -= sizeof(u32);
        entry = perf_trace_buf_alloc(__entry_size, &__regs, &rctx);
        if (!entry)
            return;
        perf_fetch_caller_regs(__regs);
        {
            entry->pid = tsk->pid;
            entry->caller = (void *)get_wchan(tsk);
            entry->io_wait = tsk->in_iowait;
        }
        perf_trace_run_bpf_submit(entry, __entry_size, rctx, event_call, __count, __regs, head, __task);
    }
    
    static inline void perf_test_probe_sched_blocked_reason(void)
    {
        check_trace_callback_type_sched_blocked_reason(perf_trace_sched_blocked_reason);
    }
    
    
    
    
    
    /* 11. TRACE_EVENT 第十一次展开,对应在 trace/bpf_probe.h 中第1次 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) */
    static notrace void __bpf_trace_sched_blocked_reason(void *__data, struct task_struct *tsk)
    {
        struct bpf_prog *prog = __data;
        CONCATENATE(bpf_trace_run, COUNT_ARGS(tsk))(prog, CONCATENATE(__CAST, COUNT_ARGS(tsk))(tsk));
    };
    
    static inline void bpf_test_probe_sched_blocked_reason(void)
    {
        check_trace_callback_type_sched_blocked_reason(__bpf_trace_sched_blocked_reason);
    }
    
    typedef void (*btf_trace_sched_blocked_reason)(void *__data, struct task_struct *tsk);
    
    static union {
        struct bpf_raw_event_map event;
        btf_trace_sched_blocked_reason handler;
    } __bpf_trace_tp_map_sched_blocked_reason __used __section("__bpf_raw_tp_map") = {
        .event = {
            .tp = &__tracepoint_sched_blocked_reason,
            .bpf_func = __bpf_trace_sched_blocked_reason,
            .num_args = COUNT_ARGS(tsk),
            .writable_size = 0,
        },
    };
    
    
    
    /* tmp.c 文件的 */
    int main()
    {
     return 0;
    }

    注:第二次展开中的asm汇编是 __TRACEPOINT_ENTRY(name) 的展开,等效于:

    static tracepoint_ptr_t __tracepoint_ptr_sched_blocked_reason __used __section("__tracepoints_ptrs") = 
    &__tracepoint_sched_blocked_reason

     四、总结

    1. 在 trace/trace_events.h 中,TRACE_EVENT 主要是通过 DECLARE_EVENT_CLASS 进行解析的。因此还有一种trace point 的定义方法,如sched.h中的:

    DECLARE_EVENT_CLASS(sched_wakeup_template,
    
        TP_PROTO(struct task_struct *p),
    
        TP_ARGS(__perf_task(p)),
    
        TP_STRUCT__entry(
            __array(    char,    comm,    TASK_COMM_LEN    )
            __field(    pid_t,    pid            )
            __field(    int,    prio            )
            __field(    int,    success            )
            __field(    int,    target_cpu        )
        ),
    
        TP_fast_assign(
            memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
            __entry->pid        = p->pid;
            __entry->prio        = p->prio; /* XXX SCHED_DEADLINE */
            __entry->success    = 1; /* rudiment, kill when possible */
            __entry->target_cpu    = task_cpu(p);
        ),
    
        TP_printk("comm=%s pid=%d prio=%d target_cpu=%03d",
              __entry->comm, __entry->pid, __entry->prio,
              __entry->target_cpu)
    );
    
    DEFINE_EVENT(sched_wakeup_template, sched_waking,
             TP_PROTO(struct task_struct *p),
             TP_ARGS(p));
    
    DEFINE_EVENT(sched_wakeup_template, sched_wakeup,
             TP_PROTO(struct task_struct *p),
             TP_ARGS(p));

    五、补充

    1. pelt中只使用 DECLARE_TRACE 定义的,只有前2种展开,后面 trace/trace_events.h 中的一次展开也没有。看起来只是定义了一个trace_point结构而已。

    DECLARE_TRACE(pelt_se_tp,
        TP_PROTO(struct sched_entity *se),
        TP_ARGS(se));

    参考:

    深入理解Linux ftrace 之 trace event: https://mp.weixin.qq.com/s/1A02qv5SIEgTEvsN1DWzqQ

  • 相关阅读:
    A1039 Course List for Student (25 分)
    A1101 Quick Sort (25 分)
    日常笔记6C++标准模板库(STL)用法介绍实例
    A1093 Count PAT's (25 分)
    A1029 Median (25 分)
    A1089 Insert or Merge (25 分)
    A1044 Shopping in Mars (25 分)
    js 验证
    根据string获取对应类型的对应属性
    HTML 只能输入数字
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/16774074.html
Copyright © 2020-2023  润新知