鸿蒙系列-如何使用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.mzph.cn/news/73983.shtml

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

相关文章

使用GPU虚拟化技术搭建支持3D设计的职校学生机房(云教室)

背景 学校为职业学校,计算机教室需要进行Maya、Adobe Illustrator、Adobe Dreamweaver、Adobe PhotoShop等软件的教学。每个教室为35用户。资源需求为4核、8G内存、80G硬盘。 基于桌面虚拟化VDI技术的机房在成本、可管理性方面,相对于传统胖终端的机房…

华为认证系统学习大纲及课程

前言 任何学习过程都需要一个科学合理的学习路线,才能够有条不紊的完成我们的学习目标。华为认证网络工程师所需学习的内容纷繁复杂,难度较大,所以今天特别为大家整理了一个全面的华为认证网络工程师学习大纲及课程,帮大家理清思…

更健康舒适更科技的照明体验!书客SKY护眼台灯SUKER L1上手体验

低价又好用的护眼台灯是多数人的需求,很多人只追求功能性护眼台灯,显色高、无频闪、无蓝光等基础需求。但是在较低价格中很难面面俱到,然而刚发布的SUKER书客L1护眼台灯却是一款不可多得的性价比护眼台灯,拥有高品质光源&#xff…

前端实现展开收起的效果 (react)

需求背景:需要实现文本的展开收起效果,文本是一行一行的,数据格式是数组结构。 如图所示(图片已脱敏) 简单实现:使用一个变量控制展开收起效果。 展开收起逻辑部分(react) const […

国际版腾讯云阿里云免费开户:全站加快 DCDN 重磅发布!打造新一代加快引擎

腾讯云全站加快 DCDN 重磅发布!打造新一代加快引擎 在数字化转型革新逐渐深化的当下,安全高效成为企业上云、全球化布置的要害需求。 跟着运用场景复杂度不断提高、事务需求差异化开展,为了给企业供给更完善的安全加快服务,阿里云…

【Linux】VirtualBox安装Centos7

文章目录 下载并安装VirtualBox下载Centos镜像VirtualBox设置管理->全局设定:设定虚拟机默认安装路径工具->网络管理器:添加NetWork网络配置 VirtualBox安装CentOS7新建虚拟机,指定安装目录及名称,点击下一步指定虚拟机内存…

FGO:使用chaIdea获取抽卡数据(mitmproxy抓包)

需求描述 最近逛贴吧看到好多master贴出自己的抽卡概率截图,本非洲杂鱼master也对自己的脸黑程度产生了好奇(曾经15单芭娜娜池子1五星,6单道满池子1五星,梅莉池子330抽1五星,最近的芭娜娜复刻又330抽1五星&#xff09…

Dedecms最新版--0day分享分析(二)

前言 接上一篇的Tricks,既然利用远程文件下载方式成为了实现RCE的最好方法,毕竟在执行的时候没有恶意shell文件,恶意木马被存放于远端服务器,那么下文的day就是对远程恶意文件的利用。 环境 下载最新版本: https://…

Java从入门到精通-数组(二)

4.数组的基本操作 数组的基本操作包括遍历数组、填充替换数组元素、对数组进行排序、复制数组以及查询数组中的元素。 • 4.1 遍历数组 遍历数组是访问数组中所有元素的过程,通常使用循环完成。 使用 for 循环遍历数组: int[] numbers {1, 2, 3, 4…

Datax抽取mysql的bit类型数据

背景:使用datax抽取mysql的一张表,里面有两个bit类型的字段,抽取出来显示如下: 需要在抽取reader里面进行处理配置 最终生成的datax的json文件reader的配置会转换为具体的数值 最终查询效果:

UniTask保姆级教程

目录 一、UniTask的简介和安装 https://github.com/Cysharp/UniTask.gitpathsrc/UniTask/Assets/Plugins/UniTask 空载性能测试 二、基础用法详解 三、基础用法扩展 四、进阶 五、VContainer简介 六、VContainer基础实例 方便快速查找 一、UniTask的简介和安装 项目地…

信息安全保障

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

Spring学习笔记——3

Spring学习笔记——3 一、AOP简介1.1、AOP概述1.2、AOP思想的实现方案1.3、模拟AOP的基础代码1.4、AOP的相关概念 二、基于XML配置的AOP2.1、XML方式AOP快速入门2.2、XML方式AOP配置详解2.3、XML方式AOP原理剖析 三、基于注解配置AOP3.1、注解方式AOP基本使用3.2、注解方式AOP配…

手写Spring:第15章-通过注解注入属性信息

文章目录 一、目标:通过注解注入属性信息二、设计:通过注解注入属性信息三、实现:通过注解注入属性信息3.1 工程结构3.2 自动扫描注入占位符配置和对象类图3.3 读取属性并填充到容器中3.3.1 定义解析字符串接口3.3.2 配置Bean工厂添加解析器3…

基于Java+SpringBoot+Vue前后端分离农产品直卖平台设计和实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

手写签名到背景上合为1张图

手写签名到背景上合为1张图 package.json中 "signature_pad": "3.0.0-beta.3"<template><div class"home"><canvas id"canvas" width"500" height"300"></canvas><button click"…

ELK高级搜索(三)

文章目录 11&#xff0e;索引Index入门11.1 索引管理11.2 定制分词器11.3 type底层结构11.4 定制dynamic mapping11.5 零停机重建索引 12&#xff0e;中文分词器 IK分词器12.1 Ik分词器安装使用12.2 ik配置文件12.3 使用mysql热更新 13&#xff0e;java api 实现索引管理14&…

026:vue中el-progress逆向倒计时方式显示

第026个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

Redis多机数据库实现

Redis多机数据库实现 为《Redis设计与实现》笔记 复制 客户端可以使用SLAVEOF命令将指定服务器设置为该服务器的主服务器 127.0.0.1:12345> SLAVEOF 127.0.0.1 6379127.0.0.1:6379将被设置为127.0.0.1:123456的主服务器 旧版复制功能的实现 Redis的复制功能分为同步&a…

Linux之history、tab、alias、命令执行顺序、管道符以及exit

目录 Linux之history、tab、alias、命令执行顺序、管道符以及exit history历史命令 格式 参数 修改默认记录历史命令条数 案例 案例1 --- 显示history历史记录中出现次数最高的top10 案例2 --- 增加history显示的时间信息 命令与文件名补全 --- tab 命令别名 格式 案…