1 关键字

滑动;FPS;帧率;

2 问题描述

OpenHarmony版本:3.2 Release

问题描述:设置应用首页列表滑动卡顿,使用 DevEcoTesting 工具测试帧率只有 40 fps

3 问题原因

3.1 正常机制

设置应用首页列表滑动正常,使用 DevEcoTesting 工具测试帧率 58 fps以上

3.2 异常机制

由于设置应用的UI 布局过度嵌套,装饰器 linearGradient 性能较差,导致列表滑动卡顿帧率不达标

4 解决方案

  1. 优化UI页面,减少过度绘制;

  2. 列表使用使用 LazyForEach 嵌套 List 控件;

  3. 去除 listitem 使用的 linearGradient 装饰器,点击效果使用用动态修改 backgroundColor 方法;

5 定位过程

快速滑动列表首页,使用 GP_daemon_fps 工具抓取帧率:

抓取命令:

GP_daemon_fps 10 | grep fps

抓取结果:

FPS

使用 GP_daemon_fps 工具抓取帧率最高42 fps 最低28 fps,帧率达标值为58 fps 以上,性能严重不达标。

于是,抓取滑动时的 trace 具体分析导致帧率不达标的因素。使用如下命令抓取 trace,抓取成功后,使用 chrome 浏览器的 tracing 插件(chrome://tracing) 分析抓取的 trace 文件。注意:使用tracing 插件分析需要删除 trace 文本的前2行没有#标识的 text 文本

hdc_std shell bytrace -t 5 --overwrite ability app ark ace window graphic > D:mytrace_01.ftrace

使用 tracing 插件打开 trace 文件后,选取10 个 vsync 信号,如下图:

OnVsyncEvent

RSMainThread::OnVsync

10 个 vsync 信号对应的时长为 165.86 ms,但是 RSRenderThread 和 RSMainThread 只处理 6 个 vsync 信号。下面,分别抓取单个 RSRenderThread 和 RSMainThread 处理一个 vsync 信号的时长。如下图

RSRenderThread

RSRenderThread

RSMainThread

通过观察上各个阶段的单帧处理时长,可以发现:控件的测量与绘制指令的录制阶段性能是达标的,远低于16.6ms(1000/60 =16.6 1000ms 60 fps)的阈值,但是渲染阶段在(RSRenderThread )在处理一个 vsync 信号时,时间最大达到了 31ms,严重超过了16.6ms,因此可以判定 RSRenderThread 绘制线程出现了丢帧,进而导致后续的 RenderService 以及 display 在合成送显过程也出现丢帧。因而,使用帧率测试工具测试 fps 只有40 左右,列表在滑动的过程中,给用户明显的肉眼卡顿。

5.1 UI 优化

现在思考怎样能够缩减单帧的绘制时间?具有前端开发经验的同学肯定知道,UI 性能优化有两个重要的措施:

  1. UI 布局的优化

  2. 减少 UI 的层级

在讲上面2个优化手段之前,首先引入一个概念:过度绘制。过度绘制(Overdraw)是指应用在渲染一帧的时间内对屏幕某个像素进行多次绘制。应用应该尽可能避免过度绘制。在 OpenHarmony 系统中,设置中的开发者选项提供了过度绘制检测工具,此工具能够展示页面上哪些区域出现了不必要的过度绘制,可以直观查看应用当前页面是否存在过度绘制的现象,并且可以直观对比优化前后的显示效果。

按照步骤开启:设置>开发者选项>调试 GPU 过度绘制

开启调试 GPU 过度绘制后

display

不同的颜色代表不同程度的过度绘制:无色到红色,颜色越深,表示过度绘制的层度越大。因此过度绘制的优化目标是使得显示区域的过度绘制色块大部分为无色或者为蓝色,避免不大面积出现红色。

查看设置应用 UI 代码,有 List 嵌套 List 以及多个Column 相互嵌套的情况,因而可以通过优化布局解决 list 和 Column 相互嵌套

优化前示例:

List() {
   ......
   ListItem() {
      List() {
          ListItem(){}
          ......
      }
      ......
   }
}

优化界面布局后,右侧箭头的红色区域消失

display

5.2 LazyForEach

OpenHarmony arkUI 为 list 组件提供了 LazyForEach 数据懒加载机制。LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当 LazyForEach 在滚动容器中使用了,框架会根据滚动容器可视区域按需创建组件,当组件划出可视区域外时,框架会进行组件销毁回收以降低内存占用。

因此,首页列表的数据源也可以使用 LazyForEach 数据懒加载机制。在使用 LazyForEach 懒加载机制后,当快速滑动时,使用top 命令查看当前的CPU利用分布情况以及内存使用情况:可以发现 settings、render_server 进程的 cpu 时间占用百分比和进程使用的物理内存百分比明显降低,如下图:

优化前

top

优化后

top

5.3 点击效果的替换

在使用上述2个优化手段后,再次抓取 trace 分析,UI控件的测量阶段单帧耗时得到了优化,单个 vsync 信号的处理时间降到了10ms 以内,但是 RSRenderThread 处理单个 vsync 信号的时长却没有明显的降低。如下图:RSRenderThread 处理5个 vsync 信号耗时145ms,单个 vsync 信号处理时长接近30 ms。

trace

但是, list demo 应用 RSRenderThread 处理单个 vsync 信号在12ms 以内,如下图:

trace

通过2个trace 数据的对比,说明设置列表中肯定存在UI元素会导致 RSRenderThread 渲染阶段性能劣化。通过注释列表中的 UI 元素,最后发现,列表中 item 设置的 linearGradient 渐变装饰会导致性能劣化。由于 linearGradient 属性会导致UI 性能劣化,于是使用 backgroundColor 暂时替换渐变效果。

5.4 优化后的效果

通过上述手段优化后,设置列表的快速滑动时,视觉卡顿消失,再次抓取trace,165ms 完成了10 个vsync 信号的处理,单个信号处理时长低于16.6 ms,优化后的帧率接近60fps。

trace

trace

使用 GP_daemon_fps 工具抓取帧率,最高可以达到59 fps,稳定在55fps 以上。

优化后FPS

 

 

 

 

 

 

6 知识分享

本问主要介绍了如何从应用角度去分析帧率卡顿,系统层面可以参考:芯片解决方案--SL8541e-系统性能优化总结

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐