帧率和丢帧分析实践

一、识别丢帧

        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定位问题,然后选择优化方式。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1541003.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Visual Studio 引入外部静态库与动态库

Windows Visual Studio 引入外部静态库与动态库 1.前言 在C开发中不可避免地要在自己的项目中引入外部库(OpenGL、OpenCV、OCC等),使用这些库都需要在项目中配置相应的属性才能正常开发编译。 2.引入 引入外部库主要引入三种文件&#xf…

C语言 | Leetcode C语言题解之第420题强密码检验器

题目&#xff1a; 题解&#xff1a; #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))int strongPasswordChecker(char * password) {int n strlen(password);bool has_lower false, has_upper false, has_digit false;for …

高质量的翻译:应用程序可用性和成功的关键

在日益全球化的应用市场中&#xff0c;开发一款优秀的产品只是成功的一半。另一半&#xff1f;确保你的用户&#xff0c;无论他们在哪里或说什么语言&#xff0c;都能无缝理解和使用它。这就是高质量翻译的用武之地——不是事后的想法&#xff0c;而是应用程序可用性和最终成功…

攻防世界---->ReverseMe-120

做题学习笔记。 前言&#xff1a;目前遇见的reverse都是&#xff0c;已知密文&#xff0c;去求解明文flag&#xff1b; 此题逆着来&#xff0c;通过明文&#xff0c;去求解密文flag。 base加密的识别&#xff0c;还算容易。 那么&#xff0c;base解码的识别呢&#xff1f; 攻…

Java调用数据库 笔记06 (修改篇)

1.创建Java的普通class类 2.加载驱动 Class.forName("com.mysql.jdbc.Driver"); 3.驱动管理类调用方法进行连接&#xff0c;得到连接对象 DriverManager.getConnection(url, user, password); 其中设置参数&#xff1a; static final String url "jdbc:my…

聊天组件 Vue3-beautiful-chat 插槽

前言 Vue3-beautiful-chat 组件有四个插槽可以定制 一、user-avatar(头像) 首先是头像插槽,我们可以直接在 <beautiful-chat></beautiful-chat> 中间使用; 作用: 我们可以在用户头像上添加自定义样式,比如添加节日边框、可以使用首字母作为头像。。。 …

《使用 LangChain 进行大模型应用开发》学习笔记(五)

前言 本文是 Harrison Chase &#xff08;LangChain 创建者&#xff09;和吴恩达&#xff08;Andrew Ng&#xff09;的视频课程《LangChain for LLM Application Development》&#xff08;使用 LangChain 进行大模型应用开发&#xff09;的学习笔记。由于原课程为全英文视频课…

kafka动态认证 自定义认证 安全认证-亲测成功

kafka动态认证 自定义认证 安全认证-亲测成功 背景 Kafka默认是没有安全机制的&#xff0c;一直在裸奔。用户认证功能&#xff0c;是一个成熟组件不可或缺的功能。在0.9版本以前kafka是没有用户认证模块的&#xff08;或者说只有SSL&#xff09;&#xff0c;好在kafka0.9版本…

【全网首发】2024华为杯数学建模ABCDEF选题方向+完整思路代码+数据集处理+可视化结果

2024华为杯研究生数学建模比赛ABCDEF选题分析 建议选哪道题&#xff1f; 点击链接加入群聊【2024华为杯数学建模助攻资料】&#xff1a;http://qm.qq.com/cgi-bin/qm/qr?_wv1027&kxtS4vwn3gcv8oCYYyrqd0BvFc7tNfhV7&authKeyedQFZne%2BzvEfLEVg2v8FOm%2BWNg1V%2Fiv3H…

Apifox Mock使用教程

Apifox是一个功能强大的可视化接口文档管理工具&#xff0c;使用Apifox可以让接口Mock变得更简单容易。Apifox具有出色的Mock功能&#xff0c;不仅兼容Mock.js语法&#xff0c;同时提供Nunjucks 和自定义脚本支持&#xff0c;能够满足不同场景需求&#xff0c;为前端接口调试提…

Element 表格相关操作

数据和页面展示分离操作 <script setup> // 从Element Plus中导入需要的图标组件 import {Check,Delete,Edit,Message,Search,Star, } from element-plus/icons-vue // 导入Vue的ref和onMounted函数 import {ref,onMounted} from vue;// 使用ref创建一个响应式的use…

vue-使用refs取值,打印出来是个数组??

背景&#xff1a; 经常使用$refs去获取组件实例&#xff0c;一般都是拿到实例对象&#xff0c;这次去取值的时候发现&#xff0c;拿到的竟然是个数组。 原因&#xff1a; 这是vue的特性,自动把v-for里面的ref展开成数组的形式&#xff0c;哪怕你的ref名字是唯一的&#xff01…

Java集合(List篇)

List a.使用List i.最基础的一种集合&#xff0c;是一种有序列表&#xff0c;内部按照放入元素的先后顺序存放&#xff0c;每个元素都可以通过索引确定自己的位置。 ii.数组的删除和新增 iii.ArrayList集合的新增和删除。 iv.LinkedList&#xff08;链表式集合&#x…

Ceph 基本架构(一)

Ceph架构图 Ceph整体组成 Ceph 是一个开源的分布式存储系统&#xff0c;设计用于提供优秀的性能、可靠性和可扩展性。Ceph 的架构主要由几个核心组件构成&#xff0c;每个组件都有特定的功能&#xff0c;共同协作以实现高可用性和数据的一致性。 以下是 Ceph 的整体架构及其…

Tomcat CVE-2017-12615 靶场攻略

漏洞描述 当 Tomcat运⾏在Windows操作系统时&#xff0c;且启⽤了HTTP PUT请求⽅法&#xff08;例如&#xff0c;将 readonly初始化参数由默认值设置为false&#xff09;&#xff0c;攻击者将有可能可通过精⼼构造的攻击请求数据包向服务器上传包含任意代 的 JSP ⽂件&#xf…

队列基础概念

文章目录 &#x1f34a;自我介绍&#x1f34a;现实生活中的例子&#x1f34a;队列的介绍&#x1f34a;循环队列&#x1f34a;小结 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;自我介…

LeetCode[中等] 54.螺旋矩阵

给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 思路&#xff1a;定义方向数组&#xff0c;按照顺时针顺序&#xff1a;右(0,1)&#xff0c;下(1,0)&#xff0c;左(0,-1)&#xff0c;上(0,-1) 从矩阵的左上角开始遍历…

了解深度学习,张量,线性代数,激活函数的概念

在人工智能领域&#xff0c;尤其是深度学习中&#xff0c;张量和线性代数是不可或缺的数学工具。这些数学知识的应用主要体现在以下几个方面&#xff1a; 数据表示与运算&#xff1a;张量是多维数组&#xff0c;用于表示和存储数据。在深度学习中&#xff0c;大部分的数据和权重…

常见项目场景题1(数据量很大时如何去重,实现超时处理)

数据很多&#xff0c;限制内存&#xff0c;如何去重 对于大数据量去重的场景&#xff0c;我们可以考虑使用位图(Bitmap) Bitmap 是使用二进制来表示某个元素是否存在的数组。用0和1来表示存在与不存在 使用Bitmap的话&#xff0c;一个数字占用1bit&#xff0c;大大减少内存消耗…

Unity自我实现响应式属性

其实只是写着玩,响应式编程建议使用UniRx插件(一套成熟的响应式编程解决方案),我写的主要是借鉴一下这个思想,实现的也不够优雅,不过逻辑也算严密可以正常使用.你可以查看我写的理解响应式属性的思想. 借鉴UniRx的ReactiveProperty类,且UniRx不仅有响应式属性. using System; …