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![ArkTS Callstack View](figures/arkts-callstack-eg.png)
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![Details View](figures/details-img-eg.png)
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![Access to JavaScript Profiler](figures/javascript-profiler-entry.png)
56
57Figure 4 Loading .cpuprofile files
58
59![Loading .cpuprofile Files](figures/load-cpuprofiler-file.png)
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![Enabling JavaScript Profiler](figures/enable-cpuprofiler-func.png)
66
67As aforementioned, JavaScript Profiler comes in three views: **Chart**, **Heavy**, and **Tree**.
68
69#### Chart
70
71Figure 6 Chart overview
72
73![Chart Overview](figures/chart-overview.png)
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![Chart Details](figures/chart-details.png)
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![Chrome Heavy View](figures/heavy-view.png)
118
119Figure 9 Visual Studio Code Heavy view
120
121![Visual Studio Code Heavy View](figures/vscode-cpuprofile-eg.png)
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![Tree View](figures/tree-view.png)
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![Example of Time Distribution of Tags](figures/time-distribution-statistic-eg.png)
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   ![Using DevEco Studio Profiler](figures/deveco-studio-profiler-catch-guide.png)
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   ![Port Mapping](figures/commandline-eg.png)
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   ![JavaScript Profile View](figures/jsvascript-profiler-view.png)
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    ![Loading .cpuprofile](figures/load-cpuprofiler-file.png)
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    ![Loading .cpuprofile](figures/load-cpuprofiler-file.png)
373