当前位置: 首页 > article >正文

卡顿丢帧分析

卡顿原理

流畅度:fps。比如 60 fps,意思是每秒画面更新 60 次;120 fps,意思是每秒画面更新 120 次。如果 120 fps 的情况下,每秒画面只更新了 110 次(连续动画的过程),这种情况我们就称之为掉帧,其表现就是卡顿,fps 对应的也从 120 降低到了 110。同时掉帧的原因非常多,有 APP 本身的问题,有系统原因导致卡顿的,也有硬件层的、整机卡的。

方法论

流畅度相关工作内容概述

系统开发的过程中,由很多引起Android卡顿的原因,但是用户和测试感受最直观的是正在使用的应用掉帧和不流畅。由于测试和用户没有办法直接确定卡顿的原因,所以一般会直接将Bug提到我们这里,所有我们的角色更像是一个卡顿问题接口人,负责分析引起卡顿的原因,再把Bug分配给对应的模块负责人去解决,如框架\App\多媒体\Display\BSP等。

所以说直接由我们来解决的问题并不是很多,我们更多的时候是通过专门的分析工具,结合源码来定位和分析问题,最多使用的工具如下:

  1. Systrace\strace\ftrace : 从整个系统的层面来看问题的大致原因。

  2. MethodTrace : 可以从进程的角度 , 以详细调用栈的形式来显示。

  3. Android Studio 的 Profile 工具。

  4. MAT : 用来分析内存问题。

  5. Log : LogReport 抓取或者录制的 Log , 里面包含大量的信息 , 包括各种常规 Log (Main Log , System Log , Event Log , Kernel Log , Crash Log 等) , 也包含了厂商自己加的一些 Log ( Power Log , Performance Log 等) , 也包含事故发生时候的截图 \ 录制的视频等。

  6. 复现视频。

  7. 本地复现。

确定卡顿的根本原因,这需要对Android App开发\Android Framework知识\Display知识\Linux Kernel知识有一定的了解,知道基本的工作流畅,并能熟练使用对应的工具,区分不同的场景,迅速找到问题的原因,然后和相关模块的负责人一起讨论优化。对于一些系统全局性的方案则需要与对应的模块负责人一起分析和解决,必须要的时候我们也会开发一些Feature来解决问题。

性能问题分析的工具和套路

应用卡顿问题的原因比较多,在数据埋点还没有完善的情况下,更多的以来Systrace来从全局的角度来分析卡顿的具体原因:

  1. Systrace分析

    1. 首先确认卡顿的App。

    2. 通过App和主线程和SurfaceFlinger的主线程信息可以确定卡顿的现场。

    3. 分析 Systrace , Systrace 的分析需要一定的知识储备 : 需要知道 Systrace 每一个模块展示的内容是如何与用户感受到的内容相对应的 ; 需要知道 Systrace 上各个模块的交互式如何展示的 ; 需要知道 Binder 调用信息 ; 需要会看 Kernel 信息。

      • 如果是App主线程耗时,则分析App主线程的原因。

      • 如果是System的问题,则需要分析System_Server\SurfaceFlinger\HWC\CRTE\CPU等。

  2. TraceView + 源码分析

    1. 使用Systrace确定原因后,可以是会用TraceView结合源码查看对应的代码逻辑,Android Studio的Profile工具可以以线程为单位,进行Method的Profile,可以打出非常详细的函数调用栈,并可以与Systrace对应。

    2. 源码分析可以使用 Android Studio 进行断点调试 App 或者 Framework , 观察 Debug 信息是否与预期相符。

  3. 很多问题也需要借助 Log 工具抓上来的 Log 进行分析 , Log 分析 Log 里面一些比较重要的点 (一般从 Log 里面很难确定卡顿的原因, 但是可以结合 Systrace 做一定的辅助分析)。

    1. 截图:确定卡顿发生的时间点\卡顿的界面。

    2. Dumpsys meminfo信息。

    3. Dumpsys cpuinfo信息。

    4. “Slow dispatch” 和 “Slow delivery” Log 信息。

    5. 卡顿发生的一段时间内的 EventLog , 还原卡顿时候用户的操作。

  4. 本地尝试复现

    1. 可以录高数录像,观察细节,如果必现,可以让测试这边提供录像。

    2. 过滤Log,找到卡顿时候的异常Log。

    3. 多抓几份Systrace,有助于确定原因。

  5. 可以让测试提供 LogReport 中没有的一些信息, 来分析当时用户的手机的整体的状态。

adb shell dumpsys activity oom
adb shell dumpsys meminfo
adb shell cat /proc/buddyinfo
adb shell dumpsys cpuinfo
adb shell dumpsys input
adb shell dumpsys window

通过性能数据数据分析

由于用户反馈的不确定性 , 和内部测试的不完备性 , 通过系统或者 App 的性能埋点数据来做分析 , 是改进系统的一个好的方法。 一方面不用用户主动参与 , 一方面有大量的数据可以来做分析 , 看趋势。目前国内各大手机厂商和 App 厂商基本都有自己的 APM 平台 , 负责监控 App 或者系统的监控程度 , 来做对应的优化方案 , 比如腾讯的 Matrix 平台已经监控了下面这些内容 , 其他的 App 厂商可以直接接入。

手机厂商由于有代码权限 , 所以可以采集到更多的数据 , 比如 Kernel 相关的数据 : cpu 负载 \ io 负载 \ Memory 负载 \ FSync \ 异常监控 \ 温度监控 \ 存储大小监控 等 , 每一个大项又都有几十个小项。所以可以监控的数据会非常多 , 遇到问题也可以从多个技术指标去分析。这就需要在这方面经验非常丰富的团队 , 去定义这些监控指标 , 确定最终要收集那些信息 , 收集上来的数据如何去分析等。目前能力比较强的手机厂商 , 都在底层各个模块 , 结合硬件做优化 , 因为归根结底都是资源的分配 ; 而一些研发实力不是很强的厂商 , 则重点还是围绕在根据场景分配资源。

总结

这里简单概述了一下流畅性问题的一般分析思路和分析工具 , 而且由于我的方向主要在 Framework 和 App , 所以很多东西都是从上层的角度来说的 , 想必 Kernel 优化团队会有更好的角度和分析。

展望一下,这里想把手机厂商分为三类:

  1. 一类是苹果,自己研发芯片和核心元件,有自己的OS和生态;

  2. 二类是三星、华为,自己研发芯片和核心元件(当然华为和三星还是有所区别),共享 Android OS 和生态,当然三星在本土化这一块做的是不如华为和其他 Top 厂商的;

  3. 三类是其他 Android 手机厂商,芯片和核心元件来自于不同供应商,共享 Android OS和生态。

从技术层面看:

  1. 苹果始终会是在性能的第一阵营,可以顺利推行从硬件到 OS 到 APP 级别的任何性能保障方案;

  2. 三星、华为属于第二阵营,可以实现芯片-OS层面的整合优化;

  3. 其他 Top Android 手机厂商差距不会太大,他们有多个不同的 SoC 供应商,方案有差异,非常芯片底层的地方,往往不会去涉及,更多是做纯软件层面的策略性的优化,有价值但是不容易形成壁垒,注意这个不容易形成壁垒指的是在 top 厂商中间,一些小的厂商往往还是心有余而力不足。不过还是很期待看到有更多的突破出现。

系统篇

主要列举一些由 Android 平台自身原因导致的卡顿问题。各大国内 Android 厂商的产品由于硬件性能有高有低 , 功能实现各有差异 , 团队技术能力各有千秋 , 所以其系统的质量也有高有低 , 这里我们就来列举一下 , 由于系统的硬件和软件原因导致的性能问题。

Android 手机使用中的卡顿问题 , 一般来说手机厂商和 App 开发商都会非常重视 , 所以不管是手机厂商还是 App 开发者 , 都会对卡顿问题非常重视 , 内部一般也会有专门的基础组或者优化组来进行优化。目前市面上有一些非常棒的第三方性能监控工具 , 比如腾讯的 Matrix ; 手机厂商一般也会有自己的性能监控方案 , 由于可以修改源码和避免权限问题 , 所以手机厂商可以拿到更多的数据 , 分析起来也会更方便一些。

说回流畅度 , 其实就是操作过程中的丢帧 , 本来一秒中画面需要更新 60 帧,但是如果这期间只更新了 55 帧 , 那么在用户看来就是丢帧了 , 主观感觉就是卡了 , 尤其是帧率波动 , 用户的感知会更明显。引起丢帧的原因非常多, 有硬件层面的 , 有软件层面的 , 也有 App 自身的问题。

Android平台性能导致的性能案例

下面会列出来一些实际的卡顿案例 , 这些导致卡顿的原因都是由于 Android 系统平台的一些问题导致的 , 有些问题在开发阶段就会暴露出来 , 这一类通常会在发给用户之前就解决掉 ; 有些问题是用户在长时间使用之后才会暴露出来 , 这一类问题最多 , 但是也比较难以解决 ; 还有一些问题 , 只有非常特殊的场景或者特殊的硬件才会暴露出来。

这些实际的案例 , 很多都可以在 Systrace 上看出来 , 所以我的很多贴图都是 Systrace 上实际被发现的问题 , Systrace 从系统全局的角度 , 来展示当前系统的运行状况 , 通常被用来 Debug Android 性能问题。

SurfaceFlinger主线程耗时

SurfaceFlinger 负责 Surface 的合成 , 一旦 SurfaceFlinger 主线程调用超时 , 就会产生掉帧。SurfaceFlinger 主线程耗时会也会导致 hwc service 和 crtc 不能及时完成, 也会阻塞应用的 binder 调用, 如 dequeueBuffer \ queueBuffer 等。

在Android系统中,SurfaceFlinger、HWC(Hardware Composer)和CRTC(Cathode Ray Tube Controller)都是与图形渲染和显示相关的重要组件。以下是它们的简介和相关概念的解释:

1. SurfaceFlinger

SurfaceFlinger是Android的合成器,它负责将多个应用程序的窗口合成成一个最终的图像,然后发送到显示硬件。它的主线程负责处理各种图形请求,包括接收来自应用的缓冲区请求、合成这些缓冲区以及进行屏幕更新。

2. HWC(Hardware Composer)

HWC是一层中介,负责将SurfaceFlinger合成的图像传递给显示硬件。它可以决定哪些图层需要由GPU处理,哪些可以直接由显示硬件处理,以提高性能和减少功耗。HWC的存在使得在显示过程中,CPU和GPU可以更高效地使用,并减少渲染延迟。

3. CRTC(Cathode Ray Tube Controller)

CRTC是显示控制器的一个组件,负责控制显示设备的输出信号。虽然名字源于显像管,但现代显示设备(如LCD或OLED)也用类似的概念。CRTC负责管理显示的帧率和同步,确保图像正确呈现。

4. dequeueBuffer 和 queueBuffer

dequeueBuffer:这是一个调用,用于从缓冲区队列中获取一个可用的缓冲区。应用程序通过这个调用来请求一个空闲的图像缓冲区,以便准备下一帧的图像。

queueBuffer:这个调用则是将准备好的缓冲区返回给SurfaceFlinger,表示该缓冲区已填充图像数据,可以被合成和显示。

主线程耗时的影响

SurfaceFlinger主线程耗时:如果SurfaceFlinger的主线程因为某种原因(如处理复杂的合成任务、等待资源等)而耗时过长,那么它就会阻塞对HWC和CRTC的调用。这意味着:

- HWC可能无法及时处理接收到的图层数据,导致显示延迟。

- CRTC也可能无法及时更新显示内容,进一步增加延迟。

- 应用的Binder调用(如dequeueBuffer和queueBuffer)可能会被阻塞,从而导致应用的渲染效率降低,用户体验变差。

总结

在Android的图形架构中,SurfaceFlinger、HWC和CRTC之间的协调非常重要。如果SurfaceFlinger的主线程耗时过长,会影响整体的图形渲染性能和响应速度,进而影响应用的运行效率和用户体验。

下图中的 SurfaceFlinger 主线程在后半部分明显超时:

SurfaceFlinger 主线程处理不及时导致应用卡顿(第一帧卡顿,后续都为黄帧)。

屏下光感截图导致SurfaceFlinger渲染不及时

有的 Android 机型使用了屏下光感 , 屏下光感的实现方法也会影响 SurfaceFlinger 主线程的运行。屏下指纹需要频繁截图 , 来区分光线和屏幕的变化 , 进行对应的亮度变化, 但是其主线程截图的方法会导致 SurfaceFlinger 主线程被截图操作所耽误, 从而导致卡顿。

HWC Service执行耗时

hwc Service 耗时也会导致 SurfaceFlinger 下一帧不会做合成操作, 导致应用的 dequeueBuffer 和 setTransationState 方法被阻塞, 导致卡顿。如下图, 可以看到 SurfaceFlinger 的掉帧情况, Binder 的阻塞情况 和 CRTC 的耗时情况。

hwc 耗时。

crtc 等待 hwc。

CRTC执行耗时

crtc 执行耗时的结果就是 SurfaceFlinger 下一帧不会做合成操作, 导致应用的 dequeueBuffer 和 setTransationState 方法被阻塞, 导致卡顿。如下图, 可以看到 SurfaceFlinger 的掉帧情况, Binder 的阻塞情况 和 CRTC 的耗时情况。

CPU调度问题
重要任务跑在小核性能不足导致卡顿

如下图,RenderThread跑到了小核,导致这一帧执行时间过长,造成卡顿图片:

如下图 , cpu 频率对性能的影响图片:

优先级低未能及时获取cpu时间片导致卡顿

在调度器看来的低优先级任务 , 在用户这里未必是低优先级任务 , 他可能正在和 App 的主线程交互 , 或者正在和 system_server 进行交互。

被RT进程抢占

App 主线程或者渲染线程被 RT 进程抢占也会导致系统卡顿或者响应慢 , Google 也意识到了这个问题 , 也在尝试在应用启动的时候 , 把 App 主线程和渲染线程的优先级也设置为 RT , 不过这个属性一直没开 , 因为会导致应用启动速度变慢。

大小核调度问题

大小核调度的问题通常表现在该跑在大核的任务跑到了小核 , 或者该在小核运行的任务却持续跑到大核 ,或者错误的被绑定在了某一个核心上。

如下图, 这是一个 CTS 问题, CTS 主线程由于被绑定到了 cpu7 , 由于 cpu7 在执行 RenderThread , 所以主线程没有调度到, 导致 CTS 失败:

触发Thermal导致限频

触发 Thermal 发热限频也有可能导致卡顿 , 这算是一种硬件级别的保护 , 如果手机已经过热 , 此时如果不进行干涉 , 那么可能会导致用户手机太烫而无法持续使用手机. 一般这个时候都会对系统的资源进行一些限制 , 比如降低 cpu\gpu 的最高频率之类的 , 这么做的话 , 势必也会对流畅性造成影响。如果你手机非常热 , 而且变卡了 , 那么放下手机休息一会 , 查杀一下后台 , 或者重启一下手机。

后台活动进程太多导致系统繁忙

后台进程活动太多,会导致系统非常繁忙, cpu \ io \ memory 等资源都会被占用, 这时候很容易出现卡顿问题 , 这也是系统这边经常会碰到的问题。

CPU繁忙

Dumpsys cpuinfo可以查看一段时间内cpu的使用情况。

主线程调度不到,处于Runnable状态

当线程为 Runnable 状态的时候 , 调度器如果迟迟不能对齐进行调度 , 那么就会产生长时间的 Runnable 线程状态 , 导致错过 Vsync 而产生流畅性问题。

无关进程活跃耗时

无关进程通常是人为定义的,指的是当前前台App运行无关的进程,这些活跃进程势必会对App主进程的调度产生影响,不管这些无关进程是系统的还是App自身的,或是其他三方的App的。

CPU被占用

当后台任务过多的时候,cpu资源就会异常紧缺,如下图就是在系统低内存的时候,HeapTask和kswapD几乎沾满了整个cpu,在疯狂地想系统申请内存。

System锁

system_server 的 AMS 锁和 WMS 锁 , 在系统异常的情况下 , 会变得非常严重 , 如下图所示 , 许多系统的关键任务都被阻塞 , 等待锁的释放 , 这时候如果有 App 发来的 Binder 请求带锁 , 那么也会进入等待状态 , 这时候 App 就会产生性能问题 ; 如果此时做 Window 动画 , 那么 system_server 的这些锁也会导致窗口动画卡顿。

Layer过多导致SurfaceFlinger Layer Compute耗时

Android P 修改了 Layer 的计算方法 , 把这部分放到了 SurfaceFlinger 主线程去执行, 如果后台 Layer 过多, 就会导致 SurfaceFlinger 在执行 rebuildLayerStacks 的时候耗时 , 导致 SurfaceFlinger 主线程执行时间过长。

所以在使用 Android 系统的时候 , 记得多用多任务清理后台任务。

Input报点不均匀

如果出现 Input 报点不均匀或者没有报点的情况, 那么主线程由于没有收到 Input 事件, 所以不去做绘制, 也会导致卡顿。如下图 , 这是一个连续滑动的 Systrace 图 ÿ


http://www.kler.cn/news/339021.html

相关文章:

  • 渐开线起始圆和基圆之间有约束关系吗?
  • CVE-2024-9014 pgAdmin4 OAuth2 client ID与secret敏感信息泄漏漏洞
  • Mysql数据库原理--查询收尾+索引+事务
  • ubuntu18.04运行OpenPCDet出现的问题
  • gm/ID设计方法学习笔记(二)
  • FireRedTTS - 小红书最新开源AI语音克隆合成系统 免训练一键音频克隆 本地一键整合包下载
  • 找不到concrt140.dll如何修复,快来试试这6种解决方法
  • 红日靶机(三)笔记
  • docker compose入门2—docker-compose.yaml中的version表示什么意思
  • MySQL表操作(进阶)
  • 使用A*算法进行无人机路径规划的优化
  • UE5蓝图实战:动态墙上挖坑与自定义坑尺寸
  • 数据提取之JSON与JsonPATH
  • 来看看Python迭代器能让你的代码提升100倍的密码
  • MySQL 篇-深入了解视图、SQL 优化(主键优化、order by 优化、group by 优化、update 优化等)
  • 1.一、MyBatis入门
  • JS进阶 3——深入面向对象、原型
  • 费曼学习法没有输出对象怎么办?
  • 算法专题三: 二分查找
  • 【STM32单片机_(HAL库)】4-2-1【定时器TIM】定时器输出PWM实现呼吸灯实验