卡顿分析是非常复杂的,但是也是我们必须要掌握的一个点,最近遇到了一个bug,根据平台的帮忙以及自身的分析最终定位到原因,这一步步的分析流程可以形成一个套路流程以供参考
(没关系我不累)
问题描述以及初步分析
手机在使用过程中滑动Launcher感觉非常卡顿,有十分明显的掉帧情况。不管是从抓取的logcat中findstr查看当前的fps还是从trace中通过surfaceflinger去查看当前出帧情况,都可以验证肉眼看到的情况。那么对于这样的情况,我们怎样去分析原因呢?分为以下几个步骤
对于卡顿问题,我们首先会选用一个对比机以及设立一个标准,这样才能明确究竟什么才是卡,因为不能说一掉帧他就是卡了。那么对于卡顿,我们主要还是从trace中查看函数调用以及CPU利用进行分析。从图中我们可以看到,分析的第一步就是要判断是否是UI thread长,也就是RenderThread。
检查Renderthread
本机器为90Hz,所以理论上每一帧的渲染时间都应该为11ms,那么超过11ms的绘制帧就应该表现为掉帧了,事实真的是这样吗?那肯定不是的。因为除了这一块,我们也需要同步看SF的buffer产生,毕竟不止这一个程序在运行,对吧。
那么我们结合SF的VSYNC信号,可以看到确实没有出帧并且sf的合成也比较慢,每一次合成也是超时的。既然如此,我们回到应用本身去查看他的出帧情况,可以发现他不是runnable时间过长,也不是uninterruptible sleep或者sleep时间长,而是running时间明显长于90Hz一帧所需要的时间~~(当然,也只有这四种状态)~~ 。那么本篇文章主要从running时间长这一方面下手,其他的情况以后再聊~
running时间长
将超时的一帧放大,对每一个函数调用的时间进行拆解,首先我们看到最前面的绿色标,将它放大来:
可以看到这里就是同步帧状态,,然后进行绘制。右边的紫色标就是查询曲面帧并且进行dequebuffer去请求一个空闲的缓冲区进行绘制。淡紫色的标签也可以看出来,绘制的大小就是1080x2460,如果trace看的是系统的apk,那它基本等于机器的分辨率。这两部分的时长对比同等CPU正常运行不卡的机器,running时间基本是正常一致的。但是这个Drawing过程异常长与对比机,继续拆分下面三个主要函数
字段名 | 耗时 |
---|---|
renderFrameImpl | 2642us |
flush commands | 8270us |
eglSwapBuffersWithDamageKHR | 1596us |
对比发现主要长在flush commands这个函数,那么在这一段我们可以在下面看到两个函数:一个是texture upload ,还有一个是texture release。那么就说明这么长一段主要是由于apk纹理的绘制上传以及结束,主要还是由apk端去优化问题。那么在这里,有些小明以为就结束辣?那肯定没有这么简单。我们这种愿意探索的人肯定不能放弃学习的机会啦。
接下来,热爱探索的小明对着手中的这台机器输入了如下命令:
adb shell setprop “debug.hwui.skia_atrace_enabled” true
adb shell “setprop vendor.debug.gpu.provider meow”
adb shell “stop;start”
(当然,需要root)去抓取skia + gles trace,这样我们就能看到他的具体耗时咯。那么根据以上命令,我们看到
这个apk的绘制逻辑还是很复杂的。。。在CPU以及GPU性能不足的情况下卡顿是很正常的事情,但是这个的前提需要是
- CPU调度没有问题
- 后台没有其他负载很重的进程
- 可以尝试将CPU、GPU、DDR频率拉满进行测试
- CPU大核是否运行应用
如果对齐了以上几点仍然没有改善的话,基本可以从APK端去解决问题了。记得给你应用端的好同事买桶泡面犒劳下,毕竟你增加了他的劳动量对吧。
QWQ
😛