性能优化、启动优化、内存优化、FPS监测、性能分析
在鸿蒙OpenHarmony开发过程中,开发者开发的代码(Stage 模型)通常以调用 ArkUI 框架的代码为主,主要优化的代码部分也在其中,那么如何验证自己的代码是否起到了优化效果,就需要工具对比分析优化前和优化后的效果。
我们以一次测试过程为例,介绍如何分析性能。
测试方法:我们使用对比测试的方法,比较使用 RelativeContainer() 前后可以对比的性能指标,来证明合理使用布局是对性能提升有帮助的。
测试工具:DevEco 中的 Profiler 工具。
图标以此对应可以监测的场景有:启动、帧率、耗时、内存。
测试的关键点如下:
定义的颜色如下:
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行,效果如下:
不使用 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()
}
}
}
不使用 RelativeContainer() 的情况:
使用 RelativeContainer() 的情况:
定义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% |
验证嵌套层级深度对性能有影响。
对比如下数据:
对比项 | 启动分析(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.1ms | 512.4ms | 757.1ms |
occurrences | - | - | - | 68 | 47 | 68 |
FPS | - | - | - | 90 | 90 | 89 |
结论:从嵌套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)
// 10
TextBuilder(10)
TextBuilder(11)
TextBuilder(12)
TextBuilder(13)
TextBuilder(14)
TextBuilder(15)
TextBuilder(16)
TextBuilder(17)
TextBuilder(18)
TextBuilder(19)
// 20
TextBuilder(20)
TextBuilder(21)
TextBuilder(22)
TextBuilder(23)
TextBuilder(24)
TextBuilder(25)
TextBuilder(26)
TextBuilder(27)
TextBuilder(28)
TextBuilder(29)
// 30
TextBuilder(30)
TextBuilder(31)
TextBuilder(32)
TextBuilder(33)
TextBuilder(34)
TextBuilder(35)
TextBuilder(36)
TextBuilder(37)
TextBuilder(38)
TextBuilder(39)
// 40
TextBuilder(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)
// 10
Row() {
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)
//20
Row() {
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)
// 30
Row() {
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)
// 40
Row() {
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)
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}