• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Using HiTraceMeter (C/C++)
2
3<!--Kit: Performance Analysis Kit-->
4<!--Subsystem: HiviewDFX-->
5<!--Owner: @qq_437963121-->
6<!--Designer: @MontSaintMichel-->
7<!--Tester: @gcw_KuLfPSbe-->
8<!--Adviser: @foryourself-->
9
10## Overview
11
12HiTraceMeter provides APIs for system performance tracing. You can call the APIs at key code to track processes and check system and application performance.
13
14
15## Available APIs
16
17For details about the APIs, see [trace.h](../reference/apis-performance-analysis-kit/capi-trace-h.md).
18
19| API| Description|
20| -------- | -------- |
21| void OH_HiTrace_StartTraceEx(HiTrace_Output_Level level, const char\* name, const char\* customArgs) | Starts a synchronous time slice trace with the trace output level specified.<br>**Note**: This API is supported since API version 19.|
22| void OH_HiTrace_FinishTraceEx(HiTrace_Output_Level level) | Stops a synchronous time slice trace with the trace output level specified.<br>The value of **level** must be the same as that of **OH_HiTrace_StartTraceEx**.<br>**Note**: This API is supported since API version 19.|
23| void OH_HiTrace_StartAsyncTraceEx(HiTrace_Output_Level level, const char\* name, int32_t taskId, const char\* customCategory, const char\* customArgs) | Starts an asynchronous time slice trace with the trace output level specified.<br>If multiple tracing tasks with the same name need to be performed at the same time, different task IDs must be specified through **taskId**. If the tracing tasks with the same name are not performed at the same time, the same task ID can be used.<br>**Note**: This API is supported since API version 19.|
24| void OH_HiTrace_FinishAsyncTraceEx(HiTrace_Output_Level level, const char\* name, int32_t taskId) | Stops an asynchronous time slice trace with the trace output level specified.<br>Stops a tracing task. The values of **name** and **taskId** must be the same as those in **OH_HiTrace_StartAsyncTraceEx**.<br>**Note**: This API is supported since API version 19.|
25| void OH_HiTrace_CountTraceEx(HiTrace_Output_Level level, const char\* name, int64_t count) | Traces an integer with the trace output level specified.<br>**name** indicates the name of an integer variable to trace, and **count** indicates the integer value.<br>**Note**: This API is supported since API version 19.|
26| bool OH_HiTrace_IsTraceEnabled(void) | Checks whether application trace capture is enabled.<br>When it is enabled, **true** is returned; when it is disabled or stopped, **false** is returned. In this case, calling the HiTraceMeter API does not take effect.<br>**Note**: This API is supported since API version 19.|
27
28> **NOTE**
29>
30> The vertical bar (|) is used as the separator in [user-mode trace format](hitracemeter-view.md#user-mode-trace-format). Therefore, the string parameters passed by the HiTraceMeter APIs must exclude this character to avoid trace parsing exceptions.
31
32
33### API Category
34
35HiTraceMeter APIs are classified into three types: synchronous timeslice tracing APIs, asynchronous timeslice tracing APIs, and integer tracing APIs. HiTraceMeter APIs are synchronous. The synchronous and asynchronous modes describe the traced services. The synchronous timeslice tracing APIs are used for synchronous services, and the asynchronous timeslice tracing APIs are used for asynchronous services. HiTraceMeter APIs can be used with [HiTraceChain](hitracechain-guidelines-ndk.md) to associate and analyze logging across devices, processes, or threads.
36
37
38### Use Scenarios
39
40
41- Synchronous timeslice tracing APIs:
42  The **OH_HiTrace_StartTraceEx** and **OH_HiTrace_FinishTraceEx** APIs must be used sequentially for logging during sequential execution. If they are not called in the correct order, the trace file will appear abnormal in visualization tools such as SmartPerf.
43
44- Asynchronous timeslice tracing APIs:
45  The **OH_HiTrace_StartAsyncTraceEx** API is called to start logging before an asynchronous operation is performed, and the **OH_HiTrace_FinishAsyncTraceEx** API is called to end logging after the asynchronous operation is performed.
46  During trace parsing, different asynchronous traces are identified by the **name** and **taskId** parameters. These two APIs must be used in sequence as a pair, with the same **name** and **taskId** passed.
47  Different **name** and **taskId** values must be used for different asynchronous processes. However, the same **name** and **taskId** values can be used if asynchronous processes do not occur at the same time.
48  If the API is called incorrectly, the trace file will appear abnormal in visualization tools such as SmartPerf.
49
50- Integer tracing APIs:
51  The APIs are used to trace integer variables. The **OH_HiTrace_CountTraceEx** API is called when integer values change. You can view the change in the lane diagram of SmartPerf. The values during the interval between the start of data collection and the first logging cannot be viewed.
52
53
54### Parameter Description
55
56
57| Name| Type| Description|
58| -------- | -------- | -------- |
59| level | enum | Trace output level. Trace data whose levels are lower than the system threshold will not be output.<br>The log version threshold is **HITRACE_LEVEL_INFO**, and the nolog version threshold is **HITRACE_LEVEL_COMMERCIAL**.|
60| name | const char\* | Name of the task or integer variable to trace.|
61| taskId | int32_t | Task ID. If multiple tasks with the same **name** are executed at the same time, you must set different **taskId** when calling **OH_HiTrace_StartAsyncTraceEx**.|
62| count | int64_t | Value of an integer variable.|
63| customCategory | const char\* | Custom category name, which is used to collect asynchronous trace data of the same type.<br>If the category is not required, pass in an empty string.|
64| customArgs | const char\* | Custom key-value pair. If there are multiple key-value pairs, separate them with commas (,), for example, **key1=value1,key2=value2**.<br>If this parameter is not required, pass in an empty string.|
65
66
67> **NOTE**
68>
69> The maximum length of a [user-mode trace](hitracemeter-view.md#user-mode-trace-format) is 512 characters. Excess characters will be truncated. Therefore, it is recommended that the total length of the **name**, **customCategory**, and **customArgs** fields be less than or equal to 420 characters.
70
71
72## How to Develop
73
74The following is an example of a native C++ application that uses the HiTraceMeter APIs.
75
76
77### Step 1: Creating a Project
78
79
801. Create a project in DevEco Studio and select **Native C++**. The project directory structure is as follows:
81
82   ```text
83   ├── entry
84   │   ├── src
85   │       ├── main
86   │       │   ├── cpp
87   │       │   │   ├── CMakeLists.txt
88   │       │   │   ├── napi_init.cpp
89   │       │   │   └── types
90   │       │   │       └── libentry
91   │       │   │           ├── Index.d.ts
92   │       │   │           └── oh-package.json5
93   │       │   ├── ets
94   │       │   │   ├── entryability
95   │       │   │   │   └── EntryAbility.ets
96   │       │   │   ├── entrybackupability
97   │       │   │   │   └── EntryBackupAbility.ets
98   │       │   │   └── pages
99   │       │   │       └── Index.ets
100   ```
101
1022. In the **entry/src/main/cpp/CMakeLists.tx** file, add **libhitrace_ndk.z.so** and **libhilog_ndk.z.so**. The complete file content is as follows:
103
104   ```cmake
105   # the minimum version of CMake.
106   cmake_minimum_required(VERSION 3.5.0)
107   project(HiTraceChainTest03)
108
109   set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
110
111   if(DEFINED PACKAGE_FIND_FILE)
112       include(${PACKAGE_FIND_FILE})
113   endif()
114
115   include_directories(${NATIVERENDER_ROOT_PATH}
116                       ${NATIVERENDER_ROOT_PATH}/include)
117
118   add_library(entry SHARED napi_init.cpp)
119   target_link_libraries(entry PUBLIC libace_napi.z.so libhitrace_ndk.z.so libhilog_ndk.z.so)
120   ```
121
1223. In the **entry/src/main/cpp/napi_init.cpp** file, call the HiTraceMeter NDK_C APIs in the **Add** function to trace performance. The sample code is as follows:
123
124   ```c++
125   #include <cstdio>
126   #include <cstring>
127
128   #include "hilog/log.h"
129   #include "hitrace/trace.h"
130   #include "napi/native_api.h"
131
132   #undef LOG_TAG
133   #define LOG_TAG "traceTest"
134
135   static napi_value Add(napi_env env, napi_callback_info info)
136   {
137       // Start the first asynchronous tracing task.
138       OH_HiTrace_StartAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestAsyncTrace", 1001, "categoryTest", "key=value");
139       // Start the counting task.
140       int64_t traceCount = 0;
141       traceCount++;
142       OH_HiTrace_CountTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestCountTrace", traceCount);
143       // Keep the service process running.
144       OH_LOG_INFO(LogType::LOG_APP, "myTraceTest running, taskId: 1001");
145
146       // Start the second asynchronous tracing task with the same name while the first task is still running. The tasks are running concurrently and therefore their taskId must be different.
147       OH_HiTrace_StartAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestAsyncTrace", 1002, "categoryTest", "key=value");
148       // Start the counting task.
149       traceCount++;
150       OH_HiTrace_CountTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestCountTrace", traceCount);
151       // Keep the service process running.
152       OH_LOG_INFO(LogType::LOG_APP, "myTraceTest running, taskId: 1002");
153
154       // Stop the asynchronous tracing task whose taskId is 1001.
155       OH_HiTrace_FinishAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestAsyncTrace", 1001);
156       // Stop the asynchronous tracing task whose taskId is 1002.
157       OH_HiTrace_FinishAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestAsyncTrace", 1002);
158
159       // Start a synchronous tracing task.
160       OH_HiTrace_StartTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestSyncTrace", "key=value");
161       // Keep the service process running.
162       OH_LOG_INFO(LogType::LOG_APP, "myTraceTest running, synchronizing trace");
163       // Stop the synchronous tracing task.
164       OH_HiTrace_FinishTraceEx(HITRACE_LEVEL_COMMERCIAL);
165
166       // If the process of generating the parameters passed by the HiTraceMeter API is complex, you can use isTraceEnabled to determine whether trace capture is enabled.
167       // Avoid performance loss when application trace capture is not enabled.
168       if (OH_HiTrace_IsTraceEnabled()) {
169           char customArgs[128] = "key0=value0";
170           for (int index = 1; index < 10; index++) {
171               char buffer[16];
172               snprintf(buffer, sizeof(buffer), ",key%d=value%d", index, index);
173               strncat(customArgs, buffer, sizeof(customArgs) - strlen(customArgs) - 1);
174           }
175           OH_HiTrace_StartAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestAsyncTrace", 1003, "categoryTest", customArgs);
176           OH_LOG_INFO(LogType::LOG_APP, "myTraceTest running, taskId: 1003");
177           OH_HiTrace_FinishAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, "myTestAsyncTrace", 1003);
178       } else {
179           OH_LOG_INFO(LogType::LOG_APP, "myTraceTest running, trace is not enabled");
180       }
181
182       size_t requireArgc = 2;
183       size_t argc = 2;
184       napi_value args[2] = {nullptr};
185
186       napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
187
188       napi_valuetype valuetype0;
189       napi_typeof(env, args[0], &valuetype0);
190
191       napi_valuetype valuetype1;
192       napi_typeof(env, args[1], &valuetype1);
193
194       double value0;
195       napi_get_value_double(env, args[0], &value0);
196
197       double value1;
198       napi_get_value_double(env, args[1], &value1);
199
200       napi_value sum;
201       napi_create_double(env, value0 + value1, &sum);
202
203       return sum;
204   }
205
206   EXTERN_C_START
207   static napi_value Init(napi_env env, napi_value exports)
208   {
209       napi_property_descriptor desc[] = {
210           { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }
211       };
212       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
213       return exports;
214   }
215   EXTERN_C_END
216
217   static napi_module demoModule = {
218       .nm_version = 1,
219       .nm_flags = 0,
220       .nm_filename = nullptr,
221       .nm_register_func = Init,
222       .nm_modname = "entry",
223       .nm_priv = ((void*)0),
224       .reserved = { 0 },
225   };
226
227   extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
228   {
229       napi_module_register(&demoModule);
230   }
231   ```
232
233
234### Step 2: Collecting and Viewing Trace Information
235
2361. Run the following command in DevEco Studio Terminal to enable trace capture:
237
238   ```shell
239   PS D:\xxx\xxx> hdc shell
240   $ hitrace --trace_begin app
241   ```
242
2432. Click the **Run** button in DevEco Studio to run the project. Then, click "Hello world" to execute the service logic that contains HiTraceMeter logging. Run the following command to capture trace data and filter the trace data using the keyword **myTest** (the name field prefix passed by the logging API is **myTest** in this example).
244
245   ```shell
246   $ hitrace --trace_dump | grep myTest
247   ```
248
249   The sample trace data is as follows:
250
251   ```text
252   <...>-49837   (-------) [002] .... 349137.708093: tracing_mark_write: S|49837|H:myTestAsyncTrace|1001|M62|categoryTest|key=value
253   <...>-49837   (-------) [002] .... 349137.708103: tracing_mark_write: C|49837|H:myTestCountTrace|1|M62
254   <...>-49837   (-------) [002] .... 349137.708201: tracing_mark_write: S|49837|H:myTestAsyncTrace|1002|M62|categoryTest|key=value
255   <...>-49837   (-------) [002] .... 349137.708209: tracing_mark_write: C|49837|H:myTestCountTrace|2|M62
256   <...>-49837   (-------) [002] .... 349137.708239: tracing_mark_write: F|49837|H:myTestAsyncTrace|1001|M62
257   <...>-49837   (-------) [002] .... 349137.708246: tracing_mark_write: F|49837|H:myTestAsyncTrace|1002|M62
258   <...>-49837   (-------) [002] .... 349137.708252: tracing_mark_write: B|49837|H:myTestSyncTrace|M62|key=value
259   <...>-49837   (-------) [002] .... 349137.708301: tracing_mark_write: S|49837|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
260   <...>-49837   (-------) [002] .... 349137.708323: tracing_mark_write: F|49837|H:myTestAsyncTrace|1003|M62
261   ```
262
263
264### Step 3: Stoping Trace Capture
265
2661. Run the following command to stop the application trace capture:
267
268   ```shell
269   $ hitrace --trace_finish
270   ```
271
2722. Click "Hello World" on the application screen again. The trace capture of the application is disabled, and the **OH_HiTrace_IsTraceEnabled** API returns **false**. In the **Log** window of the DevEco Studio, input the keyword **not enabled** for filtering and the following log is displayed.
273
274   ```text
275   myTraceTest running, trace is not enabled
276   ```
277
278   > **NOTE**
279   >
280   > In the log version, after the **hitrace --trace_finish** command is used to stop capture, the snapshot mode is automatically started and trace capture is enabled. In this case, the **isTraceEnabled** API returns **true**, and the preceding log is not printed.
281