2024年运维最新Linux 调试之 TRACE_EVENT(一)(1),直击优秀开源框架灵魂

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

	  \_\_print\_flags(__entry->prev_state & (TASK_STATE_MAX-1), "|",
			{ 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" },
			{ 16, "Z" }, { 32, "X" }, { 64, "x" },
			{ 128, "K" }, { 256, "W" }, { 512, "P" }) : "R",
	__entry->prev_state & TASK_STATE_MAX ? "+" : "",
	__entry->next_comm, __entry->next_pid, __entry->next_prio)

);


除第一个参数外的所有参数都用另一个宏(TP\_PROTO、TP\_ARGS、TP\_STRUCT\_\_entry、TP\_fast\_assign和TP\_printk)封装。这些宏提供了更多的处理控制,并且允许在TRACE\_EVENT()宏中使用逗号。


#### 2.2.1 Name


Name:第一个参数是名称。



TRACE_EVENT(sched_switch,


这是用于调用此跟踪点的名称。实际使用的跟踪点在名称前加上trace\_前缀(即trace\_sched\_switch),比如:



#define CREATE_TRACE_POINTS
#include <trace/events/sched.h>

/**
* prepare_task_switch - prepare to switch tasks
* @rq: the runqueue preparing to switch
* @prev: the current task that is being switched out
* @next: the task we are going to switch to.
*
* This is called with the rq lock held and interrupts off. It must
* be paired with a subsequent finish_task_switch after the context
* switch.
*
* prepare_task_switch sets up locking and calls architecture specific
* hooks.
*/
static inline void
prepare_task_switch(struct rq *rq, struct task_struct *prev,
struct task_struct *next)
{
//使用 tracepoint:sched_switch
trace_sched_switch(prev, next);
sched_info_switch(prev, next);
perf_event_task_sched_out(prev, next);
fire_sched_out_preempt_notifiers(prev, next);
prepare_lock_switch(rq, next);
prepare_arch_switch(next);
}


#### 2.2.2 Prototype


Prototype:第二个参数是函数原型。



TP\_PROTO(struct task\_struct \*prev,
	 struct task\_struct \*next),

编写原型时,就像直接声明跟踪点一样:



trace_sched_switch(struct task_struct *prev, struct task_struct *next),


它被用作添加到内核代码中的跟踪点和回调函数的原型。请记住,跟踪点调用回调函数,就像在跟踪点的位置调用回调函数一样。


#### 2.2.3 Arguments


Arguments:第三个参数是函数原型使用的参数。



TP_ARGS(prev, next),


它不仅是TRACE\_EVENT()宏所需要的,它也是下面的跟踪点基础结构所需要的。跟踪点代码在激活时将调用回调函数(可以为给定的跟踪点分配多个回调)。  
 创建跟踪点的宏必须同时访问原型和参数。以下是跟踪点宏完成此操作所需的说明:



struct tracepoint_func {
void *func;
void *data;
};

struct tracepoint {
const char *name; /* Tracepoint name */
struct static_key key;
void (*regfunc)(void);
void (*unregfunc)(void);
struct tracepoint_func __rcu *funcs;
};

extern struct tracepoint tracepoint##name;
static inline void trace
##name(proto)
{
if (static_key_false(&_tracepoint##name.key))
__DO_TRACE(&_tracepoint##name,
TP_PROTO(data_proto),
TP_ARGS(data_args),
TP_CONDITION(cond),);
}


#### 2.2.4 Structure


Structure:此参数描述将存储在跟踪器环形缓冲区中的数据的结构布局。



TP_STRUCT__entry(
__array( char, prev_comm, TASK_COMM_LEN )
__field( pid_t, prev_pid )
__field( int, prev_prio )
__field( long, prev_state )
__array( char, next_comm, TASK_COMM_LEN )
__field( pid_t, next_pid )
__field( int, next_prio )
),


此参数描述将存储在跟踪器环形缓冲区中的数据的结构布局。结构的每个元素都由另一个宏定义。这些宏用于自动创建结构,与功能不同。请注意,宏之间没有任何分隔符(没有逗号或分号)。  
 sched\_switch跟踪点使用的宏包括:  
 \_\_array(type,name,len)-这定义了一个数组项,相当于int name[len];其中类型为int,数组的名称为array,数组中的项数为len。  
 \_\_field(type,name):这定义了一个普通的结构元素,比如in tvar;其中类型为int,名称为var。  
 还有其他元素宏将在后面的文章中描述。sched\_switch跟踪点的定义将生成如下结构:



struct {
char prev_comm[TASK_COMM_LEN];
pid_t prev_pid;
int prev_prio;
long prev_state;
char next_comm[TASK_COMM_LEN];
pid_t next_pid;
int next_prio;
};


#### 2.2.5 Assignment


Assignment:第五个参数定义了将参数中的数据保存到环形缓冲区的方式。



TP_fast_assign(
memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN);
__entry->prev_pid = prev->pid;
__entry->prev_prio = prev->prio;
__entry->prev_state = __trace_sched_switch_state(prev);
memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN);
__entry->next_pid = next->pid;
__entry->next_prio = next->prio;
),


TP\_fast\_assign()中的代码是正常的C代码。特殊变量\_\_entry表示指向由TP\_STRUCT\_\_entry定义的结构类型的指针,并直接指向环形缓冲区。TP\_fast\_assign用于填充TP\_STRUCT\_\_entry中创建的所有字段。然后可以使用TP\_PROTO和TP\_ARGS定义的参数的变量名将适当的数据分配到\_\_entry结构中。


#### 2.2.6 Print


Print:最后一个参数定义如何使用printk()打印TP\_STRUCT\_\_entry结构中的字段。



TP_printk(“prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s%s ==> next_comm=%s next_pid=%d next_prio=%d”,
__entry->prev_comm, __entry->prev_pid, __entry->prev_prio,
__entry->prev_state & (TASK_STATE_MAX-1) ?
__print_flags(__entry->prev_state & (TASK_STATE_MAX-1), “|”,
{ 1, “S”} , { 2, “D” }, { 4, “T” }, { 8, “t” },
{ 16, “Z” }, { 32, “X” }, { 64, “x” },
{ 128, “K” }, { 256, “W” }, { 512, “P” }) : “R”,
__entry->prev_state & TASK_STATE_MAX ? “+” : “”,
__entry->next_comm, __entry->next_pid, __entry->next_prio)


变量\_\_entry再次用于引用指向包含数据的结构的指针。格式字符串与任何其他printf格式一样。\_\_print\_flags()是TRACE\_EVENT()附带的一组帮助函数的一部分。


### 2.3 Format file


Format file:sched\_switch TRACE\_EVENT()宏以/sys/kernel/debug/tracking/events/sched/sched\_switch/format格式生成以下格式文件:



[root@localhost ~]# cat /sys/kernel/debug/tracing/events/sched/sched_switch/format
name: sched_switch
ID: 326
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;

    field:char prev_comm[16];       offset:8;       size:16;        signed:1;
    field:pid\_t prev_pid;   offset:24;      size:4; signed:1;
    field:int prev_prio;    offset:28;      size:4; signed:1;
    field:long prev_state;  offset:32;      size:8; signed:1;
    field:char next_comm[16];       offset:40;      size:16;        signed:1;
    field:pid\_t next_pid;   offset:56;      size:4; signed:1;
    field:int next_prio;    offset:60;      size:4; signed:1;

print fmt: “prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s%s ==> next_comm=%s next_pid=%d next_prio=%d”, REC->prev_comm, REC->prev_pid, REC->prev_prio, REC->prev_state & (1024-1) ? __print_flags(REC->prev_state & (1024-1), “|”, { 1, “S”} , { 2, “D” }, { 4, “T” }, { 8, “t” }, { 16, “Z” }, { 32, “X” }, { 64, “x” }, { 128, “K” }, { 256, “W” }, { 512, “P” }) : “R”, REC->prev_state & 1024 ? “+” : “”, REC->next_comm, REC->next_pid, REC->next_prio


请注意,格式文件中的\_\_entry替换为REC。第一组字段(common\_\*)不是来自TRACE\_EVENT()宏,而是由创建此格式文件的Ftrace添加到所有事件中,其他跟踪程序可以添加不同的字段。格式文件为用户空间工具提供解析包含sched\_switch项的二进制输出所需的信息。


#### 2.3.1 tracing/events/


与进程调度有关的其他 tracepoints 点:



[root@localhost ~]# cat /sys/kernel/debug/tracing/events/sched/
enable sched_move_numa/ sched_process_free/ sched_stat_runtime/ sched_switch/
filter sched_pi_setprio/ sched_process_hang/ sched_stat_sleep/ sched_wait_task/
sched_kthread_stop/ sched_process_exec/ sched_process_wait/ sched_stat_wait/ sched_wake_idle_without_ipi/
sched_kthread_stop_ret/ sched_process_exit/ sched_stat_blocked/ sched_stick_numa/ sched_wakeup/
sched_migrate_task/ sched_process_fork/ sched_stat_iowait/ sched_swap_numa/ sched_wakeup_new/


#### 2.3.2 perf


除了通过 debugfs 的 /tracing/events/ 查看 tracepoint点还可以通过 perf list 查看:



[root@localhost ~]# perf list tracepoint | grep sched:
sched:sched_kthread_stop [Tracepoint event]
sched:sched_kthread_stop_ret [Tracepoint event]
sched:sched_migrate_task [Tracepoint event]
sched:sched_move_numa [Tracepoint event]
sched:sched_pi_setprio [Tracepoint event]
sched:sched_process_exec [Tracepoint event]
sched:sched_process_exit [Tracepoint event]
sched:sched_process_fork [Tracepoint event]
sched:sched_process_free [Tracepoint event]
sched:sched_process_hang [Tracepoint event]
sched:sched_process_wait [Tracepoint event]
sched:sched_stat_blocked [Tracepoint event]
sched:sched_stat_iowait [Tracepoint event]
sched:sched_stat_runtime [Tracepoint event]
sched:sched_stat_sleep [Tracepoint event]
sched:sched_stat_wait [Tracepoint event]
sched:sched_stick_numa [Tracepoint event]
sched:sched_swap_numa [Tracepoint event]
sched:sched_switch [Tracepoint event]
sched:sched_wait_task [Tracepoint event]
sched:sched_wake_idle_without_ipi [Tracepoint event]
sched:sched_wakeup [Tracepoint event]
sched:sched_wakeup_new [Tracepoint event]


#### 2.3.3 bpftrace


对于支持 ebpf 的高版本Linux内核版本,可以用bpftrace查看:



yl@yl-virtual-machine:~/Desktop$ uname -r
5.19.0-23-generic
yl@yl-virtual-machine:~/Desktop$ sudo bpftrace -l tracepoint:sched:*
tracepoint:sched:sched_kthread_stop
tracepoint:sched:sched_kthread_stop_ret
tracepoint:sched:sched_kthread_work_execute_end
tracepoint:sched:sched_kthread_work_execute_start
tracepoint:sched:sched_kthread_work_queue_work
tracepoint:sched:sched_migrate_task
tracepoint:sched:sched_move_numa
tracepoint:sched:sched_pi_setprio
tracepoint:sched:sched_process_exec
tracepoint:sched:sched_process_exit
tracepoint:sched:sched_process_fork
tracepoint:sched:sched_process_free
tracepoint:sched:sched_process_hang
tracepoint:sched:sched_process_wait
tracepoint:sched:sched_stat_blocked
tracepoint:sched:sched_stat_iowait
tracepoint:sched:sched_stat_runtime
tracepoint:sched:sched_stat_sleep
tracepoint:sched:sched_stat_wait
tracepoint:sched:sched_stick_numa
tracepoint:sched:sched_swap_numa
tracepoint:sched:sched_switch
tracepoint:sched:sched_wait_task
tracepoint:sched:sched_wake_idle_without_ipi
tracepoint:sched:sched_wakeup
tracepoint:sched:sched_wakeup_new
tracepoint:sched:sched_waking


#### 2.3.4 bcc


使用bcc查看:



yl@yl-virtual-machine:~/Desktop$ sudo /usr/share/bcc/tools/tplist -v “sched:*”
sched:sched_kthread_stop
char comm[TASK_COMM_LEN];
pid_t pid;
sched:sched_kthread_stop_ret
int ret;
sched:sched_kthread_work_queue_work
void * work;
void * function;
void * worker;
sched:sched_kthread_work_execute_start
void * work;
void * function;
sched:sched_kthread_work_execute_end
void * work;
void * function;
sched:sched_waking
char comm[TASK_COMM_LEN];
pid_t pid;
int prio;
int target_cpu;
sched:sched_wakeup
char comm[TASK_COMM_LEN];
pid_t pid;
int prio;
int target_cpu;
sched:sched_wakeup_new
char comm[TASK_COMM_LEN];
pid_t pid;
int prio;
int target_cpu;
sched:sched_switch
char prev_comm[TASK_COMM_LEN];
pid_t prev_pid;
int prev_prio;
long prev_state;
char next_comm[TASK_COMM_LEN];
pid_t next_pid;
int next_prio;
sched:sched_migrate_task
char comm[TASK_COMM_LEN];
pid_t pid;
int prio;
int orig_cpu;
int dest_cpu;
sched:sched_process_free
char comm[TASK_COMM_LEN];
pid_t pid;
int prio;
sched:sched_process_exit
char comm[TASK_COMM_LEN];
pid_t pid;
int prio;
sched:sched_wait_task
char comm[TASK_COMM_LEN];
pid_t pid;
int prio;
sched:sched_process_wait
char comm[TASK_COMM_LEN];
pid_t pid;
int prio;
sched:sched_process_fork
char parent_comm[TASK_COMM_LEN];
pid_t parent_pid;
char child_comm[TASK_COMM_LEN];
pid_t child_pid;
sched:sched_process_exec
__data_loc char[] filename;
pid_t pid;
pid_t old_pid;
sched:sched_stat_wait
char comm[TASK_COMM_LEN];
pid_t pid;
u64 delay;
sched:sched_stat_sleep
char comm[TASK_COMM_LEN];
pid_t pid;
u64 delay;
sched:sched_stat_iowait
char comm[TASK_COMM_LEN];
pid_t pid;
u64 delay;
sched:sched_stat_blocked
char comm[TASK_COMM_LEN];
pid_t pid;
u64 delay;
sched:sched_stat_runtime
char comm[TASK_COMM_LEN];
pid_t pid;
u64 runtime;
u64 vruntime;
sched:sched_pi_setprio
char comm[TASK_COMM_LEN];
pid_t pid;
int oldprio;
int newprio;
sched:sched_process_hang
char comm[TASK_COMM_LEN];
pid_t pid;
sched:sched_move_numa
pid_t pid;
pid_t tgid;
pid_t ngid;
int src_cpu;
int src_nid;
int dst_cpu;
int dst_nid;
sched:sched_stick_numa
pid_t src_pid;
pid_t src_tgid;
pid_t src_ngid;
int src_cpu;
int src_nid;
pid_t dst_pid;
pid_t dst_tgid;
pid_t dst_ngid;
int dst_cpu;
int dst_nid;
sched:sched_swap_numa
pid_t src_pid;
pid_t src_tgid;
pid_t src_ngid;
int src_cpu;
int src_nid;
pid_t dst_pid;
pid_t dst_tgid;
pid_t dst_ngid;
int dst_cpu;
int dst_nid;
sched:sched_wake_idle_without_ipi
int cpu;


#### 2.3.5 SystemTap


SystemTap也可以查看:



[root@localhost ~]# stap -L ‘kernel.trace(“sched*”)’
kernel.trace(“sched:sched_kthread_stop”) $t:struct task_struct*
kernel.trace(“sched:sched_kthread_stop_ret”) $ret:int
kernel.trace(“sched:sched_migrate_task”) $p:struct task_struct* $dest_cpu:int
kernel.trace(“sched:sched_move_numa”) $tsk:struct task_struct* $src_cpu:int $dst_cpu:int
kernel.trace(“sched:sched_pi_setprio”) $tsk:struct task_struct* $newprio:int
kernel.trace(“sched:sched_process_exec”) $p:struct task_struct* $old_pid:pid_t $bprm:struct linux_binprm*
kernel.trace(“sched:sched_process_exit”) $p:struct task_struct*
kernel.trace(“sched:sched_process_fork”) $parent:struct task_struct* $child:struct task_struct*
kernel.trace(“sched:sched_process_free”) $p:struct task_struct*
kernel.trace(“sched:sched_process_hang”) $tsk:struct task_struct*
kernel.trace(“sched:sched_process_wait”) $pid:struct pid*
kernel.trace(“sched:sched_stat_blocked”) $tsk:struct task_struct* $delay:u64
kernel.trace(“sched:sched_stat_iowait”) $tsk:struct task_struct* $delay:u64
kernel.trace(“sched:sched_stat_runtime”) $tsk:struct task_struct* $runtime:u64 $vruntime:u64

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前在阿里

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以点击这里获取!

技术停滞不前!**

因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
[外链图片转存中…(img-rUukGtJi-1715279547694)]
[外链图片转存中…(img-5XTnmZlJ-1715279547695)]
[外链图片转存中…(img-kjhLmRVg-1715279547696)]
[外链图片转存中…(img-iif2GhAh-1715279547697)]
[外链图片转存中…(img-h8DeyVX3-1715279547697)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以点击这里获取!

  • 13
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值