帧率和丢帧分析实践
一、识别丢帧
1、使用AppAnalyzer检测性能问题
首先使用AppAnalyzer工具进行性能问题检测,AppAnalyzer是DevEco Studio中提供的检测评分工具,用于测试并评价HarmonyOS应用或元服务的质量,能快速提供评估结果和改进建议,当前支持的测试类型包括兼容性、性能、UX测试和最佳实践等。
(1)启动DevEco Studio,连接设备,打开应用。
a、单击菜单栏Tools > AppAnalyzer
b、在AppAnalyzer页面Module选择框选择应用/服务工程模块
c、根据应用的类别选择Category
d、选择Rules,这里选择Benchmark(性能套餐),勾选”Fast Response to In-app Swipes”(应用内滑动操作响应快)、“Smooth In-app Swiping“(应用内滑动过程流畅)和“Smooth In-app Transitions“(应用内转场操作流畅)
(2) 点击Start启动检测,检测过程中,手机需要保持解锁亮屏状态
a、工具会先对应用功能进行自动检测,开发者不需要进行操作,在自动检测结束后需要根据提示手动遍历应用功能
b、自动检测和手动遍历完成后点击Stop停止测试任务
(3)获得检测结果,下面列举了检测通过和未通过的示例
检测通过示例,如下图所示,无异常信息;
检测未通过示例,例如下图结果,有多项检测未通过。
点击左侧的菜单栏对应的选项,可以查看异常的具体信息。
2、录制Frame模板
发现卡顿丢帧问题后创建Frame模板录制,在录制期间复现卡顿丢帧场景。录制完成后,在时间轴上拖动鼠标选定要查看的时间段,这里选择了一个2.5s的时间区段。选中Frame主泳道,查看下面的Statistics栏,可以发现应用在这个时间段内丢了16帧,丢帧率达到了7%。
3、认识卡顿帧
下面是使用Frame Profiler录制的一段Trace,在时间轴上拖动鼠标选定要查看的时间段,这里我们选择了一个2.5s的时间区段。选中Frame主泳道,查看下面的Statistics栏,可以发现应用在这个时间段内丢了16帧,丢帧率达到了7%。
丢帧问题可能出现在Render Service侧,也有可能出现在App侧。上图中的丢帧主要出现在应用帧,针对这种丢帧现象我们继续分析,放大右侧的图表,选中超时的帧查看详细数据,期望时间为8.3ms(当前设备为120Hz),而实际处理时间为8.9ms。
二、分析丢帧原因
1、看线程状态和运行核,看是否被其他进程抢占资源,排除系统侧运行异常。
(1)看线程状态
从下图可以看到,应用线程大部分时间处于Running状态,无特殊异常。运行在CPU10和CPU11上。
(2)看运行频率
查看关键任务是否跑在了小核,以低频运行。从CPU Slice和Frequency泳道,如图8所示,可以看到丢帧处应用线程和前面正常帧类似,都主要运行在大核上(该设备0~3号CPU是小核,4~11号CPU为大核)。鼠标悬浮在Frequency泳道上,可以看到CPU运行频率。
通过上面的分析,可以看到应用线程正常运行在CPU大核上,且运行频率正常。到这里,这个示例可以排除系统异常。
如果应用线程运行出现以下问题,开发者可以进行在线提单反馈异常。
- 执行频率较低
- 线程在小核上工作
- 线程频繁在Running和Runnable之间切换
- 线程频繁在Running和Sleep之间切换
- 不重要的线程占用了大核
2、找到Trace中每一帧耗时的部分,大致定位是App侧问题还是RS侧问题,并结合Trace标签,初步定位原因。
通过Frame泳道,我们可以快速发现丢帧的位置,并完成初步的定界:
- App侧有红色出现,需要审视UI线程的处理逻辑是否过于复杂或低效,以及是否被其它任务抢占资源。
- 如果是RenderService帧处理有红色出现,需要审视是否是界面布局过于复杂。可以借助DevEco Studio内的ArkUI Inspector、HiDumper等工具进一步分析。
前面示例中的丢帧主要出现在应用侧,针对这种丢帧现象我们继续分析,放大右侧的图表,选中超时的帧(220#帧)查看详细数据,期望时间为8.3ms(当前设备为120Hz),而实际处理时间为8.9ms。
接下来通过Trace再看看每一帧的具体耗时情况。这里有一个小技巧,我们可以点击泳道信息区的收藏按钮,将应用帧处理的泳道收藏置顶,可以有效防止上下文信息丢失。点击图标跳转到卡顿帧应用侧Trace详情,如下图所示:
可以看到这这几帧的卡顿可能都是BuildLazyItem方法耗时较长导致,可以大致推测,是列表懒加载时,Item绘制时间较长导致的。
同时在ArkUI Component泳道上,可以直观的看到,自定义组件ArtileView的绘制频率比较高且比较耗时,对于太过频繁的绘制组件,可能也是影响应用丢帧的原因。
需要注意的是在Frame模板中,要想查看ArkUI Component泳道需要在泳道录制前进行手动勾选,如下图所示:
3、查看ArkTS函数调用栈信息,排查应用编码。
可以结合Frame Profiler工具,选择ArkTS Callstack泳道查看热点函数,方便地跳回源码,定位具体是哪一个自定义组件绘制时间较长。如下图所示,可以看到自定义组件ArticleCardView的绘制频繁。下面以220#帧为例子,通过热点函数可以看到其中initialRenderView 和__lazyForEachItemGenFunction这两个方法比较耗时,占比分别达到52.7%和22.9%,其中绿色的”ArkTS”表示双击该行可以跳转到应用源码。
我们以initialRenderView函数的耗时为例进行分析,展开函数,可以看到主要是列表项ListItem的子组件ArticleCardView创建比较耗时。
展开其中一个组件函数调用链进行详细分析,通过查看函数调用,可以猜测是由于使用了@Prop变量,@Prop装饰的变量会对父组件传入状态值进行深拷贝,如果@Prop装饰器装饰的变量为复杂Object、class或其类型数组时,会增加状态创建时间以及占用大量内存。双击跳转到源码,可以看到自定义组件ActionButtonView中确实使用了@Prop装饰器变量。
三、选择优化方案
选择优化方案需要一些经验的积累,开发者可以参考一些性能方面的最佳实践,来选择相应的优化方法。
下面我们对丢帧问题进行优化,针对前面的一些分析结果,我们可以从两方面来入手解决卡顿问题:
- 使用组件复用能力@Reusable来减少组件的频繁创建。可复用组件从组件树上移除时,会进入到一个回收缓存区。后续创建新组件节点时,会复用缓存区中的节点,节约组件重新创建的时间。
- 简化组件创建的逻辑,使用更高效的@Builder来构建列表项Item的子组件,替代原有@Component自定义组件的方式。此外使用@Builder以后,就不需要使用@Prop了,从而减少了数据的深拷贝耗时。
四、验证优化效果
最后,我们可以使用步骤一的方式,来验证优化后的结果。下面用Frame模板录制后发现,丢帧情况得到明显改善,列表快速滑动15.9s,丢帧率为0%,丢帧问题得到解决。如下图:
如果此时问题仍未解决,可以再重新分析Trace定位问题,然后选择优化方式。
原文地址:https://blog.csdn.net/sinat_34896766/article/details/142215634
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!