基于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