目录
橘色:不可中断的睡眠态 (Uninterruptible Sleep - IO Block)
紫色 : 不可中断的睡眠态(Uninterruptible Sleep)
-
什么是 Trace 文件?
Trace 文件是 Android Studio 提供的用于记录应用执行周期的一种工具。它详细记录了应用中各个方法的执行时间、调用栈信息等,有助于开发者发现并解决性能问题。
-
什么是systrace
systrace 是 android 4.1 中新增的性能数据采集和分析工具,它可帮助开发者收集 Android 关键子系统(如 SurfaceFlinger、WindowManagerService、Framework 关键模块、服务、View 系统等)的运行信息,从而帮助开发者更直观的分析系统瓶颈,改进性能。
systrace 允许你监视和跟踪 android 系统的行为,它会告诉你系统都在哪些工作上花费时间、CPU 周期都用在哪里,甚至你可以看到每个线程、进程在指定时间内都在干嘛。它同时还会突出观测到的问题,从垃圾回收到渲染内容都可能是问题对象,甚至提供给你建议的解决方案。
systrace 的功能包括跟踪系统的 I/O 操作、内核工作队列、CPU 负载以及 android 各个子系统的运行状况等。在 Android 平台中,它主要由3部分组成:
-
内核部分:systrace 利用了 Linux Kernel 中的 ftrace 功能,所以如果要使用 systrace 的话,必须开启 kernel 中和 ftrace 相关的模块。
-
数据采集部分:android 定义了一个 Trace 类,应用程序可利用该类把统计信息输出给 ftrace。同时,Android 还有一个 atrace 程序,它可以从 ftrace 中读取统计信息然后交给数据分析工具来处理。
-
数据分析工具:android 提供了一个 systrace.py(python 脚本文件,位于 Android SDK 目录 /external/chromium-trace/catapult/systrace- 7.1以上系统,其内部将调用 atrace 程序)用来配置数据采集的方式(如采集数据的标签、输出文件名等)和收集 ftrace 统计数据并生成一个结果网页文件供用户查看。
从本质上看,systrace 是对 Linux kernel 中 ftrace 的封装,应用程序可以利用 android 提供的 Trace 类来使用 systrace
-
如何导出 Trace 文件
以下是导出 Trace 文件的步骤:
-
启动 Android Studio:打开你的项目,确保你所连接的设备或模拟器已启动。
-
选择 Profiler:在底部工具栏中选择 “Profiler” 选项。
-
开始分析:在 Profiler 界面中,选择应用进程,然后选择 “CPU” 选项。
-
录制 Trace:点击 “Record” 按钮开始录制 CPU 性能数据,进行一系列操作以模拟实际使用场景,然后停止录制。
-
导出 Trace 文件:点击 “Export Trace” 按钮将生成的 Trace 文件保存到本地。
-
原理和基本流程
Systrace是android性能调试优化的常用工具,它可以收集进程的活动信息,如界面布局、UI渲染、binder通信等;也可以收集内核信息,如cpu调度、IO活动、中断等;这些信息会统一时间轴,在Chrome浏览器中显示出来,非常方便工程师性能调试、优化卡顿等工作。
简易的流程图如下,systrace是基于ftrace实现的,而ftrace 是 Linux 内核中的调试跟踪机制。
-
首先systrace指定抓取trace的类别等参数,然后触发手机端的/system/bin/atrace 开启对应文件节点的信息记录,接着atrace会读取 ftrace 的缓存,生成只包含ftrace信息的atrace_raw。
-
Systrace会进一步收集系统的ps、task等信息,这些信息是为了协助解析atrace_raw中的ftrace信息,比如ps信息可以得到进程的名称,而不是难记的pid号。处理后的ftrace信息将和systrace目录下的prefix.html、systrace_trace_viewer.html、suffix.html整合为一体,成为单个的html文件。
-
当浏览systrace信息时,Chrome浏览器借助systrace解析器(通过chrome://tracing访问),解析上面生成的trace.html文件,把其中原始的ftrace信息分门别类,再按照时间轴聚合排列,绘制出不同色块,简洁可观的显示在html页面上。
-
具体实现
Systrace抓取的trace数据,总体上可以分为两类,一类是Java和Native在用户层发生的函数调用,一类是内核态的事件信息。
用户层的函数调用,其实最终事件记录都是同一个文件节点/sys/kernel/debug/tracing/trace_marker。
此节点允许用户层写入字符串,ftrace会记录该写入操作时的时间戳,当用户在上层调用不同函数时,写入不同的调用信息,比如函数进入和退出分别写入,那么ftrace就可以记录跟踪函数的运行时间。
atrace在处理用户层的多种trace类别时,仅仅是激活不同的TAG,如用户选择了Input类别,则激活ATRACE_TAG_INPUT;选中Graphics则激活ATRACE_TAG_GRAPHICS,记录调用的流程都是一样的,最终都是记录到trace_marker。
内核态的事件信息,则不是统一的,需要激活各自对应的事件节点,让ftrace记录下不同事件的tracepoint。例如激活进程调度信息记录,需要激活如下相关节点:
events/sched/sched_switch/enable
events/sched/sched_wakeup/enable
内核在运行时,根据节点的使能状态,会往ftrace缓冲中打点记录事件。
-
启动 systrace
systrace 工具可以在 sdk/platform-tools/ 中找,源码位于 external/chromium-trace 下面
-
使用 AndroidStudio
1. Tools > Android > Monitor 2. 在设备tab中选择需要监听的 android 设备 3. 点击 Systrace
-
直接使用命令行
1. PC 安装 pythone2.7 以上版本
2. kernel 配置 ftrace,默认已打开
3. 连接设备,adb usb debugging options 打开
4. cmd 切换到 android-sdk-windows/sdk/platform-tool/systrace
5. 输入命令 python systrace.py + 相关参数
6. 在 chrome 地址栏输入"chrome:tracing"
点击 load 加载生成的 trace.html 文件
-
命令格式:
切换systrce.py文件所在的目录,然后执行如下命格式:
python systrace.py [options] [category1] [category2] ... [categoryN]
option取值:
option | 说明 |
-a | 后跟应用包名,指定抓取的应用报名 |
-o | 后跟文件路径,说明导出到哪个路径,文件名是什么 |
-t N, –time=N | 抓取时长,默认是5s |
-b N, -buf-size=N | buffer的大小(单位:KB),用于限制trace总大小,默认无上限,注意这里限制小了会导致trace抓不全 |
-from-file=<FROM_FILE> | 如果是用atrace直接在shell命令环境中抓取的atrace文件,则需要用这个选项,加上-o <FILE_PATH>来转换成.html后缀的文件,然后用chrome浏览chrome://tracing/去浏览分析trace |
-l, --list-categories | 查看所有可用的category(可抓取的trace维度,比如:am、wm、view、gfx等等) |
category取值:
category | 说明 |
gfx | 图形信息,加上能看到主线程的doFrame和RenderThread的drawFrame过程 |
sched | cpu调度信息 |
view | 视图相关,加上这个就能看到View的测量,布局文件的inflate过程 |
am | Activity Manager服务,加上这个就能看到Application、Activity的启动过过程了 |
wm | 窗口管理服务 |
app | 应用信息,实测好多设备都不支持这个category了 |
webview | WebView相关信息 |
-
systrace报告怎么看?
网站:
chrome://tracing/ 或edge://traceing
-
线程状态信息
-
绿色 : 运行中(Running)
-
蓝色:Runanble状态
-
白色:Sleeping状态
线程没有工作要做,可能是因为线程在互斥锁上被阻塞。 作用:这里一般是在等事件驱动
-
橘色:不可中断的睡眠态 (Uninterruptible Sleep - IO Block)
线程在I / O上被阻塞或等待磁盘操作完成,一般底线都会标识出此时的 callsite :wait_on_page_locked_killable
作用:这个一般是标示 io 操作慢,如果有大量的橘色不可中断的睡眠态出现,那么一般是由于进入了低内存状态,申请内存的时候触发 pageFault, linux 系统的 page cache 链表中有时会出现一些还没准备好的 page(即还没把磁盘中的内容完全地读出来) , 而正好此时用户在访问这个 page 时就会出现 wait_on_page_locked_killable 阻塞了. 只有系统当 io 操作很繁忙时, 每笔的 io 操作都需要等待排队时, 极其容易出现且阻塞的时间往往会比较长.
比如com.miui.notification:remote进程有这样的状态:
-
紫色 : 不可中断的睡眠态(Uninterruptible Sleep)
线程在另一个内核操作(通常是内存管理)上被阻塞。 作用:一般是陷入了内核态,有些情况下是正常的,有些情况下是不正常的,需要按照具体的情况去分析
-
线程唤醒信息:
6360线程处于Runanble状态时,蓝色的线程状态区域,是被6456线程唤醒,继续看这个线程是干什么的。 虽然这个线程只能看到tid=6456,但是根据硬件加速打开状态,并且这个线程是紧接着doFrame做drawFrame操作的,可以推断这个是RenderThread线程。
并不是每个Runnable状态的时间段都能看到唤醒线程,为什么? 推测并不一定是等待同步锁对象导致的Runnable状态,也可能是CPU时间片没分配到。
-
帧率信息
帧率信息主要看主线程的doFrame和RenderThread线程drawFrame的trace进行分析。
每一帧就是一个F圆圈,代表调用Choreographer(编舞者)的doFrame()方法耗时
-
圆圈绿色代表Frame渲染流畅
-
黄色和红色代表渲染超过16.6ms,红色的更严重。
-
perfetto分析trace上是没有⭕️的,这时候可以选中一段时间,然后看看doFrame+drawFrame执行了多少次,计算出平均帧率分析卡顿程度
应用启动耗时分析
分析应用启动主要看trace上以下几个阶段: 应用启动几大核心阶段:
-
Sytrace 转换成html 的方法
使用 systrace.py 脚本既可以将手机抓取的Systrace 转换成Html 文件。
1.systrace.py 文件目录如下:
sdk\platform-tools\systrace\systrace.py
2.systrace.py 转换命令如下:
systrace.py --from-file=input.ctrace -o output.html