• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2# 使用HiDumper命令行工具优化性能
3
4## 简介
5
6HiDumper是OpenHarmony为开发、测试人员、IDE工具提供的系统信息获取工具,帮助开发者分析、定位问题。在应用开发过程中,开发者可以使用Hidumper命令行工具获取UI界面组件树信息,配合ArkUI Inspector等图形化工具定位布局性能问题;还可以使用该命令行工具获取如内存和CPU使用情况等各项系统数据,对应用性能进行评估。本文通过一些示例介绍在优化应用性能过程中如何使用Hidumper命令行工具。
7
8开发者可参考下面步骤,通过使用HiDumper提供的-s、--mem、--cpuusage等命令进行性能分析。有关HiDumper其他功能的详细介绍可查看[《HiDumper概述》](../../device-dev/subsystems/subsys-dfx-hidumper.md)。
9
10
11## HiDumper查看组件信息
12
13开发者可以按照以下步骤获取组件信息,相比ArkUI Inspector可更灵活的获取组件的细粒度信息。
14
151. 开启ArkUI的debug模式。
16    ```
17    hdc shell param set persist.ace.debug.enabled 1
18    ```
192. 重新启动应用。
203. 获取当前页面对应应用的window ID。
21    ```
22    hdc shell hidumper -s WindowManagerService -a '-a'
23    ```
24
25   ![WinId](figures/hidumper-winid.PNG)
26
27
28   * `hidumper -s`: 导出系统全部的元能力信息。
29   * `hidumper -s WindowManagerService -a ['-a']`: 以 `-a` 为参数导出当前设备打开的窗口的系统元能力信息,其中 `-a` 表示执行打印操作,`['-a']` 表示打印的具体信息。
30   * `WindowName`: 表示当前打开应用的窗口名,其中 `demo0` 为示例应用的默认窗口名。
31   * 常见的WindowName与内置应用窗口对应关系如下:
32
33     | WindowName           | 说明   |
34     |----------------------|------|
35     | EntryView            | 桌面   |
36     | RecentView           | 最近任务 |
37     | SystemUi_NavigationB | 三键导航 |
38     | SystemUi_StatusBar   | 状态栏  |
39     | ScreenLockWindow     | 锁屏   |
40
414. 通过WinId获取对应页面的控件树文件
42   ```
43   hdc shell hidumper -s WindowManagerService -a '-w 28 -element -c' // 28 即为查找到的WinId
44   ```
45
46   ![FilePath](figures/hidumper-filepath.PNG)
47
48
495. 下载组件树文件到本地。由于安全机制此处的路径非真实路径,需要使用 `find` 命令查找对应文件的准确路径。
50   ```
51   hdc shell find /data/ -name arkui.dump
52   ```
53
54   ![CorrectFilePath2](figures/hidumper-filepath2.PNG)
55
56   ```
57   hdc file recv /data/app/el2/100/base/com.example.demo/haps/entry/files/arkui.dump . // 获取文件到本地
58   ```
596. 打开文件查看应用组件树。组件树文件详细列出了每个组件的各项属性,如子组件数量childSize、组件ID、背景色BackgroundColor等。
60   ```
61   // arkui.dump文件内容片断
62   |-> GridItem childSize:1
63     | ID: 22
64     | Depth: 9
65     | IsDisappearing: 0
66     | FrameRect: RectT (360.00, 0.00) - [180.00 x 29.00]
67     | BackgroundColor: #00000000
68     ...
69     |-> Stack childSize:1
70       | ID: 23
71       | Depth: 10
72       | IsDisappearing: 0
73       | FrameRect: RectT (0.00, 0.00) - [180.00 x 29.00]
74       | BackgroundColor: #FFFFFF00
75       ...
76       |-> Stack childSize:1
77         | ID: 24
78         | Depth: 11
79         | IsDisappearing: 0
80         | FrameRect: RectT (0.00, 0.00) - [180.00 x 29.00]
81         | BackgroundColor: #FF0000FF
82         ...
83         |-> Stack childSize:1
84           | ID: 25
85           | Depth: 12
86           | IsDisappearing: 0
87           | FrameRect: RectT (0.00, 0.00) - [180.00 x 29.00]
88           | BackgroundColor: #00000000
89           ...
90           |-> Text childSize:0
91               ID: 26
92               Depth: 13
93               IsDisappearing: 0
94               FrameRect: RectT (83.00, 0.00) - [14.00 x 29.00]
95               BackgroundColor: #00000000
96               ...
97   ```
98
99### 查看if/else控件
100
101当使用if/else时,if/else语句会被当成一个组件,作为节点存在于组件树上。使用HiDumper命令时,打印的组件树内容包含if/else组件信息(使用ArkUI Inspector工具,if/else组件不会被作为节点项显示在组件树上)。下述代码中通过if语句: `if(this.isShow)` 实现Row组件的创建和销毁。
102```
103@Entry
104@Component
105struct ConditionComponent {
106  @State isShow: boolean = true;
107
108  build() {
109    Column() {
110      Button("显隐切换")
111        .onClick(() => {
112          this.isShow = !this.isShow
113        })
114      if (this.isShow) {
115        Row()
116          .width(300).height(300).backgroundColor(Color.Pink)
117      }
118    }.width('100%')
119  }
120}
121```
122当isShow为true时,Row组件显示,此时使用HiDumper查看组件树文件,可以发现使用if/else条件语句时,if/else组件也被当作节点被创建,Row组件被当作子组件嵌套在其中。
123```
124|-> IfElse childSize:1
125  | ID: 9
126  | Depth: 6
127  | IsDisappearing: 0
128  |-> Row childSize:0
129      ID: 12
130      Depth: 7
131      IsDisappearing: 0
132      FrameRect: RectT (135.00, 60.00) - [450.00 x 450.00]
133      BackgroundColor: #FFFFC0CB
134      ParentLayoutConstraint: minSize: [[0.00 x 0.00]]maxSize: [[720.00 x 1136.00]]percentReference: [[720.00 x 1136.00]]parentIdealSize: [[720.00 x NA]]selfIdealSize: [[NA x NA]]
135      top: 60.000000 left: 135.000000
136      Active: 1
137      Visible: 0
138      ...
139```
140当isShow为false时,Row组件隐藏,此时使用HiDumper查看组件树文件,可以发现使用if/else条件语句时,if/else组件也被当作节点被创建,但Row组件并不会被加载。
141```
142|-> IfElse childSize:0
143    ID: 9
144    Depth: 6
145    IsDisappearing: 0
146```
147
148### 查看visibility属性
149
150开发者可以使用visibility属性控制组件的显隐。下述代码中通过visibility属性: `visibility(this.isVisible)` 实现Row组件的显示和隐藏。
151```
152@Entry
153@Component
154struct VisibilityComponent {
155  @State isVisible: Visibility = Visibility.Visible;
156
157  build() {
158    Column() {
159      Button("Visible")
160        .onClick(() => {
161          this.isVisible = Visibility.Visible
162        })
163      Button("Hidden")
164        .onClick(() => {
165          this.isVisible = Visibility.Hidden
166        })
167      Button("None")
168        .onClick(() => {
169          this.isVisible = Visibility.None
170        })
171      Row().visibility(this.isVisible)
172        .width(720).height(300).backgroundColor(Color.Pink)
173    }.width('100%')
174  }
175}
176```
177当isVisible为Visible时,Row组件显示,此时使用HiDumper查看控件树文件,Visible属性为0,FrameRect属性内组件的宽和高为450。
178```
179|-> Row childSize:0
180    ID: 13
181    Depth: 6
182    IsDisappearing: 0
183    FrameRect: RectT (135.00, 180.00) - [450.00 x 450.00]
184    BackgroundColor: #FFFFC0CB
185    ParentLayoutConstraint: minSize: [[0.00 x 0.00]]maxSize: [[720.00 x 1136.00]]percentReference: [[720.00 x 1136.00]]parentIdealSize: [[720.00 x NA]]selfIdealSize: [[NA x NA]]
186    top: 180.000000 left: 135.000000
187    Active: 1
188    Visible: 0
189    ...
190```
191当isVisible为Hidden时,Row组件隐藏,此时使用HiDumper查看控件树文件,Visible属性为1,FrameRect属性内组件的宽和高为450。
192```
193|-> Row childSize:0
194    ID: 13
195    Depth: 6
196    IsDisappearing: 0
197    FrameRect: RectT (135.00, 180.00) - [450.00 x 450.00]
198    BackgroundColor: #FFFFC0CB
199    ParentLayoutConstraint: minSize: [[0.00 x 0.00]]maxSize: [[720.00 x 1136.00]]percentReference: [[720.00 x 1136.00]]parentIdealSize: [[720.00 x NA]]selfIdealSize: [[NA x NA]]
200    top: 180.000000 left: 135.000000
201    Active: 1
202    Visible: 1
203    ...
204```
205当isVisible为None时,Row组件隐藏,此时使用HiDumper查看控件树文件,Visible属性为2,FrameRect属性内组件的宽和高为0。
206```
207|-> Row childSize:0
208    ID: 13
209    Depth: 6
210    IsDisappearing: 0
211    FrameRect: RectT (135.00, 180.00) - [0.00 x 0.00]
212    BackgroundColor: #FFFFC0CB
213    ParentLayoutConstraint: minSize: [[0.00 x 0.00]]maxSize: [[720.00 x 1136.00]]percentReference: [[720.00 x 1136.00]]parentIdealSize: [[720.00 x NA]]selfIdealSize: [[NA x NA]]
214    top: 180.000000 left: 135.000000
215    Active: 1
216    Visible: 2
217    ...
218```
219对比三种情况的组件数可以发现:
220* 当使用visibility属性控制组件显隐时,该组件通过改变Visible属性实现功能,但组件的其他结构依然会被创建。
221* 当visibility属性为Hidden时,组件虽然不会显示,但仍然在页面中占用实际位置。
222
223## HiDumper查看内存信息
224
225开发者可以通过以下步骤,获取到当前应用的内存信息。
226
2271. 打开示例应用,运行 `hdc shell hidumper -s WindowManagerService -a '-a'` ,获取到当前应用的pid。
2282. 输入 `hidumper --mem [pid]` ,并将命令中的 `[pid]` 换成当前应用的pid,就可以获取到示例应用的内存信息了,如下图所示:
229```
230hdc shell hidumper --mem [pid]
231```
232
233![内存信息](figures/hidumper-mem.png)
234
235一般情况下,开发者只需要关注PSS (Proportional Set Size(实际使用物理内存))Total一列的数据,即示例应用实际使用的物理内存。在上图中可以看到,应用总共占用了53395KB的内存,主要包括ark ts heap(ArkUI堆内存)的3411KB以及native heap的45846KB。
236
237## HiDumper查看CPU信息
238
239在应用开发中,经常会遇到需要大量计算的场景,HiDumper提供了查看CPU使用率的功能,方便开发者进行性能优化。下面将以[Chat](https://gitee.com/openharmony/applications_app_samples/tree/master/code/Solutions/IM/Chat)为例,展示如何使用HiDumper查看CPU信息。
240
2411. 编译项目、安装并打开Chat应用,运行以下hidumper命令获取当前应用的Pid。
242    ```
243    hdc shell hidumper -s WindowManagerService -a '-a'
244    ```
2452. 运行 `hidumper --cpuusage [pid]` ,获取Chat应用的CPU信息,如下图所示:
246    ```
247    hdc shell hidumper --cpuusage [pid]
248    ```
249
250    ![CPU信息](figures/hidumper-cpu.png)
251
252    一般情况下,只需要关注Total Usage(总使用率)、User Space(用户程序的运行空间)、Kernel Space(内核的运行空间)。其中,Total Usage用于统计应用的总CPU使用率,User Space用于执行简单的运算,Kernel Space用于调用系统的资源。通过上图可以看到,当前示例的三项数据分别是11%,11%,0%,表示当前应用并没有调用系统资源,只需要查看应用的运行空间即可。如果想要查看CPU在一段时间内的使用率,则可以通过Shell脚本,多次执行 `hdc shell hidumper --cpuusage [pid]` 命令,并通过 `hdc shell hidumper --zip --cpuusage` 将结果输出到手机的/data/log/hidumper目录下,方便进行分析。