1# CPU Profiler 2 3## Introduction 4 5CPU Profiler provides insights into your application's performance. It can measure the time spent in functions at different layers of the call stack without instrumentation, and display the profile data in the timeline. 6 7In this document, you can learn how to get the most out of this tool – inspect the timing and time consumption of TS/JS code and NAPI code, identify hotspot functions and performance bottlenecks, and make informed improvements. 8 9## Data Visualization 10 11Profile data from CPU Profiler can be visualized in two places: **DevEco Studio** > **Profiler** > **Time** > **ArkTS Callstack** and **Chrome** > **JavaScript Profiler**. The former provides two views: **ArkTS Callstack** and **Details**. The latter provides three views: **Chart**, **Heavy**, and **Tree**. 12 13### DevEco Studio Profiler Views 14 15> **NOTE** 16> 17> To use Profiler, your DevEco Studio must be 4.0 beta2 or later. 18 19#### ArkTS Callstack View 20 21In the **ArkTS Callstack** view, you can discover the function that is being executed or the phase it is in along the time axis. In terms of functions, the representation can be understood as the top of the call stack over time. You can press and hold **Ctrl** and move the mouse scroll wheel to zoom in on or zoom out of a segment. 22 23Native APIs (NAPIs) are marked yellow in the timeline. You can check the native call stack of these APIs in the **Details** view. 24 25Figure 1 ArkTS Callstack view 26 27 28 29#### Details View 30 31You can access the **Details** view by clicking any time bar in the timeline or selecting a time range. The **Details** view, shown at the bottom of the page, consists of two panes. The left pane shows the complete call chains of the functions represented by the time bar or time range. The right pane, **Heaviest Stack**, shows the most stack-hungry call chains. 32 33Figure 2 Details view 34 35 36 37As shown above, we can see not only the JS call stack, but also the C++ call stack in the native implementation of the NAPI. 38 39For a JS method or a custom native method, you can double-click the line where the method is located in **Details** to navigate to the source code of the method. 40 41> **NOTE** 42> 43> The line of code you navigate to here is the first line of the executable code in the method. 44 45### Chrome JavaScript Profiler Views 46 47By default, JavaScript Profiler of the Chrome browser uses V8's sample-based profiler to capture web page JS profile data. You can import the profile data (in .cpuprofile format) from the TS/JS CPU Profiler to JavaScript Profiler for analysis. 48 49To open JavaScript Profiler and import data in Chrome, press **F12** and choose **More tools** > **JavaScript Profiler** > **Load**. 50 51The following figure shows this procedure. 52 53Figure 3 Opening JavaScript Profiler 54 55 56 57Figure 4 Loading .cpuprofile files 58 59 60 61If JavaScript Profiler cannot be found, select the option shown below and press **F12** to try again. 62 63Figure 5 Enabling JavaScript Profiler 64 65 66 67As aforementioned, JavaScript Profiler comes in three views: **Chart**, **Heavy**, and **Tree**. 68 69#### Chart 70 71Figure 6 Chart overview 72 73 74 75The **Chart** view contains a flame graph that visualizes the stack traces of the profiled application. Time 0 on the time axis indicates when data collection starts. You can move the mouse scroll wheel to zoom in. 76 77Figure 7 Chart details 78 79 80 81Hover on a function to view the function details, which include the following fields: 82 83- **Name**: function name, followed by a tag in parentheses. The tag indicates the function type. For details, see [Description of Function Name Tags](#description-of-function-name-tags). 84 85- **Self Time**: amount of time, in milliseconds, spent in the function within its own stack frame, excluding the time spent in other functions it calls. The calculation formula is as follows: Total amount of time the stack frame takes to execute – Amount of time spent in downstream function calls. 86 87- **Total Time**: total amount of time, in milliseconds, spent in the function, including the time spent in other functions it calls. 88 89- **URL**: location of the function in the TS/JS code, in the format of "file path: line number." Wherein, the line number refers to the line number of the function header. 90 91 > **NOTE** 92 > 93 > - As sourcemap conversion is not yet performed on some function URLs, these URLs are in the build directory. 94 > 95 > - Though the aforementioned line number, by specification, refers to the line number of the function header. Currently, it actually refers to the number of the first line of the executable code in the function. 96 97- **Aggregated self time**: sum of all self times of the function throughout the sampling process, in milliseconds. Only the function calls under the same call stack are counted. 98 99- **Aggregated total time**: sum of all total times of the function throughout the sampling process, in milliseconds. Only the function calls under the same call stack are counted. 100 101#### Heavy 102 103The **Heavy** view lists the top functions of all call stacks. It can be seen as a **bottom-up view** of the flame graph. From this view you can initially see the end functions of call chains and their self time. The proportions of all self times add up to 100%. 104 105If you click the down arrow of a function to expand it, you can find its complete call chain, which may contain multiple call chains, all of which the function is called. 106 107You can sort functions in this view by self time. The first one displayed indicates that it has the longest self time and may be worth further examination. 108 109Below are **Heavy** views from Chrome and Visual Studio Code, both illustrating the parsing result of the same .cpuprofile file. Noticeably, the time from the parsing results is different, which is caused by difference in the calculation method. 110 111The time in the Chrome **Heavy** view is obtained by multiplying the hit ratio of the function by the total time, while that in the Visual Studio Code **Heavy** view is the actual time spent. 112 113In light of this, for the purpose of analysis accuracy, it is recommended that you use Visual Studio Code for parsing. Simply open the .cpuprofile file in the tool. 114 115Figure 8 Chrome Heavy view 116 117 118 119Figure 9 Visual Studio Code Heavy view 120 121 122 123#### Tree 124 125The **Tree** view lists the bottom functions of all call stacks. It can be seen as a **top-down view** of the flame graph. From this view you can initially see the start functions of call chains and their total time. The proportions of all total times add up to 100%. 126 127If you click the down arrow of a function to expand it, you can find its complete call chain, which may contain multiple call chains, all of which start from the function. 128 129You can sort functions in this view by total time. The first one displayed indicates that it has the longest total time and may be worth further examination. 130 131Figure 10 Tree view 132 133 134 135### Description of Function Name Tags 136 137When represented in a view, the function name tag may be preceded by the function name, as in **func1(AOT)**, or appear on its own, as in **(program)**. 138 139#### Tags Preceded by Function Names 140 141Tags preceded by function names are: (NAPI), (ARKUI_ENGINE), (BUILTIN), (GC), (AINT), (CINT), (AOT), and (RUNTIME). They can be used as reference for category-specific performance analysis. The last four tags are invisible by default when profile data is collected in non-CLI mode. To enable them, run the **hdc shell param set persist.ark.properties 0x505c; hdc shell reboot** command. 142 143- **(NAPI)**: system-provided native APIs or native APIs customized in DevEco Studio, for example, **testNapi.add()** in the template native C++ application. 144 145- **(ARKUI_ENGINE)**: ArkUI component implemented by native code, for example, **onClick()**. Currently, functions labeled with this tag do not provide a function name. 146 147- **(BUILTIN)**: JS standard library interface provided by the virtual machine (VM) and implemented by native code, for example, **JSON.stringify()**. 148 149- **(GC)**: garbage collection phase. 150 151- **(AINT)**: TS/JS method, which is interpreted and executed by the assembly interpreter of the VM. 152 153- **(CINT)**: TS/JS method, which is interpreted and executed by the C interpreter of the VM. 154 155- **(AOT)**: TS/JS method, which is compiled into machine code before it is executed, by using the Ahead of Time (AOT) compiler of the VM. When in compliance with the programming specifications, AOT can fully accelerate compilation, with execution time faster than that of interpretation. 156 157- **(RUNTIME)**: method that is called by native APIs (NAPI, ARKUI_ENGINE, BUILTIN) and that calls the internal runtime code of the VM. 158 159#### Tags Standing on Their Own 160 161The tags standing on their own represent a type of special node or phase, not actual functions. These tags are (root), (program), and (idle). 162 163- **(root)**: root node, which is the parent node of the **program** node, **idle** node, and all stack bottoms. It can be seen as the upper layer of the main function. 164 165- **(program)**: phase where the application executes only native code (no JS code is executed, no JS calls native code, and no native code calls JS). At this phase, the application may be executing code at the system framework layer. 166 167- **(idle)**: phase where the profiled thread is not executing any task or is not in the running state, and does not occupy the CPU. 168 169 > **NOTE** 170 > 171 > Currently, the (idle) phase is included in the (program) phase and not separately counted. 172 173#### Time Distribution of Tags 174 175To inspect the time distribution of tags, first open the .cpuprofile file in JSON format. At the start of the file you can find the execution time (in microseconds) of functions by tag, with the (idle), (root), and (program) tags grouped under the **otherTime** field. Based on the preceding information, you can work out the time distribution of tags to provide reference for performance analysis. 176 177Figure 11 Example of time distribution of tags 178 179 180 181## Data Collection Methods 182 183### Usage of Data Collection Methods 184 185| Collection Method | [DevEco Studio Profiler](#collecting-data-using-deveco-studio-profiler) | [JavaScript Profiler](#collecting-data-using-chrome-javascript-profiler) | [hdc shell](#collecting-data-using-hdc-shell-commands) | [Instrumentation](#collecting-data-using-instrumentation) | 186| -------------- | ------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------- | --------------------------------- | 187| Debug-type applications | Supported | Supported | Supported | Supported | 188| Release-type application | Not supported currently | Not supported currently | Supported | Supported | 189| Main thread | Supported | Supported | Supported | Supported | 190| Worker thread| Not supported currently | Supported | Supported | Supported | 191| Data after application startup| Supported | Supported | Supported | Supported | 192| Cold start data| Not supported currently | Not supported | Supported | Supported | 193 194### Collecting Data Using DevEco Studio Profiler 195 1961. Start the target application, open DevEco Studio, and make sure the target device is connected (the device SN is displayed in the upper right corner). 197 1982. Choose **Profiler** > **Time**, select the target device and application, and create a time session, as shown in the following figure. 199 200 Figure 12 Using DevEco Studio Profiler 201 202  203 2043. Click **Start Recording**. If the arrow changes to a square, the recording starts. 205 2064. Interact with the application to reproduce the scenario to be analyzed. 207 2085. Click the recording button again. If the square turns gray, the recording ends. 209 2106. Select **ArkTS Callstack** and then select a time range or directly select a function for analysis. For details, see [DevEco Studio Profiler Views](#deveco-studio-profiler-views). 211 212### Collecting Data Using Chrome JavaScript Profiler 213 2141. Start the application. Run the following command to obtain a list of the application thread IDs. In the list, the long IDs (whose length is twice the length of short IDs) are of Worker threads. 215 216 ```shell 217 hdc shell "netstat -anp | grep PandaDebugger" 218 ``` 219 2202. Bind thread IDs and port numbers. To collect data for different Worker threads at once, bind them to different port numbers and open multiple Chrome windows. 221 222 > **NOTE** 223 > 224 > - To avoid conflicts, select larger port numbers. Port 9006 is used in this example. 225 > 226 > - The port number needs to be rebound each time the process is disconnected or exited. 227 > 228 > - 229 230 ```shell 231 hdc fport tcp:9006 localabstract:2172PandaDebugger 232 ``` 233 234 Figure 13 Port mapping 235 236  237 2383. Visit **devtools://devtools/bundled/inspector.html?ws=//127.0.0.1:9006** from Chrome to access the JavaScript Profiler page. 239 2404. Click the recording button in the upper left corner. If the button turns red, the recording starts. 241 2425. Interact with the application to reproduce the scenario to be analyzed. 243 2446. Click the recording button again. If the button turns gray, the recording ends. 245 2467. Click a profile in the left pane. The profile data is then displayed in the right pane, in a chart or flame graph, depending on your selection. For details, see [Chrome JavaScript Profiler Views](#chrome-javascript-profiler-views). 247 248 Figure 14 JavaScript Profile view 249 250  251 252### Collecting Data Using hdc shell Commands 253 2541. Set VM parameters as needed. 255 256 - Collect cold start data. 257 258 ```shell 259 # Collect cold start data of the main thread only. 260 hdc shell param set persist.ark.properties 0x705c 261 # Collect cold start data of the Worker thread only. 262 hdc shell param set persist.ark.properties 0x1505c 263 # Collect cold start data of both the main and Worker threads. 264 hdc shell param set persist.ark.properties 0x1705c 265 ``` 266 267 - Collect data for any phase after application startup. 268 269 ```shell 270 # Collect data after startup of the main thread only. 271 hdc shell param set persist.ark.properties 0x2505c 272 # Collect data after startup of the Worker thread only. 273 hdc shell param set persist.ark.properties 0x4505c 274 # Collect data after startup of both the main and Worker threads. 275 hdc shell param set persist.ark.properties 0x6505c 276 ``` 277 2782. (Applicable to collection of cold start data) Set the bundle name of the application to be profiled. In this example, the bundle name is **com.ohos.example**. 279 280 ```shell 281 hdc shell param set persist.ark.arkbundlename com.ohos.example 282 ``` 283 2843. Restart the device. 285 286 ```shell 287 hdc shell reboot 288 ``` 289 2904. Start the application. Data is automatically collected before the application is started. 291 2925. Interact with the application to reproduce the scenario to be analyzed. 293 2946. To collect data for any phase after application startup, run the following command, where **pid** indicates the application process ID: 295 296 ```shell 297 hdc shell kill -39 pid 298 ``` 299 3007. Interact with the application to reproduce the scenario to be analyzed. 301 3028. To stop data collection, run the following command, where **pid** indicates the application process ID: 303 304 ```shell 305 hdc shell kill -39 pid 306 ``` 307 3089. Fetch the .cpuprofile file. The actual file location and file name vary by application. **com.ohos.example** is used as an example. 309 310 > **NOTE** 311 > 312 > You can repeat steps 6 through 8 multiple times to collect data for multiple phases and generate multiple .cpuprofile files. 313 > 314 > The count suffix increments by one each time data is collected. The initial count is 1. For collection of cold start data, the file name does not include the count suffix. 315 316 ```shell 317 # Main thread: 318 # In general cases, for non-system applications, the .cpuprofile file is stored in **/data/app/el2/100/base/<bundle_name>/files/**. 319 hdc file recv /data/app/el2/100/base/com.ohos.example/files/com.ohos.example_*count*.cpuprofile ./ 320 # For system applications, the .cpuprofile file is stored in **/data/app/el2/0/base/<bundle_name>/files/**. 321 hdc file recv /data/app/el2/0/base/com.ohos.example/files/com.ohos.example_*count*.cpuprofile ./ 322 ``` 323 324 ```shell 325 # Worker thread: 326 # In general cases, for non-system applications, the .cpuprofile file is stored in **/data/app/el2/100/base/<bundle_name>/files/**. 327 hdc file recv /data/app/el2/100/base/com.ohos.example/files/com.ohos.example_*thread ID*_*count*.cpuprofile ./ 328 # For system applications, the .cpuprofile file is stored in **/data/app/el2/0/base/<bundle_name>/files/**. 329 hdc file recv /data/app/el2/0/base/com.ohos.example/files/com.ohos.example_*thread ID*_*count*.cpuprofile ./ 330 ``` 331 33210. Import the **com.ohos.example.cpuprofile** file to Chrome JavaScript Profiler for analysis. For details, see [Chrome JavaScript Profiler Views](#chrome-javascript-profiler-views). 333 334 Figure 15 Loading the .cpuprofile file 335 336  337 338### Collecting Data Using Instrumentation 339 3401. Instrument the application, and then package and install the application. 341 342 > **NOTE** 343 > 344 > When possible, place trace code to a key position that will not be executed repeatedly, for example, the first and last lines in **onClick**. If you perform start and stop operations repeatedly, only the first start and stop operations will be successfully executed. 345 346 ```ts 347 import hidebug from '@ohos.hidebug'; 348 // The parameter is the name of the output file. No suffix is required. This parameter is mandatory. 349 hidebug.startJsCpuProfiling("filename"); 350 // Code block 351 // ... 352 // Code block 353 hidebug.stopJsCpuProfiling("filename"); 354 ``` 355 3562. Interact with the application to reproduce the scenario to be analyzed, and ensure that the trace code is executed properly. 357 3583. Fetch the JSON file and change the file name extension to .cpuprofile. The actual file location and file name vary by application. **com.ohos.example** is used as an example. 359 360 ```shell 361 # In general cases, for non-system applications, the .cpuprofile file is stored in **/data/app/el2/100/base/<bundle_name>/files/**. 362 hdc file recv /data/app/el2/100/base/com.ohos.example/files/filename.json ./filename.cpuprofile 363 364 # For system applications, the .cpuprofile file is stored in **/data/app/el2/0/base/<bundle_name>/files/**. 365 hdc file recv /data/app/el2/0/base/com.ohos.example/files/filename.json ./filename.cpuprofile 366 ``` 367 3684. Import the **filename.cpuprofile** file to Chrome JavaScript Profiler for analysis. For details, see [Chrome JavaScript Profiler Views](#chrome-javascript-profiler-views). 369 370 Figure 16 Loading the .cpuprofile file 371 372  373