• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Trace调测
2
3
4## 基本概念
5
6Trace调测旨在帮助开发者获取内核的运行流程,各个模块、任务的执行顺序,从而可以辅助开发者定位一些时序问题或者了解内核的代码运行过程。
7
8
9## 运行机制
10
11内核提供一套Hook框架,将Hook点预埋在各个模块的主要流程中, 在内核启动初期完成Trace功能的初始化,并注册Trace的处理函数到Hook中。
12
13当系统触发到一个Hook点时,Trace模块会对输入信息进行封装,添加Trace帧头信息,包含事件类型、运行的cpuid、运行的任务id、运行的相对时间戳等信息;
14
15Trace提供2种工作模式,离线模式和在线模式。
16
17离线模式会将trace frame记录到预先申请好的循环buffer中。如果循环buffer记录的frame过多则可能出现翻转,会覆盖之前的记录,故保持记录的信息始终是最新的信息。Trace循环buffer的数据可以通过shell命令导出进行详细分析,导出信息已按照时间戳信息完成排序。
18
19![zh-cn_image_0000001214329013](figures/zh-cn_image_0000001214329013.png)
20
21在线模式需要配合IDE使用,实时将trace frame记录发送给IDE,IDE端进行解析并可视化展示。
22
23
24## 接口说明
25
26
27### 内核态
28
29LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以查看[API](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h)参考。
30
31  **表1** Trace模块接口说明
32
33| 功能分类 | 接口描述 |
34| -------- | -------- |
35| 启停控制 | LOS_TraceStart:启动Trace<br/>LOS_TraceStop:停止Trace |
36| 操作Trace记录的数据 | LOS_TraceRecordDump:输出Trace缓冲区数据<br/>LOS_TraceRecordGet:获取Trace缓冲区的首地址<br/>LOS_TraceReset:清除Trace缓冲区中的事件 |
37| 过滤Trace记录的数据 | LOS_TraceEventMaskSet:设置事件掩码,仅记录某些模块的事件 |
38| 屏蔽某些中断号事件 | LOS_TraceHwiFilterHookReg:注册过滤特定中断号事件的钩子函数 |
39| 插桩函数 | LOS_TRACE_EASY:简易插桩<br/>LOS_TRACE:标准插桩 |
40
41- 当用户需要针对自定义事件进行追踪时,可按规则在目标源代码中进行插桩,系统提供如下2种插桩接口:
42  - LOS_TRACE_EASY(TYPE, IDENTITY, params...) 简易插桩。
43     - 用户在目标源代码中插入该接口即可。
44     - TYPE有效取值范围为[0, 0xF],表示不同的事件类型,不同取值表示的含义由用户自定义。
45     - IDENTITY类型UINTPTR,表示事件操作的主体对象。
46     - Params类型UINTPTR,表示事件的参数。
47          示例:
48
49        ```
50        假设需要新增对文件(fd1、fd2)读写操作的简易插桩,
51        自定义读操作为type:1, 写操作为type:2,则
52        在读fd1文件的适当位置插入:
53        LOS_TRACE_EASY(1, fd1, flag, size);
54        在读fd2文件的适当位置插入:
55        LOS_TRACE_EASY(1, fd2, flag, size);
56        在写fd1文件的适当位置插入:
57        LOS_TRACE_EASY(2, fd1, flag, size);
58        在写fd2文件的适当位置插入:
59        LOS_TRACE_EASY(2, fd2,flag, size);
60        ```
61  - LOS_TRACE(TYPE, IDENTITY, params...) 标准插桩。
62     - 相比简易插桩,支持动态过滤事件和参数裁剪,但使用上需要用户按规则来扩展。
63     - TYPE用于设置具体的事件类型,可以在头文件los_trace.h中的enum LOS_TRACE_TYPE中自定义事件类型。定义方法和规则可以参考其他事件类型。
64     - IDENTITY和Params的类型及含义同简易插桩。
65          示例:
66
67        ```
68        1.在enum LOS_TRACE_MASK中定义事件掩码,即模块级别的事件类型。
69          定义规范为TRACE_#MOD#_FLAG,#MOD#表示模块名。
70          例如:
71          TRACE_FS_FLAG = 0x4000
72        2.在enum LOS_TRACE_TYPE中定义具体事件类型。
73          定义规范为#TYPE# = TRACE_#MOD#_FLAG | NUMBER,
74          例如:
75          FS_READ  = TRACE_FS_FLAG | 0; // 读文件
76          FS_WRITE = TRACE_FS_FLAG | 1; // 写文件
77        3.定义事件参数。定义规范为#TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ...
78          其中的#TYPE#就是上面2中的#TYPE#,
79          例如:
80          #define FS_READ_PARAMS(fp, fd, flag, size)    fp, fd, flag, size
81          宏定义的参数对应于Trace缓冲区中记录的事件参数,用户可对任意参数字段进行裁剪:
82          当定义为空时,表示不追踪该类型事件:
83          #define FS_READ_PARAMS(fp, fd, flag, size) // 不追踪文件读事件
84        4.在适当位置插入代码桩。
85          定义规范为LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...))
86          LOS_TRACE(FS_READ, fp, fd, flag, size); // 读文件的代码桩,
87          #TYPE#之后的入参就是上面3中的FS_READ_PARAMS函数的入参
88        ```
89
90        > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
91        > 预置的Trace事件及参数均可以通过上述方式进行裁剪,参数详见 [kernel\include\los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h)92
93- Trace Mask事件过滤接口LOS_TraceEventMaskSet(UINT32 mask),其入参mask仅高28位生效(对应LOS_TRACE_MASK中某模块的使能位),仅用于模块的过滤,暂不支持针对某个特定事件的细粒度过滤。例如:LOS_TraceEventMaskSet(0x202),则实际设置生效的mask为0x200(TRACE_QUE_FLAG),QUE模块的所有事件均会被采集。一般建议使用的方法为: LOS_TraceEventMaskSet(TRACE_EVENT_FLAG | TRACE_MUX_FLAG | TRACE_SEM_FLAG | TRACE_QUE_FLAG);
94
95- 如果仅需要使能简易插桩事件,通过设置Trace Mask为TRACE_MAX_FLAG即可。
96
97- Trace缓冲区有限,事件写满之后会覆盖写,用户可通过LOS_TraceRecordDump中打印的CurEvtIndex识别最新记录。
98
99- Trace的典型操作流程为:LOS_TraceStart、 LOS_TraceStop、 LOS_TraceRecordDump.
100
101- 针对中断事件的Trace, 提供中断号过滤,用于解决某些场景下特定中断号频繁触发导致其他事件被覆盖的情况,用户可自定义中断过滤的规则,
102    示例如下:
103
104  ```c
105  BOOL Example_HwiNumFilter(UINT32 hwiNum)
106  {
107      if ((hwiNum == TIMER_INT) || (hwiNum == DMA_INT)) {
108          return TRUE;
109      }
110      return FALSE;
111  }
112  LOS_TraceHwiFilterHookReg(Example_HwiNumFilter);
113  ```
114
115则当中断号为TIMER_INT 或者DMA_INT时,不记录中断事件。
116
117
118### 用户态
119
120新增trace字符设备,位于"/dev/trace",通过对设备节点的read、write、ioctl,实现用户态trace的读写和控制:
121
122- read: 用户态读取Trace记录数据
123
124- write: 用户态事件写入
125
126- ioctl: 用户态Trace控制操作,包括
127
128
129```c
130#define TRACE_IOC_MAGIC   'T'
131#define TRACE_START      _IO(TRACE_IOC_MAGIC, 1)
132#define TRACE_STOP       _IO(TRACE_IOC_MAGIC, 2)
133#define TRACE_RESET      _IO(TRACE_IOC_MAGIC, 3)
134#define TRACE_DUMP		 _IO(TRACE_IOC_MAGIC, 4)
135#define TRACE_SET_MASK	 _IO(TRACE_IOC_MAGIC, 5)
136```
137
138分别对应Trace启动(LOS_TraceStart)、停止(LOS_TraceStop)、清除记录(LOS_TraceReset)、dump记录(LOS_TraceRecordDump)、设置事件过滤掩码(LOS_TraceEventMaskSet)
139
140具体的使用方法参见[用户态编程实例](kernel-small-debug-trace.md#用户态)。
141
142
143## 开发指导
144
145
146### 内核态开发流程
147
148开启Trace调测的典型流程如下:
149
1501. 配置Trace模块相关宏。
151   配置Trace控制宏LOSCFG_KERNEL_TRACE,默认关,在 kernel/liteos_a 目录下执行 make update_config 命令配置 "Kernel-&gt;Enable Hook Feature-&gt;Enable Trace Feature" 中打开:
152
153   | 配置项 | menuconfig选项 | 含义 | 设置值 |
154   | -------- | -------- | -------- | -------- |
155   | LOSCFG_KERNEL_TRACE | Enable&nbsp;Trace&nbsp;Feature | Trace模块的裁剪开关 | YES/NO |
156   | LOSCFG_RECORDER_MODE_OFFLINE | Trace&nbsp;work&nbsp;mode&nbsp;-&gt;Offline&nbsp;mode | Trace工作模式为离线模式 | YES/NO |
157   | LOSCFG_RECORDER_MODE_ONLINE | Trace&nbsp;work&nbsp;mode&nbsp;-&gt;Online&nbsp;mode | Trace工作模式为在线模式 | YES/NO |
158   | LOSCFG_TRACE_CLIENT_INTERACT | Enable&nbsp;Trace&nbsp;Client&nbsp;Visualization&nbsp;and&nbsp;Control | 使能与Trace&nbsp;IDE&nbsp;(dev&nbsp;tools)的交互,包括数据可视化和流程控制 | YES/NO |
159   | LOSCFG_TRACE_FRAME_CORE_MSG | Enable&nbsp;Record&nbsp;more&nbsp;extended content<br>->Record&nbsp;cpuid,&nbsp;hardware&nbsp;interrupt status,&nbsp;task&nbsp;lock&nbsp;status | 记录CPUID、中断状态、锁任务状态 | YES/NO |
160   | LOSCFG_TRACE_FRAME_EVENT_COUNT | Enable&nbsp;Record&nbsp;more&nbsp;extended&nbsp;content<br>&nbsp;-&gt;Record&nbsp;event&nbsp;count,<br>&nbsp;which&nbsp;indicate&nbsp;the&nbsp;sequence&nbsp;of&nbsp;happend&nbsp;events | 记录事件的次序编号 | YES/NO |
161   | LOSCFG_TRACE_FRAME_MAX_PARAMS | Record&nbsp;max&nbsp;params | 配置记录事件的最大参数个数 | INT |
162   | LOSCFG_TRACE_BUFFER_SIZE | Trace&nbsp;record&nbsp;buffer&nbsp;size | 配置Trace的缓冲区大小 | INT |
163
1642. (可选)预置事件参数和事件桩(或使用系统默认的事件参数配置和事件桩)。
165
1663. (可选)调用LOS_TraceStop停止Trace后,清除缓冲区LOS_TraceReset(系统默认已启动trace)。
167
1684. (可选)调用LOS_TraceEventMaskSet设置需要追踪的事件掩码(系统默认的事件掩码仅使能中断与任务事件),事件掩码参见 [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h) 中的LOS_TRACE_MASK定义。
169
1705. 在需要记录事件的代码起始点调用LOS_TraceStart。
171
1726. 在需要记录事件的代码结束点调用LOS_TraceStop。
173
1747. 调用LOS_TraceRecordDump输出缓冲区数据(函数的入参为布尔型,FALSE表示格式化输出,TRUE表示输出到Trace IDE)。
175
176上述第3-7步中的接口,均封装有对应的shell命令,开启shell后可执行相应的命令,对应关系如下:
177
178- LOS_TraceReset —— trace_reset
179
180- LOS_TraceEventMaskSet —— trace_mask
181
182- LOS_TraceStart —— trace_start
183
184- LOS_TraceStop —— trace_stop
185
186- LOS_TraceRecordDump —— trace_dump
187
188
189### 内核态编程实例
190
191本实例实现如下功能:
192
1931. 创建一个用于Trace测试的任务。
194
1952. 设置事件掩码。
196
1973. 启动trace。
198
1994. 停止trace。
200
2015. 格式化输出trace数据。
202
203
204### 内核态示例代码
205
206该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c  中的 TestTaskEntry 中进行测试。
207实例代码如下:
208
209
210```c
211#include "los_trace.h"
212UINT32 g_traceTestTaskId;
213VOID Example_Trace(VOID)
214{
215    UINT32 ret;
216    LOS_TaskDelay(10);
217    /* 开启trace */
218    ret = LOS_TraceStart();
219    if (ret != LOS_OK) {
220        dprintf("trace start error\n");
221        return;
222    }
223    /* 触发任务切换的事件 */
224    LOS_TaskDelay(1);
225    LOS_TaskDelay(1);
226    LOS_TaskDelay(1);
227    /* 停止trace */
228    LOS_TraceStop();
229    LOS_TraceRecordDump(FALSE);
230}
231UINT32 Example_Trace_test(VOID)
232{
233    UINT32 ret;
234    TSK_INIT_PARAM_S traceTestTask;
235    /* 创建用于trace测试的任务 */
236    memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S));
237    traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace;
238    traceTestTask.pcName       = "TestTraceTsk";    /* 测试任务名称 */
239    traceTestTask.uwStackSize  = 0x800; // 0x800: trace test task stacksize
240    traceTestTask.usTaskPrio   = 5; // 5: trace test task priority
241    traceTestTask.uwResved   = LOS_TASK_STATUS_DETACHED;
242    ret = LOS_TaskCreate(&g_traceTestTaskId, &traceTestTask);
243    if (ret != LOS_OK) {
244        dprintf("TraceTestTask create failed .\n");
245        return LOS_NOK;
246    }
247    /* 系统默认情况下已启动trace, 因此可先关闭trace后清除缓存区后,再重启trace */
248    LOS_TraceStop();
249    LOS_TraceReset();
250    /* 开启任务模块事件记录 */
251    LOS_TraceEventMaskSet(TRACE_TASK_FLAG);
252    return LOS_OK;
253}
254LOS_MODULE_INIT(Example_Trace_test, LOS_INIT_LEVEL_KMOD_EXTENDED);
255```
256
257
258### 结果验证
259
260输出结果如下:
261
262
263```
264***TraceInfo begin***
265clockFreq = 50000000
266CurEvtIndex = 7
267Index   Time(cycles)      EventType      CurTask   Identity      params
2680       0x366d5e88        0x45           0x1       0x0           0x1f         0x4       0x0
2691       0x366d74ae        0x45           0x0       0x1           0x0          0x8       0x1f
2702       0x36940da6        0x45           0x1       0xc           0x1f         0x4       0x9
2713       0x3694337c        0x45           0xc       0x1           0x9          0x8       0x1f
2724       0x36eea56e        0x45           0x1       0xc           0x1f         0x4       0x9
2735       0x36eec810        0x45           0xc       0x1           0x9          0x8       0x1f
2746       0x3706f804        0x45           0x1       0x0           0x1f         0x4       0x0
2757       0x37070e59        0x45           0x0       0x1           0x0          0x8       0x1f
276***TraceInfo end***
277```
278
279输出的事件信息包括:发生时间、事件类型、事件发生在哪个任务中、事件操作的主体对象、事件的其他参数。
280
281- EventType:表示的具体事件可查阅头文件 [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h) 中的enum LOS_TRACE_TYPE。
282
283- CurrentTask:表示当前运行在哪个任务中,值为taskid。
284
285- Identity:表示事件操作的主体对象,可查阅头文件 [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h) 中的\#TYPE\#_PARAMS。
286
287- params:表示的事件参数可查阅头文件 [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h) 中的\#TYPE\#_PARAMS。
288
289下面以序号为0的输出项为例,进行说明。
290
291
292```
293Index   Time(cycles)      EventType      CurTask   Identity      params
2940       0x366d5e88        0x45           0x1       0x0           0x1f         0x4
295```
296
297- Time cycles可换算成时间,换算公式为cycles/clockFreq,单位为s。
298
299- 0x45为TASK_SWITCH即任务切换事件,当前运行的任务taskid为0x1。
300
301- Identity和params的含义需要查看TASK_SWITCH_PARAMS宏定义:
302
303```c
304#define TASK_SWITCH_PARAMS(taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus) \
305taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus
306```
307
308因为\#TYPE\#_PARAMS(IDENTITY, parma1...) IDENTITY, ...,所以Identity为taskId(0x0),第一个参数为oldPriority(0x1f)
309
310> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
311> params的个数由LOSCFG_TRACE_FRAME_MAX_PARAMS配置,默认为3,超出的参数不会被记录,用户应自行合理配置该值。
312
313综上所述,任务由0x1切换到0x0,0x1任务的优先级为0x1f,状态为0x4,0x0任务的优先级为0x0。
314