# ftrace的使用

这章我们先来看看如何使用ftrace。

说来惭愧，多少年前同事告诉我这种高级方法的时候，我还觉得麻烦，依然在使用printk。现在回想起来真实井底之蛙啊。

有几个非常不错的参考资料：

* 内核源码中的[使用手册](https://github.com/torvalds/linux/blob/master/Documentation/trace/ftrace.rst)
* [LWN 1](https://lwn.net/Articles/365835/)
* [LWN 2](https://lwn.net/Articles/366796/)
* [Secrets of the Ftrace function tracer](https://lwn.net/Articles/370423/)
* [LWN Artical List](https://lwn.net/Kernel/Index/#Tracing)
* [Ftrace Kernel Hooks: More than just tracing](https://blog.linuxplumbersconf.org/2014/ocw/system/presentations/1773/original/ftrace-kernel-hooks-2014.pdf)

接下来就从来看几个例子：

## Tracing测试文件目录

要和trace打交道都是要通过它的debugfs接口，默认情况下这个文件目录在 /sys/kernel/debug/tracing.

你也可以手动挂载到想要的位置：

```
mount -t tracefs nodev /sys/kernel/tracing
```

在这个目录下有很多重要的文件，具体每个文件的作用可以在[使用手册](https://github.com/torvalds/linux/blob/master/Documentation/trace/ftrace.rst)中找到。这里解说几个比较重要的

设置当前使用的tracer

* current\_tracer
* available\_tracer

是否过滤函数

* available\_filter\_functions
* set\_ftrace\_filter
* set\_graph\_function

得到trace输出

* trace
* per\_cpu/cpu0/trace
* trace\_pipe

控制是否将跟踪输出写入

* tracing\_on

像我这样的初级小白，了解这么几个文件就够用了。

## 使用function tracer

先来看一个完整的使用方法。

```
echo 0 > tracing_on
echo function > current_tracer
echo 1 > tracing_on
# wait a while
echo 0 > tracing_on
cat trace
cat per_cpu/cpu0/trace
```

tracing\_on用来控制是否实际输出到trace文件，所以我们在开始和结束时，我们都关掉输出，以免有太多的输出内容。 第二个命令用来指定这次使用的是function trace。因为没有设置函数过滤，所以应该是所有的内核函数都会被记录。 打开输出，停一会儿再关掉后，就可以通过trace文件查看这段时间内的内核运行情况了。

另外还可以通过查看per\_cpu/cpu0/trace文件来只观察在cpu0上发生的内核函数调用。这是一个非常不错去除多个cpu之间干扰的好方法。

## 使用function\_graph tracer

这个例子和之前的区别在于选择了不同的tracer，function\_graph的话可以打印出函数调用的关系，更加方便理解。

```
echo 0 > tracing_on
echo function_graph > current_tracer
echo 1 > tracing_on
# wait a while
echo 0 > tracing_on
cat trace
cat per_cpu/cpu0/trace
```

也就不做过多的解释。

## 使用trace\_printk()

这个函数的用法和printk()一样，只是输出不在console，而是在ftrace的ring buffer。

而且在nop tracer的情况下也能在trace中看到输出。这样就不会被函数调用信息干扰到了。

汗颜，现在才知道这个。

## 使用function command

这个用法来自作者的第三篇文章[Secrets of the Ftrace function tracer](https://lwn.net/Articles/370423/)。因为trace的内容太多，这个方法能够在某个函数被调用时停止trace，方便调试时观察到trace信息。

方法如下

```
# echo '__bad_area_nosemaphore:traceoff' > set_ftrace_filter
# cat set_ftrace_filter
#### all functions enabled ####
__bad_area_nosemaphore:traceoff:unlimited
```

这样就可以在函数\_\_bad\_area\_nosemaphore触发时，停止trace，留住最后的案发现场。

## 现实谁调用了某个函数

在学习内核的过程中，我们有时候会想了解一下一个函数都会被谁调用，整个调用栈是什么样子的。ftrace也提供了这个功能。

```
   [tracing]# echo kfree > set_ftrace_filter
   [tracing]# cat set_ftrace_filter
   kfree
   [tracing]# echo function > current_tracer
   [tracing]# echo 1 > options/func_stack_trace
   [tracing]# cat trace | tail -8
    => sys32_execve
    => ia32_ptregs_common
                cat-6829  [000] 1867248.965100: kfree <-free_bprm
                cat-6829  [000] 1867248.965100: <stack trace>

    => free_bprm
    => compat_do_execve
    => sys32_execve
    => ia32_ptregs_common
   [tracing]# echo 0 > options/func_stack_trace
   [tracing]# echo > set_ftrace_filter
```

## Profiling

Ftrace也能做profile。

```
   [tracing]# echo nop > current_tracer
   [tracing]# echo 1 > function_profile_enabled
   [tracing]# cat trace_stat/function0 |head
     Function                               Hit    Time            Avg
     --------                               ---    ----            ---
     schedule                             22943    1994458706 us     86931.03 us
     poll_schedule_timeout                 8683    1429165515 us     164593.5 us
     schedule_hrtimeout_range              8638    1429155793 us     165449.8 us
     sys_poll                             12366    875206110 us     70775.19 us
     do_sys_poll                          12367    875136511 us     70763.84 us
     compat_sys_select                     3395    527531945 us     155384.9 us
     compat_core_sys_select                3395    527503300 us     155376.5 us
     do_select                             3395    527477553 us     155368.9 us
```

没实验成功，以后再看看。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://richardweiyang-2.gitbook.io/kernel-exploring/00-index-2/03-ftrace_usage.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
