当我们说 流畅度 的时候,我们说的是什么?不同的人对流畅性(卡顿掉帧)有不同的理解,对卡顿阈值也有不同的感知,所以有必要在开始这个系列文章之前,先把涉及到的内容说清楚,防止出现不同的理解,也方便大家带着问题去看这几篇问题,下面是一些基本的说明
Systrace 流畅性实战目前包括下面三篇
Systrace (Perfetto) 工具的基本使用如果还不是很熟悉,那么需要优先去补一下 [Systrace 基础知识系列] [4]
Systrace 作为分析卡顿问题的第一手工具,给开发者提供了一个从手机全局角度去看问题的方式,通过 Systrace 工具进行分析,我们可以大致确定卡顿问题的原因:是系统导致的还是应用自身的问题
当然 Systrace 作为一个工具,再进行深入的分析的时候就会有点力不从心,需要配合 TraceView + 源码来进一步定位和解决问题,最后再使用 Systrace 进行验证
所以本文更多地是讲如何发现和分析卡顿问题,至于如何解决,就需要后续自己寻找合适的解决方案了,比如对比竞品的 Systrace 表现、优化代码逻辑、优化系统调度、优化布局等
个人在使用小米 10 Pro 的时候,在桌面滑动这个最常用的场景里面,总会有一种卡顿的感觉,10 Pro 是 90Hz 的屏幕,FPS 也是 90,所以一旦出现卡顿,就会有很明显的感觉(个人对这个也比较敏感)。之前没怎么关注,在升级 12.5 之后,这个问题还是没有解决,所以我想看看到底是怎么回事
抓了 Systrace 之后分析发现,这个卡顿场景是一个非常好的案例,所以把这个例子拿出来作为流畅度的一个实战分享
建议大家下载附件中的 Systrace,对照文章食用最佳
- 鉴于卡顿问题的影响因素比较多,所以在开始之前,我把本次分析所涉及的硬件、软件版本沟通清楚,如果后续此场景有优化,此文章也不会进行修改,以文章附件中的 Systrace 为准
- 硬件:小米 10 Pro
- 软件:MIUI 12.5.3 稳定版
- 小米桌面版本:RELEASE-4.21.11.2922-03151646
分析卡顿问题,我们一般的流程如下
按照这个流程分析之后,需要再反过来看各个进程,把各个线索联系起来,推断最有可能的原因
这次抓的 Systrace 我只滑动了一次,所以比较好定位,滑动的 input 事件由一个 Input Down 事件 + 若干个 Input Move 事件 + 一个 Input Up 事件组成
在 Systrace 中,SystemServer 中的 InputDispatcher 和 InputReader 线程都有体现,我们这里主要看在 App 主线程中的体现
如上图,App 主线程上的 deliverInputEvent 标识了应用处理 input 事件的过程,input up 之后,就进入了 Fling 阶段,这部分的基础知识可以查看下面这两篇文章
由于这次卡顿主要是松手之后才出现的,所以我们主要看 Input Up 之后的这段
主线程上面的 Frame 有颜色进行标注,一般有绿、黄、红三种颜色,上面的 Systrace 里面,没有红色的帧,只有绿色和黄色。那么黄色就一定是卡顿么?红色就一定是卡顿么?其实不一定,单单通过主线程,我们并不能确定是否卡顿,这个在下面会讲
从主线程我们没法确定是否发生了卡顿,我们找出了三个可疑的点,接下来我们看一下 RenderThread
放大第一个可疑点,可以看到,这一帧总耗时在 19ms, RenderThread 耗时 16ms,且 RenderThread 的 cpu 状态都是 running(绿色),那么这一帧这么耗时的原因大概率是下面两个原因导致的:
由于只是可疑点,所以我们先不去看 cpu 相关的,先查看 SurfaceFlinger 进程,确定这里有卡顿发生
对于 Systrace 中 SurfaceFlinger 部分解读不熟悉的可以先预习一下这篇文章 [Android Systrace 基础知识(5) - SurfaceFlinger 解读] [7]
这里我们主要看两个点
判断是否卡顿的标准如下
1 . 如果 SurfaceFlinger 主线程没有合成任务,而且 App 在这一个 Vsync 周期(vsync-app)进行了正常的工作,但是对应的 App 的 BufferQueue 里面没有可用的 Buffer,那么说明这一帧卡了 — 卡顿出现这种情况如下图所示(也是上图中第一个疑点所在的位置)
2 . 如果 SurfaceFlinger 进行了合成,而且 App 在这一个 Vsync 周期(vsync-app)进行了正常的工作,但是对应的 App 的 BufferQueue 里面没有可用的 Buffer,那么这一帧也是卡了,之所以 SurfaceFlinger 会正常合成,是因为有其他的 App 提供了可用来合成的 Buffer — 卡顿出现这种情况如下图所示(也在附件的 Systrace 里面)
3 . 如果 SurfaceFlinger 进行了合成,而且 App 在这一个 Vsync 周期(vsync-app)进行了正常的工作,而且对应的 App 的 BufferQueue 里面有可用的 Buffer,那么这一帧就会正常合成,此时没有卡顿出现 — 正常情况正常情况如下,作为对比还是贴上来方便大家对比
回到本例的第一个疑点的地方,我们通过 SurfaceFlinger 端的分析,发现这一帧确实是掉了,原因是 App 没有准备好可用的 Buffer 供 SurfaceFlinger 来合成,那么接下来就需要看为什么这一帧 App 没有可用的 Buffer 给到 SurfaceFlinger
上面我们分析这一帧所对应的 MainThread + RenderThread 耗时在 19ms,且 RenderThread 耗时就在 16ms,那么我们来看 RenderThread 的情况
出现这种情况主要是有下面两个原因
但是桌面滑动这个场景,负载并不高,且松手之后并没有多余的操作,View 更新之类的,本身耗时比前一帧多了将近 3 倍,可以推断不是自身负载加重导致的耗时
那么就需要看此时的 RenderThread 的 cpu 情况:
既然在 Running 情况,我们就去 CPU Info 区域查看这一段时间这个任务的调度情况
查看 CPU (Kernel 区域,这部分的基础知识可以查看 [Android Systrace 基础知识 - CPU Info 解读] [8] 和 [Android Systrace 基础知识 -- 分析 Systrace 预备知识] [9])这两篇文章
回到这个案例,我们可以看到 App 对应的 RenderThread 大部分跑在 cpu 2 和 cpu 0 上,也就是小核上(这个机型是高通骁龙 865,有四个小核+3 个大核+1 个超大核)
其此时对应的频率也已经达到了小核的最高频率(1.8Ghz)
且此时没有 cpu boost 介入
那么这里我们猜想,之所以这一帧 RenderThread 如此耗时,是因为小核就算跑满了,也没法在这么短的时间内完成任务
那么接下来要验证我们的猜想,需要进行下面两个步骤
在用同样的流程分析了后面几个掉帧之后,我们发现
至此,这一次的卡顿分析我们就找到了原因:RenderThread 掉到了小核
至于 RenderThread 的任务为啥跑着跑着就掉到了小核,这个跟调度器是有关系的,大小核直接的调度跟任务的负载有关系,任务从大核掉到小核、或者从小核迁移到大核,调度器这边都是有参数和算法来控制的,所以后续的优化可能需要从这方面去入手
在 [Triple-Buffer-的作用] [10] 这篇文章,讲到了 Triple Buffer 几个作用
那么在桌面滑动卡顿这个案例里面,Triple Buffer 发挥了什么作用呢?结论是:有的场景没有发挥作用,反而有副作用,导致卡顿现象更明显,下面是分析流程
可以看文章中 Triple Buffer 缓解掉帧 的原理:
在分析小米桌面滑动卡顿这个案例的时候,我发现在有一个问题,小米桌面对应的 App 的 BufferQueue,有时候会出现可用 Buffer 从 2 →0 ,这相当于直接把一个 Buffer 给抛弃掉了,如下图所示
这样的话,如果在后续的桌面 Fling 过程中,又出现了一次 RenderThread 耗时,那么就会以卡顿的形式直接体现出来,这样也就失去了 Triple Buffer 的缓解掉帧的作用了
下图可以看到,由于丢弃了一个 Buffer,导致再一次出现 RenderThread 耗时的时候,表现依然是无 Buffer 可用,出现掉帧
仔细看前面这段丢弃 Buffer 的逻辑,也很容易想到,这里本身就已经丢了一帧了,还把这个耗时帧所对应的 Buffer 给丢弃了(也可能丢弃的是第二帧),不管是哪种情况,滑动时候的每一帧的内容都是计算好的(参考 List Fling 的计算过程),如果把其中一帧丢了,再加上本身 SurfaceFlinger 卡的那一下,卡顿感会非常明显
举个例子,以滑动为例,offset 指的是离屏幕一个左边的距离
2→4→6→8→10→12
2→4→6→6→8→10→12
(假设 计算 8 的这一帧超时了,就会看到两个 6 ,这是掉了一帧的情况)2→4→6→6→10→12
,直接从 6 跳到了 10,相当于卡了 1 次,步子扯大了一次,感官上会觉得卡+跳跃附件已经上传到了 Github 上,可以自行下载:https://github.com/Gracker/SystraceForBlog/tree/master/Android_Systrace_Smooth_In_Action[14]
[1]Systrace 流畅性实战 1 :了解卡顿原理: https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-1/
[2]Systrace 流畅性实战 2 :案例分析: MIUI 桌面滑动卡顿分析: https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-2/
[3]Systrace 流畅性实战 3 :卡顿分析过程中的一些疑问: https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-3/
[4]Systrace 基础知识系列: https://www.androidperformance.com/2019/05/26/Android_Systrace_0/
[5]https://www.androidperformance.com/2019/11/04/Android-Systrace-Input/: https://www.androidperformance.com/2019/11/04/Android-Systrace-Input/
[6]https://www.androidperformance.com/2020/08/20/weibo-imageload-opt-on-huawei/: https://www.androidperformance.com/2020/08/20/weibo-imageload-opt-on-huawei/
[7]https://www.androidperformance.com/2020/02/14/Android-Systrace-SurfaceFlinger/: https://www.androidperformance.com/2020/02/14/Android-Systrace-SurfaceFlinger/
[8]Android Systrace 基础知识 - CPU Info 解读: https://www.androidperformance.com/2019/12/21/Android-Systrace-CPU
[9]Android Systrace 基础知识 -- 分析 Systrace 预备知识: https://www.androidperformance.com/2019/07/23/Android-Systrace-Pre/
[10]Triple-Buffer-的作用: https://www.androidperformance.com/2019/12/15/Android-Systrace-Triple-Buffer/#Triple-Buffer-%E7%9A%84%E4%BD%9C%E7%94%A8
[11]Systrace 流畅性实战 1 :了解卡顿原理: https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-1/
[12]Systrace 流畅性实战 2 :案例分析: MIUI 桌面滑动卡顿分析: https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-2/
[13]Systrace 流畅性实战 3 :卡顿分析过程中的一些疑问: https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-3/
[14]https://github.com/Gracker/SystraceForBlog/tree/master/Android_Systrace_Smooth_In_Action: https://github.com/Gracker/SystraceForBlog/tree/master/Android_Systrace_Smooth_In_Action
[15]关于我: https://www.androidperformance.com/about/
[16]博客内容导航: https://androidperformance.com/2019/12/01/BlogMap/
[17]优秀博客文章记录 - Android 性能优化必知必会: https://androidperformance.com/2018/05/07/Android-performance-optimization-skills-and-tools/
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8