ftrace tracers 之 function、function_graph 使用笔记(二)

接之前文章 《ftrace tracers 之 function、function_graph 使用笔记(一)

先从简单的代码流程跟踪使用学起,看下具体如何使用 functionfunction_graph

功能简介:

1、function 跟踪器可以跟踪内核函数的执行情况,可以通过 set_ftrace_filter 显式指定要跟踪的函数。可以用于跟踪内核某个函数被调用的频次,在被调用的情况。

2、function_graphfunction 跟踪器类似,只是function 跟踪器在函数的入口处探测函数,而function_graph跟踪器在函数的入口和出口处跟踪,然后使得其提供了绘制类似于 C 代码源的函数调用图的能力。可以通过 set_graph_function显式指定要生成调用流程图的函数。因此可以用于跟踪内核某个函数内部调用的子函数流程及耗时。

整体架构

基于 ftrace 的内核函数调用跟踪整体架构:
在这里插入图片描述

内核配置:

一般用作产品正式发布的版本,默认tracer 应该是 nop,如果想要使用 其他 tracer 需要打开对应的内核配置宏才行。

比如,今天我们使用到的 functionfunction_graph,需使能如下对应配置内核宏:

CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y

如果配置ok,在系统中会看到类似如下信息:

root:/sys/kernel/tracing # cat available_tracers
function_graph function nop  ...

接下来就可以正常使用 functionfunction_graph 了。

使用说明

1、准备工作

我们主要是为了单个事件或单个函数跟踪,所以排除其他多余的信息干扰。如果是做具体问题分析,则就要根据实际需要进行设置了。

root:/sys/kernel/tracing # echo 0 > tracing_on
root:/sys/kernel/tracing # echo > set_event
root:/sys/kernel/tracing # echo > trace

2、以 sched_wakeup 这个跟踪事件/跟踪点,跟踪函数为例:

root:/sys/kernel/tracing # cat events/sched/sched_wakeup/format
name: sched_wakeup
ID: 87
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 comm[16];    offset:8;       size:16;        signed:0;
        field:pid_t pid;        offset:24;      size:4; signed:1;
        field:int prio; offset:28;      size:4; signed:1;
        field:int success;      offset:32;      size:4; signed:1;
        field:int target_cpu;   offset:36;      size:4; signed:1;

print fmt: "comm=%s pid=%d prio=%d target_cpu=%03d", REC->comm, REC->pid, REC->prio, REC->target_cpu

说明:
1、以上 格式的 sched_wakeup 打印信息,由该跟踪点对应的处理函数 sched_wakeup_handler处理生成。
2、针对 sched_wakeup 进行跟踪的函数为:__traceiter_sched_wakeup

2.1、通过function 跟踪看下进行跟踪 sched_wakeup 事件的函数 __traceiter_sched_wakeup 被调用情况。
root:/sys/kernel/tracing # echo function > current_tracer
root:/sys/kernel/tracing # echo 1 > options/func_stack_trace
root:/sys/kernel/tracing # echo __traceiter_sched_wakeup > set_ftrace_filter
root:/sys/kernel/tracing # cat set_ftrace_filter
__traceiter_sched_wakeup

ftrace 设置过滤函数过程需要一点时间,稍等片刻。然后:

root:/sys/kernel/tracing # echo 1 > tracing_on

因为是休眠/唤醒相关的函数,所以需要人为制造一次待机/唤醒动作,然后才能看到跟踪日志,如:

root:/sys/kernel/tracing # cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 1035/1035   #P:8
#
#                                _-----=> irqs-off
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| /     delay
#           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
#              | |         |   ||||      |         |
     kworker/0:0-14171   [000] .... 78999.634206: lpi_pinctrl_runtime_resume: lpi_pinctrl_runtime_resume: enter
     kworker/0:0-14171   [000] .... 78999.634220: lpi_pinctrl_runtime_resume: lpi_pinctrl_runtime_resume: exit
     ...
     kworker/0:0-14171   [000] .... 78999.634759: swrm_runtime_suspend: swrm_runtime_suspend: pm_runtime: suspend done state: 3
     ...
     kworker/0:0-14171   [000] .... 78999.761684: lpi_pinctrl_runtime_suspend: lpi_pinctrl_runtime_suspend: enter
     kworker/0:0-14171   [000] .... 78999.763192: lpi_pinctrl_runtime_suspend: lpi_pinctrl_runtime_suspend: exit

被调用的地方和过程有很多,以上只提取了一部分信息,可以看到 一次对称的 resume / suspend 过程, 在此过程,__traceiter_sched_wakeup 有被 pinctrl 调用的情况。

2.2、通过function_graph 跟踪 看下进行跟踪 sched_wakeup 事件的函数 __traceiter_sched_wakeup 调用关系情况。

通过function 跟踪看下进行跟踪sched_wakeup 的函数 __traceiter_sched_wakeup 被调用情况。

root:/sys/kernel/tracing # echo > set_ftrace_filter
root:/sys/kernel/tracing # echo function_graph > current_tracer
root:/sys/kernel/tracing # echo 1 > options/funcgraph-tail
root:/sys/kernel/tracing # echo  __traceiter_sched_wakeup > set_graph_function
root:/sys/kernel/tracing # cat set_graph_function
__traceiter_sched_wakeup

注意,使用 echo > set_ftrace_filter 清除已指定的函数是必须要的操作,否则无法进行 function_graph 绘制。使用echo 1 > options/funcgraph-tail 可以增加函数尾部注释。

ftrace 设置过滤函数过程需要一点时间,稍等片刻。同样,使能 tracing_on 之后,需要人为制造一次休眠唤醒,然后 cat 抓取日志:

root:/sys/kernel/tracing # echo 1 > tracing_on
root:/sys/kernel/tracing # cat trace
# tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
------------------------------------------
1) kworker-14181  => kworker-14620
------------------------------------------
1)               |  /* lpi_pinctrl_runtime_suspend: enter */
------------------------------------------
1) kworker-14181  => kworker-14620
------------------------------------------
1)               |  /* lpass_hw_vote_unprepare: core vote clk_id 10a  */
1)               |  /* digital_cdc_rsc_mgr_hw_vote_disable */
1)               |  /* lpi_pinctrl_runtime_suspend: exit */

以上只是部分信息节选,可能函数 __traceiter_sched_wakeup 本身就是 ftrace 进行跟踪 sched_wakeup 这个 event 的,函数本身并没有复杂的调用流程关系,所以我们看到的 function关系、 function_graph关系也都比较简单。

以上相当于使用 ftrace 跟踪了一个 ftrace 的跟踪事件的函数,^_^

下面以一个常规内核函数为例再看下。

3、以常规内核函数 pm_wakeup_ws_event 为例:

3.1、使用function跟踪 pm_wakeup_ws_event
root:/sys/kernel/tracing # echo 0 > tracing_on
root:/sys/kernel/tracing # echo > set_event
root:/sys/kernel/tracing # echo > trace
root:/sys/kernel/tracing # echo > set_graph_function
root:/sys/kernel/tracing # echo function > current_tracer
root:/sys/kernel/tracing # echo 1 > options/func_stack_trace
root:/sys/kernel/tracing # echo pm_wakeup_ws_event > set_ftrace_filter
root:/sys/kernel/tracing # cat set_ftrace_filter
pm_wakeup_ws_event
root:/sys/kernel/tracing # echo 1 > tracing_on

ftrace 设置过滤函数过程需要一点时间,稍等片刻。然后:

root:/sys/kernel/tracing # cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 0/0   #P:8
#
#                                _-----=> irqs-off
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| /     delay
#           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
#              | |         |   ||||      |         |
   ...
   kworker/1:2-16429   [001] .... 127214.479918: lpi_pinctrl_runtime_suspend: lpi_pinctrl_runtime_suspend: enter
   ...
   kworker/1:2-16429   [001] .... 127214.483106: lpi_pinctrl_runtime_suspend: lpi_pinctrl_runtime_suspend: exit
   ...
3.2、使用function_graph跟踪 pm_wakeup_ws_event
root:/sys/kernel/tracing # echo 0 > tracing_on
root:/sys/kernel/tracing # echo > set_event
root:/sys/kernel/tracing # echo > trace
root:/sys/kernel/tracing # echo > set_ftrace_filter
root:/sys/kernel/tracing # echo function_graph > current_tracer
root:/sys/kernel/tracing # echo 1 > options/funcgraph-tail
root:/sys/kernel/tracing # echo  pm_wakeup_ws_event> set_graph_function
root:/sys/kernel/tracing # cat set_graph_function
pm_wakeup_ws_event
root:/sys/kernel/tracing # echo 1 > tracing_on
root:/sys/kernel/tracing # cat trace

ftrace 设置过滤函数过程需要一点时间,稍等片刻。然后:

root:/sys/kernel/tracing # cat trace
root:/sys/kernel/tracing # cat trace| head
# tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
 ------------------------------------------
 1) kworker-14620  =>  HwBinde-4845
 ------------------------------------------
 1)               |  pm_wakeup_ws_event() {
 1)   1.928 us    |    _raw_spin_lock_irqsave();
 1)               |    wakeup_source_activate() {
 1)               |      ktime_get() {
 1)   1.198 us    |        arch_counter_read();
 1)   3.594 us    |      } /* ktime_get */
 1)   6.615 us    |    } /* wakeup_source_activate */
 1)               |    s2idle_wake() {
 1)   1.146 us    |      _raw_spin_lock_irqsave();
 1)   1.145 us    |      _raw_spin_unlock_irqrestore();
 1)   5.469 us    |    } /* s2idle_wake */
 1)               |    wakeup_source_deactivate() {
 1)               |      ktime_get() {
 1)   1.197 us    |        arch_counter_read();
 1)   3.333 us    |      } /* ktime_get */
 1)   1.146 us    |      del_timer();
 1)   7.865 us    |    } /* wakeup_source_deactivate */
 1)   1.146 us    |    _raw_spin_unlock_irqrestore();
 1) + 38.334 us   |  } /* pm_wakeup_ws_event */
 1)               |  pm_wakeup_ws_event() {
 1)   1.562 us    |    _raw_spin_lock_irqsave();
 1)               |    wakeup_source_activate() {
 1)               |      ktime_get() {
 1)   1.198 us    |        arch_counter_read();
 1)   3.386 us    |      } /* ktime_get */
 1)   5.625 us    |    } /* wakeup_source_activate */
 1)               |    s2idle_wake() {
 1)   1.146 us    |      _raw_spin_lock_irqsave();
 1)   1.146 us    |      _raw_spin_unlock_irqrestore();
 1)   5.365 us    |    } /* s2idle_wake */
 1)               |    wakeup_source_deactivate() {
 1)               |      ktime_get() {
 1)   1.146 us    |        arch_counter_read();
 1)   3.281 us    |      } /* ktime_get */
 1)   1.198 us    |      del_timer();
 1)   7.761 us    |    } /* wakeup_source_deactivate */
 1)   1.875 us    |    _raw_spin_unlock_irqrestore();
 1) + 30.156 us   |  } /* pm_wakeup_ws_event */
 ------------------------------------------
root:/sys/kernel/tracing # ps -A| grep 14620
root         14620     2       0      0 worker_thread       0 I [kworker/1:2-events]
3.3 、函数 pm_wakeup_ws_event 原型。
/** drivers/base/power/wakeup.c
 * pm_wakeup_ws_event - Notify the PM core of a wakeup event.
 * @ws: Wakeup source object associated with the event source.与事件源关联的唤醒源对象。
 * @msec: Anticipated event processing time (in milliseconds).预期的事件处理时间(以毫秒为单位)。
 * @hard: If set, abort suspends in progress and wake up from suspend-to-idle.
 *
 * Notify the PM core of a wakeup event whose source is @ws that will take approximately @msec milliseconds to be processed by the kernel.  If @ws is not active, activate it.  If @msec is nonzero, set up the @ws' timer to execute pm_wakeup_timer_fn() in future.
 * 通知 PM 内核有一个唤醒事件,它的源是 @ws,内核处理大约需要 @msec 毫秒。 如果@ws 未激活,请激活它。 如果@msec 不为零,则设置@ws 的计时器以在将来执行 pm_wakeup_timer_fn()。
 *
 * It is safe to call this function from interrupt context. 在中断上下文调用这个函数是安全的。
 */
void pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard)
{
	unsigned long flags;
	unsigned long expires;

	if (!ws)
		return;

	spin_lock_irqsave(&ws->lock, flags);

	wakeup_source_report_event(ws, hard);

	if (!msec) {
		wakeup_source_deactivate(ws);
		goto unlock;
	}

	expires = jiffies + msecs_to_jiffies(msec);
	if (!expires)
		expires = 1;

	if (!ws->timer_expires || time_after(expires, ws->timer_expires)) {
		mod_timer(&ws->timer, expires);
		ws->timer_expires = expires;
	}

 unlock:
	spin_unlock_irqrestore(&ws->lock, flags);
}
EXPORT_SYMBOL_GPL(pm_wakeup_ws_event);

ref:
https://baijiahao.baidu.com/s?id=1727506047428430246&wfr=spider&for=pc
https://support.huaweicloud.com/moredocuments-kunpengdevps/kunpengsys_06_0100_0.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值