调试ftrace(二)新增跟踪点
内核的各个子系统已经有大量的跟踪点,如果这些跟踪点无法满足工作中的需求,可以自己手动添加跟踪点。
添加跟踪点有两种方式,一种是仿照`events/`目录下的跟踪点,使用`TRACE_EVENT()` 宏添加。另一种是参考内核目录`samples/trace_events`添加。本文对这两种方式分别进行介绍。
## 使用 TRACE_EVENT 定义 tracepoint
我们仿照`events/timer/timer_start`,添加一个`timer_stat`的跟踪点,获取`start_pid`和`slack`参数。
首先,需要在`include/trace/events/timer.h`头文件种添加名为`timer_stat`的跟踪点。
```c
/**
* timer_stat - ftrace interface timer_stat
* @timer: pointer to struct timer_list
*/
TRACE_EVENT(timer_stat,
TP_PROTO(struct timer_list *timer),
TP_ARGS(timer),
TP_STRUCT__entry(
__field( void *, timer )
__field( int, start_pid )
__field( int, slack)
),
TP_fast_assign(
__entry->timer = timer;
__entry->start_pid = timer->start_pid;
__entry->slack = timer->slack;
),
TP_printk("ftrace interface timer_stat:timer=%p pid=%d slack=%d ",
__entry->timer,__entry->start_pid,__entry->slack)
);
```
`TRACE_EVENT()`宏如下
```c
#define TRACE_EVENT(name, proto, args, struct, assign, print)
DEFINE_TRACE(name)
```
- name:表示跟踪点的名字,如上面的timer_stat。
- proto:表示跟踪点调用的入参的原型,比如`timer`类型为`struct timer_list *`。
- args:表示参数。
- struct:定义跟踪器内部使用的`__entry`数据结构。
- assign:把参数复制到`__entry`数据结构中。
- print:定义输出的格式。
接着在`kernel/kernel/time/timer.c` `debug_activate()`添加`trace_timer_stat()`。
```c
static inline void
debug_activate(struct timer_list *timer, unsigned long expires)
{
debug_timer_activate(timer);
trace_timer_start(timer, expires, timer->flags);
trace_timer_stat(timer);
}
```
重新编译内核后,烧写到设备中,即可看到`sys`节点已经有了新增的跟踪点。

使能跟踪点后,查看trace点的输出。

## 编译为独立的ko文件
内核还提供了一个跟踪点的例子,在`samples/trace_events` 目录下。
`trace_event_init()`创建内核线程一个名为`event-sample`内核线程。
```c
static int __init trace_event_init(void)
{
simple_tsk = kthread_run(simple_thread, NULL, "event-sample");
if (IS_ERR(simple_tsk))
return -1;
return 0;
}
```
`kthread_should_stop()`用于创建的线程检查结束标志,并决定是否退出。
```c
static int simple_thread(void *arg)
{
int cnt = 0;
while (!kthread_should_stop())
simple_thread_func(cnt++);
return 0;
}
```
`set_current_state()` 来设置进程的状态,设置为`TASK_INTERRUPTIBLE`表示是可以被信号和`wake_up()`唤醒的,当信号到来时,进程会被设置为可运行。
`schedule_timeout()`将当前task调度出cpu,重新调度间隔为`HZ`。接着`trace_`开头的函数就会依次打印跟踪点的信息。
```c
static void simple_thread_func(int cnt)
{
int array[6];
int len = cnt % 5;
int i;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
for (i = 0; i < len; i++)
array[i] = i + 1;
array[i] = 0;
/* Silly tracepoints */
trace_foo_bar("hello", cnt, array, random_strings[len],
tsk_cpus_allowed(current));
trace_foo_with_template_simple("HELLO", cnt);
trace_foo_bar_with_cond("Some times print", cnt);
trace_foo_with_template_cond("prints other times", cnt);
trace_foo_with_template_print("I have to be different", cnt);
}
```
`trace_foo_with_template_simple`跟踪点的实现方式也是使用的`TRACE_EVENT ()`宏,这里不再赘述。
最后将文件编译为ko拷贝到设备上`insmod`后,即可看到`sys`目录下已经有新增的节点。
```bash
cd /home/zhongyi/code/rk3399_linux_release_v2.5.1_20210301/kernel/samples/trace_events
make -C /home/zhongyi/code/rk3399_linux_release_v2.5.1_20210301/kernel/ M=$(pwd) modules
```
```bash
root@firefly:/sys/kernel/debug/tracing# cat available_events | grep sample
sample-trace:foo_bar
sample-trace:foo_bar_with_cond
race:foo_bar_with_fn
sample-trace:foo_with_template_simple
sample-trace:foo_with_template_cond
sample-trace:foo_with_template_fn
sample-trace:foo_with_template_print
power:pstate_sample
```
```bash
root@firefly:/sys/kernel/debug/tracing# cd events/sample-trace/
root@firefly:/sys/kernel/debug/tracing/events/sample-trace# ls
enable foo_bar_with_cond foo_with_template_fn
filter foo_bar_with_fn foo_with_template_print
foo_bar foo_with_template_cond foo_with_templ_simple
root@firefly:/sys/kernel/debug/tracing/events/sample-trace# echo 1 > enable
root@firefly:/sys/kernel/debug/tracing/events/sample-trace# cat /sys/kernel/debug/tracing/trace
```

## TRACE_EVENT_CONDITION()
在某些情况下,跟踪点只有在某个条件发生时才会被调用,类似于
```c
if (cond)
trace_foo();
```
`TRACE_EVENT_CONDITION()`宏就是这个作用,它和`TRACE_EVENT()`相比只是在参数中多加了一个cond条件。`TP_CONDITION()`会对条件做个判断。
```c
TRACE_EVENT(name, proto, args, struct, assign, printk)
TRACE_EVENT_CONDITION(name, proto, args, cond, struct, assign, printk)
```
详细使用方法可以参考`trace-events-sample.h`。
## TRACE_EVENT_FN()
`TRACE_EVENT_FN()`是在跟踪点使能前和使能后分别打印一些信息。相比于`TRACE_EVENT()`,`TRACE_EVENT_FN()`多了两个参数`reg`和`unreg`,
```c
TRACE_EVENT(name, proto, args, struct, assign, printk)
TRACE_EVENT_FN( name, proto, args, struct, assign, printk, reg, unreg)
```
`reg` 和`unreg`原型为
```c
void reg(void)
```
`reg`函数在跟踪点使能前打印,`unreg`函数在跟踪点使能后打印。`reg` 和`unreg`可以根据实际情况置其中一个为NULL,也可以全部置为NULL。
详细使用方法可以参考`trace-events-sample.h`。
## 本文参考
samples/trace_events
多事之秋,2022保险大事盘点,还有更大的大事么?2022年还剩最后10天这是多事之秋的一年系列大事深刻地影响着保险业01大批保险公司评级不达标据银保监会公布2022年第三季度181家纳入评审的公司15家得C,9家得DCD合计共有
日本央行货币政策突变图为行人走在日本东京站丸之内出口附近的马路上。孙佳林摄(新华社发)12月20日,日本央行在为期两天的货币政策会议上,决定调整部分收益率曲线控制(YCC)政策,将长期利率波动幅度从原
12月FOMC会议报告市场预期主要央行加息周期何时见顶?内容摘要美联储加息50bp,将联邦基金利率目标区间上调至4。254。5,同幅度上调超额准备金利率至4。4隔夜逆回购利率至4。3。对于2024年,有7名委员认为应降息100bp至44
永兴联通创新打造智慧社区助力社会治理数字化红网时刻新闻12月22日讯(通讯员何杨)日前,由永兴联通打造的智慧社区平台正式亮相于永兴金穗家园小区,通过数字赋能实现社区治理全域化网格管理精细化,智慧社区让服务居民更有温度,更有
新消费观察快递春节不打烊,物流企业纷纷推出年货消费保障计划封面新闻记者雷强随着春节临近,采购年货成了不少消费者的头等大事。春节不打烊已成为近年快递业的标配,目前已有多家快递企业联合电商平台开始为年货春运做准备。天猫和菜鸟12月21日宣布,
隔夜美股大指数均涨超1汽车板块小鹏涨近1112月21日美东时间周三,耐克与联邦快递两家大型公司的财报点燃了企业盈利状况可能好于预期的希望。市场仍在评估美联储政策前景与美国经济衰退风险,截止收盘,道指收盘上涨526。74点,
年度家电总结消费篇尽管2022年开启于冬奥会的欢快气氛中,但冬奥会结束后,全球便迎来俄乌冲突黑天鹅,原本已经处于回落区间的原材料价格再度飙升,欧美地区的通胀水平进一步拉高,美联储紧接着启动加息,将全
2023年就业重点活动有哪些?请查收央视网消息中央经济工作会议强调,对于我们这么大的经济体而言,保持经济平稳运行至关重要。要着力稳增长稳就业稳物价,保持经济运行在合理区间。该如何稳就业?13月,人力资源社会保障部组织
什么是富硒农产品?缺硒人群如何选择富硒农产品?随着生活习惯和饮食习惯的改变,如今越来越多的人成为亚健康人群,主要表现有怕冷怕热易于感冒骨质疏松睡眠紊乱等。造成亚健康状态的原因有很多,总结起来就是内因和外因,内因主要是受情绪影响
山东深化预算绩效管理改革2019年以来,山东省深化财政预算绩效管理改革,进行事前事中事后全过程绩效评价。通过对项目预算进行成本分析测算和控制,强化监督考核,试点地区把钱花在刀刃上,有效化解了财政收支矛盾,
冯杰争分夺秒履行与自己的十年之约工人日报中工网记者邹明强通讯员王嵩松李晴14年前,河南农村小伙冯杰,一脸的稚气入职江汉石油工程公司。形单影只的青葱少年,望向一台台正在驶入基地的压裂车组,他却暗自下定决心,未来一定