Skip to main content
 首页 » 操作系统

Linux tracer ftrace笔记(5)—— 使用笔记汇总

2022年07月19日54telwanggs

一、抓Trace的网址

1. 4个抓trace的网址

(1) chrome://tracing/ 
(2) https://ui.perfetto.dev/v18.0-d996f9e27/assets/catapult_trace_viewer.html 
(3) https://ui.perfetto.dev/#!/ 
(4) https://ui.perfetto.dev/#!/viewer

1和2的区别是2能打开更多的trace,但是点击 Process<pid> 栏里的第一级trace显示的是相对时间,但是1显示的是绝对时间,这个绝对时间是可以和内核Log前面的时间是可以对应起来的。

2. systrace原始工具抓trace的方法:

# cd /sdk/platform-tools/systrace 
# python systrace.py [options][category1][category2]...[categoryN] 
options                            描述 
-o <FILE>                        输出的目标文件 
-t N, -time=N                    执行时间,默认是5s 
-k <KFUNCS>, -ktrace=<KFUNCS>    追踪kernel函数,用逗号分割 
-a <APP_NAMW>, -app <APP_NAMW>    追踪应用包名,用逗号分割 
--from-file=<FROM_FILE>            从文件中创建互动的systrace 
-e <DEVICE_SERIAL>, --serial=<DEVICE_SERIAL>    指定设备 
-l, --list-categories            列举可用的tags

3. perfetto对应的仓库为:source/{vnd/sys}/external/perfetto 可以对显示格式进行定制化。

二、sched_waking & sched_wakeup

1. InputDispatcher选核案例

(1) 在旧的解析网址中 InputDispatcher 线程那里找到绝对时间,然后以.txt格式打开trace,找到案发现场:

InputReader 1964-1964    (   1576) [004] d..5 72113.123884: sched_waking: comm=InputDispatcher pid=1963 prio=112 target_cpu=006 
InputReader 1964-1964    (   1576) [004] d..6 72113.123904: sched_wakeup: comm=InputDispatcher pid=1963 prio=112 target_cpu=006 
OAdOutputTh 3908-3908    (    884) [004] d..2 72113.132359: sched_switch: prev_comm=OAdOutputTh prev_pid=3908 prev_prio=101 prev_state=S ==> next_comm=InputDispatcher next_pid=1963 next_prio=112

(2) 说明:在CPU4上被别的线程唤醒的,就显示在CPU4唤醒,但是并不是目标CPU选择在CPU4上了。

(3) 老版Trace上解析这段runnable是8.455ms,而新版trace解析是8.475ms。说明旧版的Trace解析网址计算的runnable时间是:sched_switch - sched_wakeup 的时间,新版本的trace解析网址是 sched_switch - sched_waking 的时间。

72113.13236 - 72113.12388 = 8.475ms 
72113.13236 - 72113.12390 = 8.455ms

(4) trace详细解读

//这是 try_to_wake_up 函数中为任务选核之前打印的trace,含义为在CPU4上唤醒,被唤醒的名字、pid、优先级等,任务之前是运行在CPU6上的 
InputReader 1964-1964    (   1576) [004] d..5 72113.123884: sched_waking: comm=InputDispatcher pid=1963 prio=112 target_cpu=006 
//这是 try_to_wake_up 函数中为任务选核之后打印的trace,在CPU4上继续执行唤醒流程,唤醒后选核又选在了CPU6上 
InputReader 1964-1964    (   1576) [004] d..6 72113.123904: sched_wakeup: comm=InputDispatcher pid=1963 prio=112 target_cpu=006 
//又运行在CPU4上(CPU6上无法得到运行,因为都是RT线程干不过) 
OAdOutputTh 3908-3908    (    884) [004] d..2 72113.132359: sched_switch: prev_comm=OAdOutputTh prev_pid=3908 prev_prio=101 prev_state=S ==> next_comm=InputDispatcher next_pid=1963 next_prio=112

(5) 代码分析

try_to_wake_up //core.c 
    trace_sched_waking(p); //这个时候还没有选核,trace打印的cpu还是任务上次运行的cpu. 
    p->state = TASK_WAKING; 
    cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags); //唤醒选核 
    if (task_cpu(p) != cpu) { //选的核不是之前运行的CPU,要迁移 
        ... 
        set_task_cpu(p, cpu); //这里将 p->cpu 指向新选出的cpu 
    } 
    ttwu_queue(p, cpu, wake_flags);  
        ttwu_do_activate(rq, p, wake_flags, &rf); 
            activate_task(rq, p, en_flags); //将任务放到新选出的cpu的rq上 
                ttwu_do_wakeup(rq, p, wake_flags, rf); 
                    check_preempt_curr(rq, p, wake_flags); //触发一次抢占 
                    p->state = TASK_RUNNING; //虽然设置为running,但是此时还是runnable状态的 
                    trace_sched_wakeup(p); //此时打印的就是选核的目标CPU了。

三、杂项

1. 区分前后台

检索 OomAdjuster, 这一列显示的"setProcessGroup com.tencent.mm to 5 " 5就是TOP-APP,就是前台。上层TOP-APP定义在 android/frameworks/base/core/java/android/os/Process.java:public static final int THREAD_GROUP_TOP_APP = 5;
kernel中的TOP-APP分组柳杰定义的是4,定义为#define SA_CGROUP_TOP_APP 4,其打印发现的,MTK和Qcom都是。

第二个区分前后台的方法是在CPU Info中看其优先级,一般应用在前台优先级会设置为110,在后台设置为120。

/dev/cpuset/top-app # echo <PID> > cgroup.procs 上层设置为前台的方法应该是这样的,echo进去几个就有几个在前台。可以使用新解析工具打开trace,然后在CpuInfo信息中检索OomAdjuster,可同时看前台应用主线程的prio120->110的切换时间来对照着看。

2. sched_switch 中的R+中的加号表示传参preempt=1,preempt参数来自:

__schedule(bool preempt) 
    trace_sched_switch(preempt, prev, next); //在trace打印prev_state=R+中的这个R+的加号表示传参preempt=1 
 
sched_switch: prev_comm=kswapd0:0 prev_pid=171 prev_prio=120 prev_state=R+ ==> next_comm=kworker/5:1 next_pid=21307 next_prio=120

3. 下面两个作用相同,但使用场景却不同,前者设置方便,但是后者更适合于在抓trace前添加trace_event的时候使用,因为前者echo后可能覆盖,而后者不会。

/sys/kernel/tracing # echo sched_switch > set_event 
/sys/kernel/tracing # echo 1 > ./events/sched/sched_switch/enable

4. Perfetto trace上Ctrl+F检索startup,可以看到"Android App Startups"条目,可以看到启动的app,可以用来区分是启动动画还是退出动画。

5. 可以参考 process_one_work() 来实现对异步函数的trace的解析和显示

process_one_work() 
    trace_workqueue_execute_start(work); 
    worker->current_func(work); //被包裹着 
    trace_workqueue_execute_end(work); 
 
kworker/u24:3-13447   (  13447) [000] .... 714031.881139: workqueue_execute_start: work struct 0000000025ceb863: function __typeid__ZTSFvP11work_structE_global_addr 
... 
kworker/u24:3-13447   (  13447) [000] .... 714031.884821: workqueue_execute_end: work struct 0000000025ceb863 
 
//以.txt格式打开.html的trace,检索"work struct"得到如下格式控制,应该需要满足格式才行: 
const workqueueExecuteStartRE=/work struct (.+): function (\S+)/;const workqueueExecuteEndRE=/work struct (.+)/;

6. 可以通过"{"和"}"快捷键实现对binder和async binder的跳转。


本文参考链接:https://www.cnblogs.com/hellokitty2/p/16025836.html