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