鸿蒙系列-如何使用DevEco分析app的性能

如何使用DevEco分析app的性能

性能优化、启动优化、内存优化、FPS监测、性能分析🧐

在鸿蒙OpenHarmony开发过程中,开发者开发的代码(Stage 模型)通常以调用 ArkUI 框架的代码为主,主要优化的代码部分也在其中,那么如何验证自己的代码是否起到了优化效果,就需要工具对比分析优化前和优化后的效果。
我们以一次测试过程为例,介绍如何分析性能。

构造场景,验证 RelativeContainer() 提升性能的能力

测试方法:我们使用对比测试的方法,比较使用 RelativeContainer() 前后可以对比的性能指标,来证明合理使用布局是对性能提升有帮助的。

测试工具:DevEco 中的 Profiler 工具。
图标以此对应可以监测的场景有:启动、帧率、耗时、内存。

测试的关键点如下:

  1. 将 Text 作为最小单元,Row 作为模拟嵌套层级使用的容器,RelativeContainer() 作为相对布局使用的容器。
  2. 将定义一组(10)颜色循环使用,这个颜色用做 Text 的背景色,用于直观地区分每个 Text 组件。(定义10个是为了代码更易读,也方便以10为单位扩展,生成20、30、40等数据📊)
  3. 使用 50 个 Text 组件连续嵌套,测试嵌套层级为 50 级的情况。Row() 是我们用于嵌套的容器。代码放在 Stack50View.ets
  4. 将 50 个 Text 组件平铺成 1 层,测试嵌套层级为 2 级( 50个Text层 + RelativeContainer()层)的情况。 RelativeContainer() 是我们用于减少布局嵌套层数的容器。代码放在 Relative50View.ets
  5. 对比第3点和第4点的渲染时间和内存情况,试图以此来证明使用 RelativeContainer() 布局可以优化性能。

定义的颜色如下:

const COLORS = [Color.Blue, Color.Green, Color.Pink, Color.Brown, Color.Grey,
Color.White, Color.Black, Color.Orange, Color.Yellow, Color.Red]

通过编码使得 Relative50View.ets 和 Stack50View.ets 能产生一样的视觉效果,在每个 Text 上编号以区分,效果如下:

然后,把他们放在一个list里,一共10行,效果如下:

测试结果:

启动分析,启动后6s内的性能分析

不使用 RelativeContainer() 的情况:

@Entry
@Component
struct Index {@State message: string = 'Hello World'build() {Column() {Stack50View()Stack50View()Stack50View()Stack50View()Stack50View()Stack50View()Stack50View()Stack50View()Stack50View()Stack50View()}}
}

在这里插入图片描述

使用 RelativeContainer() 的情况:

在这里插入图片描述

@Entry
@Component
struct Index {@State message: string = 'Hello World'build() {Column() {Relative50View()Relative50View()Relative50View()Relative50View()Relative50View()Relative50View()Relative50View()Relative50View()Relative50View()Relative50View()}}
}

内存分析,启动后6s内的内存分析

不使用 RelativeContainer() 的情况:

在这里插入图片描述

使用 RelativeContainer() 的情况:

在这里插入图片描述

帧率分析,上下滑动 list 时候的帧率变化

定义100个item放到list中

不使用 RelativeContainer() 的情况:

@Entry
@Component
struct Index {@State arr: number[] = Array.from(Array(100).keys()); build() {Column() {List() {ForEach(this.arr,(item) => {ListItem() {Stack50View()}},(item) => item.toString())}}}
}

在这里插入图片描述

使用 RelativeContainer() 的情况:

在这里插入图片描述

@Entry
@Component
struct Index {@State arr: number[] = Array.from(Array(100).keys());build() {Column() {List() {ForEach(this.arr,(item) => {ListItem() {// Stack50View()Relative50View()}},(item) => item.toString())}}}
}

结论:

这么看对比效果不佳。

对比项启动分析(onCreate)内存分析滑动时卡顿率(jank rate)
优化前1.374ms-8.2%
优化后1.697ms-13.4%

进一步测试

验证嵌套层级深度对性能有影响。
对比如下数据:

  1. 构建 50 层嵌套,只在第50层加一个text
  2. 构建 1 层嵌套,加一个text
对比项启动分析(onCreate)内存分析滑动时卡顿率(jank rate)
优化前0.821ms-0.5%
优化后0.027ms-0.0%

在这里插入图片描述

在这里插入图片描述

通过多组数据可以画出折线图:

结论:组件嵌套会增加渲染时间和内存。

对比测试

通过 Frame 监测列表下 render_service(1132) 中的 VSync-app 1374 中框选时间片段得到:

对比项1层嵌套10层嵌套20层嵌套30层嵌套40层嵌套50层嵌套
time---757.1ms512.4ms757.1ms
occurrences---684768
FPS---909089

结论:从嵌套50层仍有89帧来看,说明嵌套对帧率变化影响不明显。

其他代码如下:

Relative50View.ets


const COLORS = [Color.Blue, Color.Green, Color.Pink, Color.Brown, Color.Grey,
Color.White, Color.Black, Color.Orange, Color.Yellow, Color.Red]@Builder function TextBuilder(index: number) {Text(`${index%10}`).fontColor(Color.White).fontSize(9).alignRules({top: { anchor: '__container__', align: VerticalAlign.Top },left: { anchor: '__container__', align: HorizontalAlign.Start }}).id(`figure${index}`).backgroundColor(COLORS[index%10]).align(Alignment.TopStart).height(70).margin({ top: 0, left: 5 * index })
}@Preview
@Component
export struct Relative50View {build() {Row() {Row() {RelativeContainerBuilder1()}.width('100%')}.height(100)}
}@Builder function RelativeContainerBuilder1() {RelativeContainer() {TextBuilder(0)TextBuilder(1)TextBuilder(2)TextBuilder(3)TextBuilder(4)TextBuilder(5)TextBuilder(6)TextBuilder(7)TextBuilder(8)TextBuilder(9)// 10TextBuilder(10)TextBuilder(11)TextBuilder(12)TextBuilder(13)TextBuilder(14)TextBuilder(15)TextBuilder(16)TextBuilder(17)TextBuilder(18)TextBuilder(19)// 20TextBuilder(20)TextBuilder(21)TextBuilder(22)TextBuilder(23)TextBuilder(24)TextBuilder(25)TextBuilder(26)TextBuilder(27)TextBuilder(28)TextBuilder(29)// 30TextBuilder(30)TextBuilder(31)TextBuilder(32)TextBuilder(33)TextBuilder(34)TextBuilder(35)TextBuilder(36)TextBuilder(37)TextBuilder(38)TextBuilder(39)// 40TextBuilder(40)TextBuilder(41)TextBuilder(42)TextBuilder(43)TextBuilder(44)TextBuilder(45)TextBuilder(46)TextBuilder(47)TextBuilder(48)TextBuilder(49)}
}

Stack50View.ets

const COLORS = [Color.Blue, Color.Green, Color.Pink, Color.Brown, Color.Grey,
Color.White, Color.Black, Color.Orange, Color.Yellow, Color.Red]@Preview
@Component
export struct Stack50View {build() {Row() {Row() {StackBuilder1()}.width('100%')}.height(100)}
}@Builder function TextBuilder(index: number, group: number) {Text(`${index%10}`).fontColor(Color.White).fontSize(9).backgroundColor(COLORS[index%10]).align(Alignment.TopStart).height(70)
}// 构建 1 层嵌套,加一个text
@Builder function StackBuilder3() {Row() {Text(`${50}`).fontColor(Color.White).fontSize(9).backgroundColor(COLORS[0]).align(Alignment.TopStart).height(50)}
}// 构建 50 层嵌套,只在第50层加一个text
@Builder function StackBuilder2(index: number) {Row() {if (index > 0) {StackBuilder2(index-1)} else {Text(`${50}`).fontColor(Color.White).fontSize(9).backgroundColor(COLORS[index%10]).align(Alignment.TopStart).height(50)}}
}// 构建 50 层嵌套,每一层增加一个text
@Builder function StackBuilder1() {Row() {TextBuilder(0, 0)Row() {TextBuilder(1, 0)Row() {TextBuilder(2, 0)Row() {TextBuilder(3, 0)Row() {TextBuilder(4, 0)Row() {TextBuilder(5, 0)Row() {TextBuilder(6, 0)Row() {TextBuilder(7, 0)Row() {TextBuilder(8, 0)Row() {TextBuilder(9, 0)// 10Row() {TextBuilder(10, 1)Row() {TextBuilder(11, 1)Row() {TextBuilder(12, 1)Row() {TextBuilder(13, 1)Row() {TextBuilder(14, 1)Row() {TextBuilder(15, 1)Row() {TextBuilder(16, 1)Row() {TextBuilder(17, 1)Row() {TextBuilder(18, 1)Row() {TextBuilder(19, 1)//20Row() {TextBuilder(20, 2)Row() {TextBuilder(21, 2)Row() {TextBuilder(22, 2)Row() {TextBuilder(23, 2)Row() {TextBuilder(24, 2)Row() {TextBuilder(25, 2)Row() {TextBuilder(26, 2)Row() {TextBuilder(27, 2)Row() {TextBuilder(28, 2)Row() {TextBuilder(29, 2)// 30Row() {TextBuilder(30, 3)Row() {TextBuilder(31, 3)Row() {TextBuilder(32, 3)Row() {TextBuilder(33, 3)Row() {TextBuilder(34, 3)Row() {TextBuilder(35, 3)Row() {TextBuilder(36, 3)Row() {TextBuilder(37, 3)Row() {TextBuilder(38, 3)Row() {TextBuilder(39, 3)// 40Row() {TextBuilder(40, 4)Row() {TextBuilder(41, 4)Row() {TextBuilder(42, 4)Row() {TextBuilder(43, 4)Row() {TextBuilder(44, 4)Row() {TextBuilder(45, 4)Row() {TextBuilder(46, 4)Row() {TextBuilder(47, 4)Row() {TextBuilder(48, 4)Row() {TextBuilder(49, 4)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信息安全保障

文章目录 目录 文章目录 一.信息安全的定义 信息安全的概念 狭义的信息安全概念: 广义的信息安全问题: 信息系统安全问题的根源: 威胁情报 威胁情报的作用: 信息安全的特征 二.信息系统的属性 三.信息安全的视角 国家视角下的信…

LlamaIndex:将个人数据添加到LLM

推荐:使用 NSDT场景编辑器 快速搭建3D应用场景 LlamaIndex是基于大型语言模型(LLM)的应用程序的数据框架。像 GPT-4 这样的 LLM 是在大量公共数据集上预先训练的,允许开箱即用的令人难以置信的自然语言处理能力。但是,…

HTML的段落中怎么样显示出标签要使用的尖括号<>?

很简单&#xff1a; 符号 < 用 < 替代&#xff1b; 符号 > 用 > 替代。 示例代码如下&#xff1a; <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>HTML中怎样打出尖括号</title> </head> <b…

AP3266 大功率同步降压恒流芯片 双路并用大电流LED车灯驱动线路 过EMC

产品描述 AP3266 是高效率、外围简单、内置功率管的同步降压恒流芯片&#xff0c;适用于4-40V输入的降压LED恒流驱动芯片。输出最大功率可达 40W&#xff0c;最大电流3.6A。AP3266 可通过调节 OVP 端口的分压电阻&#xff0c;设定输出空载电压 保护&#xff0c;避免高压 空载上…

【数据库事务日志碎片原理分析与方案】-深入解析篇.pdf

日志增长与 VLF 文件的个数 通过上面的相关内容的介绍&#xff0c;我们已经知道了日志文件自动的增长会到了一些问 题&#xff0c;而事实确实如此&#xff0c;下面&#xff0c;我们就来更加清楚的看看这些问题。 很显然&#xff0c;我们不希望日志文件任意的增长&#xff0c;…

外汇交易技巧分享:利用MT4交易平台进行精准的外汇技术分析

在外汇交易市场中&#xff0c;技术分析是一种重要的决策工具&#xff0c;能够帮助交易者预测价格走势和制定交易策略。而MT4交易平台作为一种功能强大、广泛应用的交易软件&#xff0c;为交易者提供了丰富的技术分析工具和功能。本文将与大家分享几个利用MT4交易平台(可在mtw.s…

Revit SDK 介绍:CreateAirHandler 创建户式风管机

前言 这个例子介绍如何通过 API 创建一个户式风管机族的内容&#xff0c;包含几何和接头。 内容 效果 核心逻辑 必须打开机械设备的族模板创建几何实体来表示风管机创建风机的接头 创建几何实体来表示风管机 例子中创建了多个拉伸&#xff0c;下面仅截取一段代码&#xff…

vue2 vuex

一、Vuex 概述 Vuex 是一个 Vue 的 状态管理工具&#xff0c;状态就是数据。 大白话&#xff1a;Vuex 是一个插件&#xff0c;可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。 使用场景 某个状态 在 很多个组件 来使用 (个人信息) 多个组件 共同维护 一份数据 (购物车) …

虚函数、纯虚函数、多态

一.虚函数 在基类的函数前加上virtual关键字&#xff0c;在派生类中重写该函数&#xff0c;运行时将会根据所指对象的实际类型来调用相应的函数&#xff0c;如果对象类型是派生类&#xff0c;就调用派生类的函数&#xff0c;如果对象类型是基类&#xff0c;就调用基类的函数。 …

蓝桥杯打卡Day5

文章目录 日志排序重复者 一、日志排序IO链接 本题思路:本题就是根据就是排序的知识点&#xff0c;在sort内部可以使用仿函数来改变此时排序规则。 #include <bits/stdc.h>const int N10010; int n; std::string logs[N];int main() {std::ios::sync_with_stdio(false)…

java网络编程,套接字socket

目录 一 网络概述 二 网络的类型分类 三 网络体系结构 四 网络通信协议概述 五 网络通信协议种类 六 Socket简介 七 Socket路径 八 java网络编程三要素 九 基于UDP协议的Socket编程 十 基于TCP协议的Socket编程 十一 基于TCP协议和UDP的区别 一 网络概述 多台相互连…

Docker 的常用命令

0 基本命令 概述 [root192 home]# docker --helpUsage: docker [OPTIONS] COMMANDA self-sufficient runtime for containersOptions:--config string Location of client configfiles (default "/root/.docker")-c, --context string Name of the context…

【ES】笔记-Class类剖析

Class Class介绍与初体验ES5 通过构造函数实例化对象ES6 通过Class中的constructor实列化对象 Class 静态成员实例对象与函数对象的属性不相通实例对象与函数对象原型上的属性是相通的Class中对于static 标注的对象和方法不属于实列对象&#xff0c;属于类。 ES5构造函数继承Cl…

【Linux】环境变量

环境变量 一、引子echo $NAME [NAME:环境变量名] 二、基本概念概念常见的环境变量PATH : 指定命令的搜索路径测试HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的家目录)SHELL : 当前Shell,它的值通常是/bin/bash。 和环境变量相关的命令echo -- 显示某个环境变…

[html]当网站搭建、维护的时候,你会放个什么界面?

效果图&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>网站建设中</title><style>/* 基础样式 */body, html {margin: 0;padding: 0;height: 100%;font-family: Arial, sa…

Stable Diffusion stable-diffusion-webui ControlNet Lora

Stable Diffusion Stable Diffusion用来文字生成图片&#xff0c;ControlNet就是用来控制构图的&#xff0c;LoRA就是用来控制风格的 。 stable-diffusion-webui 国内加速官网&#xff1a; mirrors / AUTOMATIC1111 / stable-diffusion-webui GitCode 安装参考&#xff1a…

OpenCV(三十一):形态学操作

​​​​​​1.形态学操作 OpenCV 提供了丰富的函数来进行形态学操作&#xff0c;包括腐蚀、膨胀、开运算、闭运算等。下面介绍一些常用的 OpenCV 形态学操作函数&#xff1a; 腐蚀操作&#xff08;Erosion&#xff09;&#xff1a; erode(src, dst, kernel, anchor, iteration…

Wireshark技巧[监听串口包]

监听串口包 本文摘录于&#xff1a;https://blog.csdn.net/qq_20405005/article/details/79652927只是做学习备份之用&#xff0c;绝无抄袭之意&#xff0c;有疑惑请联系本人&#xff01; 这里要保证安装了USBpcap: 打开USBpcap后一半都要输入过滤条件,否则USB太多数据了,比如…

PHP实现微信小程序状态检测(违规、暂停服务、维护中、正在修复)

实现原理 进入那些状态不正常的小程序会被重定向至一个Url&#xff0c;使用抓包软件抓取这个Url&#xff0c;剔除不必要参数&#xff0c;使用cURl函数请求网页获得HTML内容&#xff0c;根据内容解析出当前APPID的小程序的状态。 代码 <?php// 编码header(Content-type:ap…

正弦信号的平均功率和峰值电压计算举例

正弦信号的平均功率和峰值电压计算举例 一、问题 假设加载在纯电阻为R1Ω&#xff0c;频率为50Hz和60Hz的正弦信号的平均功率分别为0.5W和2W,请求解这两个信号的峰值电压 U p 1 U_{p1} Up1​和 U p 2 U_{p2} Up2​。 二、解答&#xff1a; 根据欧姆定律可知&#xff1a;对于…