• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用HiTraceMeter跟踪性能(ArkTS)
2
3<!--Kit: Performance Analysis Kit-->
4<!--Subsystem: HiviewDFX-->
5<!--Owner: @qq_437963121-->
6<!--Designer: @kutcherzhou1; @MontSaintMichel-->
7<!--Tester: @gcw_KuLfPSbe-->
8<!--Adviser: @foryourself-->
9
10## 简介
11
12HiTraceMeter提供系统性能打点接口。开发者在关键代码位置调用这些API,能够有效跟踪进程轨迹,查看系统和应用性能。
13
14
15## 接口说明
16
17性能打点跟踪接口由HiTraceMeter模块提供,详细API请参考[@ohos.hiTraceMeter (性能打点) ArkTS API参考](../reference/apis-performance-analysis-kit/js-apis-hitracemeter.md)。
18
19| 接口名 | 描述 |
20| -------- | -------- |
21| hiTraceMeter.startSyncTrace(level: HiTraceOutputLevel, name: string, customArgs?: string): void | 开启一个同步时间片跟踪事件,分级控制跟踪输出。<br/>**说明**:从API version 19开始,支持该接口。 |
22| hiTraceMeter.finishSyncTrace(level: HiTraceOutputLevel): void | 结束一个同步时间片跟踪事件,分级控制跟踪输出。<br/>level必须与流程开始的startSyncTrace()对应参数值保持一致。<br/>**说明**:从API version 19开始,支持该接口。 |
23| hiTraceMeter.startAsyncTrace(level: HiTraceOutputLevel, name: string, taskId: number, customCategory: string, customArgs?: string): void | 开启一个异步时间片跟踪事件,分级控制跟踪输出。<br/>taskId是trace中用来表示关联的ID,如果有多个name相同的任务并行执行,则开发者每次调用startAsyncTrace()时,传入的taskId需不同;如果具有相同name的任务是串行执行的,则taskId可以相同。<br/>**说明**:从API version 19开始,支持该接口。 |
24| hiTraceMeter.finishAsyncTrace(level: HiTraceOutputLevel, name: string, taskId: number): void | 结束一个异步时间片跟踪事件,分级控制跟踪输出。<br/>level、name和taskId必须与流程开始的startAsyncTrace()对应参数值保持一致。<br/>**说明**:从API version 19开始,支持该接口。 |
25| hiTraceMeter.traceByValue(level: HiTraceOutputLevel, name: string, count: number): void | 整数跟踪事件,分级控制跟踪输出。<br/>name和count两个参数分别用来标记一个跟踪的整数变量名及整数值。<br/>**说明**:从API version 19开始,支持该接口。 |
26| hiTraceMeter.isTraceEnabled(): boolean | 判断当前是否开启应用trace捕获。<br/>使用hitrace命令行工具等方式开启采集时返回true。未开启采集或停止采集后返回false,此时调用HiTraceMeter性能跟踪打点接口无效。<br/>**说明**:从API version 19开始,支持该接口。 |
27
28> **注意:**
29>
30> [用户态trace格式](hitracemeter-view.md#用户态trace格式说明)使用竖线 | 作为分隔符,所以通过HiTraceMeter接口传递的字符串类型参数应避免包含该字符,防止trace解析异常。
31
32
33### 接口分类
34
35HiTraceMeter打点接口分为三类:同步时间片跟踪、异步时间片跟踪和整数跟踪。HiTraceMeter接口实现均为同步,同步和异步针对的是被跟踪的业务。同步业务使用同步时间片跟踪接口,异步业务使用异步时间片跟踪接口。HiTraceMeter打点接口可与[HiTraceChain](hitracechain-guidelines-arkts.md)一起使用,进行跨设备、跨进程或跨线程的打点关联与分析。
36
37
38### 接口使用场景
39
40- 同步时间片跟踪接口
41  用于顺序执行的打点场景,需按序成对使用startSyncTrace()接口和finishSyncTrace()接口,否则会导致trace文件在smartperf等可视化工具上显示异常。
42
43- 异步时间片跟踪接口
44  在异步操作执行前调用startAsyncTrace()接口进行开始打点,在异步操作完成后调用finishAsyncTrace()接口进行结束打点。
45  解析trace时,通过name和taskId参数识别不同的异步跟踪。这两个接口必须按序成对使用,并传入相同的name和taskId。
46  不同的异步流程中应使用不同的name和taskId,但在异步跟踪流程不会同时发生的情况下,可以使用相同的name和taskId。
47  调用错误会导致trace文件在smartperf等可视化工具上显示异常。
48
49- 整数跟踪接口
50  用于跟踪整数变量。整数值变动时调用traceByValue()接口,可在smartperf的泳道图中观察变动情况。由于从开始采集到首次打点存在时间差,这段时间的数值无法查看。
51
52
53### 参数解析
54
55| 参数名 | 类型 | 必填 | 说明 |
56| -------- | -------- | -------- | -------- |
57| level | enum | 是 | 跟踪输出级别。低于系统阈值的跟踪将不会被输出。<br/>log版本阈值默认为INFO,nolog版本阈值默认为COMMERCIAL。 |
58| name | string | 是 | 要跟踪的任务名称或整数变量名称。 |
59| taskId | number | 是 | 用来表示关联的ID,如果有多个name相同的任务并行执行,则开发者每次调用startAsyncTrace()时,传入的taskId需不同。 |
60| count | number | 是 | 整数变量的值。 |
61| customCategory | string | 是 | 自定义聚类名称,用于聚合同一类异步跟踪打点。<br/>若不需要聚类,可传入一个空字符串。 |
62| customArgs | string | 否 | 自定义键值对,若有多组键值对,使用逗号进行分隔,例"key1=value1,key2=value2"。<br/>若不需要该参数,可不传入该参数或传入一个空字符串。 |
63
64> **说明:**
65>
66> [用户态trace](hitracemeter-view.md#用户态trace格式说明)总长度限制为512字符,超过部分将会被截断。建议name、customCategory和customArgs三个字段的总长度不超过420字符,以避免trace被截断。
67
68
69## 开发步骤
70
71以下为一个使用HiTraceMeter打点接口的ArkTS应用示例。
72
73
74### 步骤一:创建项目
75
761. 在DevEco Studio中新建工程,选择“Empty Ability”,工程的目录结构如下。
77
78   ```text
79   ├── entry
80   │   ├── src
81   │       ├── main
82   │       │   ├── ets
83   │       │   │   ├── entryability
84   │       │   │   │   └── EntryAbility.ets
85   │       │   │   ├── entrybackupability
86   │       │   │   │   └── EntryBackupAbility.ets
87   │       │   │   └── pages
88   │       │   │       └── Index.ets
89   ```
90
912. 编辑“entry &gt; src &gt; main &gt; ets &gt; pages &gt; Index.ets”文件,在文本点击事件处理业务中使用HiTraceMeter性能跟踪打点接口,完整的示例代码如下。
92
93   ```ts
94   import { hiTraceMeter, hilog } from '@kit.PerformanceAnalysisKit';
95
96   @Entry
97   @Component
98   struct Index {
99     @State message: string = 'Hello World';
100
101     build() {
102       Row() {
103         Column() {
104           Text(this.message)
105             .fontSize(50)
106             .fontWeight(FontWeight.Bold)
107             .onClick(() => {
108               this.message = (this.message == 'Hello HiTrace') ? 'Hello World' : 'Hello HiTrace';
109               const COMMERCIAL = hiTraceMeter.HiTraceOutputLevel.COMMERCIAL;
110
111               let traceCount = 0;
112               // 第一个异步跟踪任务开始
113               hiTraceMeter.startAsyncTrace(COMMERCIAL, 'myTestAsyncTrace', 1001, 'categoryTest', 'key=value');
114               // 开始计数任务
115               traceCount++;
116               hiTraceMeter.traceByValue(COMMERCIAL, 'myTestCountTrace', traceCount);
117               // 业务流程
118               hilog.info(0x0000, 'testTrace', 'myTraceTest running, taskId: 1001');
119
120               // 第二个异步跟踪任务开始,同时第一个跟踪的同名任务还没结束,出现了并行执行,对应接口的taskId需要不同
121               hiTraceMeter.startAsyncTrace(COMMERCIAL, 'myTestAsyncTrace', 1002, 'categoryTest', 'key=value');
122               // 开始计数任务
123               traceCount++;
124               hiTraceMeter.traceByValue(COMMERCIAL, 'myTestCountTrace', traceCount);
125               // 业务流程
126               hilog.info(0x0000, 'testTrace', 'myTraceTest running, taskId: 1002');
127
128               // 结束taskId为1001的异步跟踪任务
129               hiTraceMeter.finishAsyncTrace(COMMERCIAL, 'myTestAsyncTrace', 1001);
130               // 结束taskId为1002的异步跟踪任务
131               hiTraceMeter.finishAsyncTrace(COMMERCIAL, 'myTestAsyncTrace', 1002);
132
133               // 开始同步跟踪任务
134               hiTraceMeter.startSyncTrace(COMMERCIAL, 'myTestSyncTrace', 'key=value');
135               // 业务流程
136               hilog.info(0x0000, 'testTrace', 'myTraceTest running, synchronizing trace');
137               // 结束同步跟踪任务
138               hiTraceMeter.finishSyncTrace(COMMERCIAL);
139
140               // 若通过HiTraceMeter性能打点接口传递的参数的生成过程比较复杂,此时可以通过isTraceEnabled判断当前是否开启应用trace捕获,
141               // 在未开启应用trace捕获时,避免该部分性能损耗
142               if (hiTraceMeter.isTraceEnabled()) {
143                   let customArgs = 'key0=value0';
144                   for(let index = 1; index < 10; index++) {
145                       customArgs += `,key${index}=value${index}`
146                   }
147                   hiTraceMeter.startAsyncTrace(COMMERCIAL, 'myTestAsyncTrace', 1003, 'categoryTest', customArgs);
148                   hilog.info(0x0000, 'testTrace', 'myTraceTest running, taskId: 1003');
149                   hiTraceMeter.finishAsyncTrace(COMMERCIAL, 'myTestAsyncTrace', 1003);
150               } else {
151                   hilog.info(0x0000, 'testTrace', 'myTraceTest running, trace is not enabled');
152               }
153             })
154          }
155          .width('100%')
156        }
157        .height('100%')
158      }
159   }
160   ```
161
162
163### 步骤二:采集trace信息并查看
164
1651. 在DevEco Studio Terminal窗口中执行以下命令,开启应用的trace捕获。
166
167   ```shell
168   PS D:\xxx\xxx> hdc shell
169   $ hitrace --trace_begin app
170   ```
171
1722. 单击DevEco Studio界面上的运行按钮,启动应用。点击应用界面的“Hello World”文本,执行包含HiTraceMeter打点的业务逻辑。然后执行如下命令抓取trace数据,并使用“myTest”关键字过滤trace数据(示例打点接口传递的name字段前缀均为“myTest”)。
173
174   ```shell
175   $ hitrace --trace_dump | grep myTest
176   ```
177
178   成功抓取的trace数据如下所示:
179
180   ```text
181   e.myapplication-39945   (  39945) [010] .... 347921.342267: tracing_mark_write: S|39945|H:myTestAsyncTrace|1001|M62|categoryTest|key=value
182   e.myapplication-39945   (  39945) [010] .... 347921.342280: tracing_mark_write: C|39945|H:myTestCountTrace|1|M62
183   e.myapplication-39945   (  39945) [010] .... 347921.342327: tracing_mark_write: S|39945|H:myTestAsyncTrace|1002|M62|categoryTest|key=value
184   e.myapplication-39945   (  39945) [010] .... 347921.342333: tracing_mark_write: C|39945|H:myTestCountTrace|2|M62
185   e.myapplication-39945   (  39945) [010] .... 347921.342358: tracing_mark_write: F|39945|H:myTestAsyncTrace|1001|M62
186   e.myapplication-39945   (  39945) [010] .... 347921.342365: tracing_mark_write: F|39945|H:myTestAsyncTrace|1002|M62
187   e.myapplication-39945   (  39945) [010] .... 347921.342387: tracing_mark_write: B|39945|H:myTestSyncTrace|M62|key=value
188   e.myapplication-39945   (  39945) [010] .... 347921.342586: tracing_mark_write: S|39945|H:myTestAsyncTrace|1003|M62|categoryTest|key0=value0,key1=value1,key2=value2,key3=value3,key4=value4,key5=value5,key6=value6,key7=value7,key8=value8,key9=value9
189   e.myapplication-39945   (  39945) [010] .... 347921.342615: tracing_mark_write: F|39945|H:myTestAsyncTrace|1003|M62
190   ```
191
192   每一行trace数据中,tracing_mark_write为打点事件类型,应用程序中调用HiTraceMeter接口打点使用的均为此事件。打点事件类型前面的数据分别为线程名-线程ID、进程ID、CPU和打点时间(从开机到当前的时间,单位为秒);打点事件类型后面的数据可查看[用户态trace格式](hitracemeter-view.md#用户态trace格式说明)。
193
194
195### 步骤三:停止采集trace
196
197
1981. 执行以下命令,停止应用的trace捕获。
199
200   ```shell
201   $ hitrace --trace_finish
202   ```
203
2042. 再次点击应用界面的“Hello World”文本,此时应用trace捕获已关闭,isTraceEnabled()接口返回false。在DevEco Studio Log窗口使用关键字“not enabled”进行过滤,会打印如下日志。
205
206   ```text
207   myTraceTest running, trace is not enabled
208   ```
209
210   > **说明:**
211   >
212   > log版本在使用hitrace --trace_finish命令停止采集后会自动拉起快照模式,打开trace捕获,此时isTraceEnabled()接口返回true,不会打印上述日志。
213