trace-event
创始人
2024-04-30 03:04:41
0

trace-event

1 说明背景

内核源码中放置很多静态跟踪节点,这些节点可以被关联到对应的回调函数。当我想要调试某个子系统/模块时,通过debug系统将对应的节点开启(将回调函数挂钩子到静态跟踪点上,与之关联),这样内核在执行到跟踪点位置的时候会调用钩子函数,最终执行结果将被输出写到一个环形日志缓存区里,通过debug系统查看信息。

我把它当作一种内核层面的调试手段。当我想要调试某一个模块,开启对应的节点就好了,trace event基于现有的跟踪节点(一般是写代码的添加好的)效率高些,或者解决新的bug时将关键信息固化到调试系统里。

接下来学习 trace_event 的工作原理和使用方法,希望未来能积累足够多的使用案例。

2 如何使用

mount -t tracefs nodev /sys/kernel/tracing # 挂载tracefs
cat /sys/kernel/debug/tracing/available_events # 查看当前支持的跟踪事件列表

case01: 打开"gsgpu"驱动跟踪节点

echo 1 > /sys/kernel/debug/tracing/events/gsgpu/enable && \
echo 0 > /sys/kernel/debug/tracing/trace && \
/root/run_test.sh ; cp /sys/kernel/debug/tracing/trace /test.txt && \
echo 0 > /sys/kernel/debug/tracing/events/gsgpu/enable
cat /test.txt

case02: 通过filter过滤事件

echo 0 > /sys/kernel/debug/tracing/events/gsgpu/enable && \
echo 1 > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/enable && \
echo 0 > /sys/kernel/debug/tracing/trace && \
echo "bo_size >= 50000" > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/filter && \
/root/run_test.sh ; cp /sys/kernel/debug/tracing/trace /test.txt && \
echo 0 > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/filter
cat /test.txt

case03: 通过trigger查看栈回溯

echo 0 > /sys/kernel/debug/tracing/events/gsgpu/enable && \
echo 1 > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/enable && \
echo 0 > /sys/kernel/debug/tracing/trace && \
echo 'stacktrace' > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/trigger && \
/root/run_test.sh ; cp /sys/kernel/debug/tracing/trace /test.txt && \
echo '!stacktrace' > /sys/kernel/debug/tracing/events/gsgpu/gsgpu_bo_move/trigger && \
cat /test.txt

3 如何解析

1、调试信息

# tracer: nop
#
# entries-in-buffer/entries-written: 20103/1994095   #P:4  
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay 
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |-0     [002] d.h.  6972.008532: gsgpu_iv: client_id:4 src_id:0 ring:0 vmid:0 timestamp: 10376293560622087932 pasid:2415919108 src_data: 00000000 76089440 90000004 00000000

2、事件输出格式定义

root@loongson-pc:/sys/kernel/debug/tracing/events/gsgpu# cat ./gsgpu_iv/format
name: gsgpu_iv
ID: 1903
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:unsigned client_id;	offset:8;	size:4;	signed:0;field:unsigned src_id;	offset:12;	size:4;	signed:0;field:unsigned ring_id;	offset:16;	size:4;	signed:0;field:unsigned vmid;	offset:20;	size:4;	signed:0;field:unsigned vmid_src;	offset:24;	size:4;	signed:0;field:uint64_t timestamp;	offset:32;	size:8;	signed:0;field:unsigned timestamp_src;	offset:40;	size:4;	signed:0;field:unsigned pasid;	offset:44;	size:4;	signed:0;field:unsigned src_data[4];	offset:48;	size:16;	signed:0;print fmt: "client_id:%u src_id:%u ring:%u vmid:%u timestamp: %llu pasid:%u src_data: %08x %08x %08x %08x
", REC->client_id, REC->src_id, REC->ring_id, REC->vmid, REC->timestamp, REC->pasid, REC->src_data[0], REC->src_data[1], REC->src_data[2], REC->src_data[3]

3、源码实现(插桩方案)

/* src file: "drivers/gpu/drm/gsgpu/include/gsgpu_trace.h" */TRACE_EVENT(gsgpu_iv, // 名称TP_PROTO(struct gsgpu_iv_entry *iv), // 原型TP_ARGS(iv), // 原型使用的参数TP_STRUCT__entry(__field(unsigned, client_id)__field(unsigned, src_id)__field(unsigned, ring_id)__field(unsigned, vmid)__field(unsigned, vmid_src)__field(uint64_t, timestamp)__field(unsigned, timestamp_src)__field(unsigned, pasid)__array(unsigned, src_data, 4)), // 描述将存储在跟踪程序环缓冲区中的数据的结构布局TP_fast_assign(__entry->client_id = iv->client_id;__entry->src_id = iv->src_id;__entry->ring_id = iv->ring_id;__entry->vmid = iv->vmid;__entry->vmid_src = iv->vmid_src;__entry->timestamp = iv->timestamp;__entry->timestamp_src = iv->timestamp_src;__entry->pasid = iv->pasid;__entry->src_data[0] = iv->src_data[0];__entry->src_data[1] = iv->src_data[1];__entry->src_data[2] = iv->src_data[2];__entry->src_data[3] = iv->src_data[3];), // 定义将来自参数的数据保存到环形缓冲区的方式TP_printk("client_id:%u src_id:%u ring:%u vmid:%u timestamp: %llu pasid:%u src_data: %08x %08x %08x %08x\n",__entry->client_id, __entry->src_id,__entry->ring_id, __entry->vmid,__entry->timestamp, __entry->pasid,__entry->src_data[0], __entry->src_data[1],__entry->src_data[2], __entry->src_data[3]) // 定义了如何使用printk()打印TP_STRUCT__entry结构中的字段
);/* src file: "drivers/gpu/drm/gsgpu/gpu/gsgpu_irq.c" */
void gsgpu_irq_dispatch(struct gsgpu_device *adev,struct gsgpu_iv_entry *entry)
{// .....trace_gsgpu_iv(entry); // 插桩:桩函数// .....
}

4 如何新增

CASE001:添加trace文件和节点

0、参考内核中已经存在的用例samples/trace_events
1、首先需要在include/trace/events/文件夹下添加一个自己event的头文件

include/trace/events/sched.h

2、在探测点位置中调用桩函数,需要遵循注释的标准格式

kernel/sched/core.c

CASE002:向指定trace文件添加节点

wangjianfeng@dev:~/source/linux-4.19-loongson$ git diff
diff --git a/drivers/gpu/drm/gsgpu/gpu/gfx_v8_0.c b/drivers/gpu/drm/gsgpu/gpu/gfx_v8_0.c
index b6e14e4c5b40..7a02414475f0 100644
--- a/drivers/gpu/drm/gsgpu/gpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/gsgpu/gpu/gfx_v8_0.c
@@ -26,6 +26,7 @@#include "gsgpu_gfx.h"#include "vi.h"#include "gsgpu_cp.h"
+#include "gsgpu_trace.h"#include "ivsrcid/ivsrcid_vislands30.h"@@ -569,6 +570,7 @@ static void gfx_v8_0_ring_emit_rreg(struct gsgpu_ring *ring, uint32_t reg)static void gfx_v8_0_ring_emit_wreg(struct gsgpu_ring *ring, uint32_t reg,uint32_t val){
+       trace_ring_emit_wreg(ring, reg, val);gsgpu_ring_write(ring, GSPKT(GSPKT_WRITE, 2) | WRITE_DST_SEL(0) | WRITE_WAIT);gsgpu_ring_write(ring, reg);gsgpu_ring_write(ring, val);
diff --git a/drivers/gpu/drm/gsgpu/include/gsgpu_trace.h b/drivers/gpu/drm/gsgpu/include/gsgpu_trace.h
index a9bb78d64a5e..ad8566a2260c 100644
--- a/drivers/gpu/drm/gsgpu/include/gsgpu_trace.h
+++ b/drivers/gpu/drm/gsgpu/include/gsgpu_trace.h
@@ -464,6 +464,25 @@ TRACE_EVENT(gsgpu_bo_move,__entry->new_placement, __entry->bo_size));+TRACE_EVENT(ring_emit_wreg,
+           TP_PROTO(struct gsgpu_ring *ring, uint32_t reg, uint32_t val),
+           TP_ARGS(ring, reg, val),
+           TP_STRUCT__entry(
+                     __field(struct gsgpu_ring *, ring)
+                     __field(uint32_t , reg)
+                     __field(uint32_t , val)
+                 ),
+           TP_fast_assign(
+                     __entry->ring = ring;
+                     __entry->reg = reg;
+                     __entry->val = val;
+                 ),
+           TP_printk("ring=%p, reg=0x%08x, val=0x%08x",
+                     __entry->ring,
+                     __entry->reg,
+                     __entry->val)
+);
+#undef GSGPU_JOB_GET_TIMELINE_NAME#endif

5 记录问答

1、是什么? => trace event 就是利用 ftrace 框架,实现低性能损耗,对执行流无影响的一种信息输出机制
2、背景和发展历程 => 谁引入?何时引入?用于什么场景?
3、为什么要有这样的机制? => 提供一种内核调试的解决方案,解决了一些printk手段的缺陷
4、代码实现在哪?=> 开源参考samples/trace_events
5、如何使用?=> 参考内核文档
6、应用案例?=> 一次解决Linux内核内存泄漏实战全过程;利用Ftrace追踪一次系统调用的时间分布;
7、Ftrace和trace event的区别?=> Ftrace是通用的调试框架(提供函数钩子的基础设施;基于 tracefs 文件系统的 trace 框架),trace event是利用 ftrace 框架实现的一种信息输出机制
8、trace event跟踪点的位置如何执行到插桩函数?关键改动有哪些?=> 参考trace event原理与实现的内容
9、trace evnet过滤器filter和触发器trigger都有设置的情况下,哪一个优先级更高?=> 测试结果:触发器处理过滤器之后的信息

References

Doc | Event Tracing
阅码场 | Linux内核tracers的实现原理与应用
张乐 | 模块化学习办法
泰晓科技 | trace-event 基本用法
pwl999 | Linux ftrace 1.2、trace event
Doc | Using the Linux Kernel Tracepoints
LWN | Using the TRACE_EVENT() macro (Part 1)
SRC | samples/trace_events
张乐 | amdgpu调试接口

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...