Intelligent Assistant
Chat with our virtual assistant to get answers promptly.
Performance optimization is a systematic process of improving the running speed, resource utilization, and response time of apps. It enables better app performance and stability. In the digital era, as apps grow in complexity and scale, tuning becomes increasingly critical. Effective tuning not only makes apps run more efficiently but also enhances stability, increases efficiency, and reduces resource waste, thereby improving user experience. Therefore, it is essential for developers to be well-versed in tuning techniques and familiar with the tools commonly used in the process.
The tuning process usually involves reproducing an on-site problem, analyzing the problem, determining the solution, and testing the performance. Reproducing an on-site problem refers to re-creating a problem in a specific scenario for better analysis and solution. Analyzing the problem is to deeply analyze the performance bottlenecks and root causes of the app, providing guidance for subsequent optimizations. Determining the solution is to work out a specific optimization solution and measures based on the problem analysis result. Testing the performance is a key step to verify the effectiveness of the tuning efforts. You can evaluate the improvements by testing the optimized app.
Some common tools can be used to achieve effective tuning. For example, DevEco Profiler can monitor app performance metrics and record traces. It enables you to analyze trace data and detect performance bottlenecks in the code, achieving optimized performance.
This topic describes the tuning methods and common tools, which help you to better analyze and solve performance issues in apps, improve user experience, and achieve efficient and stable running of apps.
In daily development, you need to pay attention to metrics such as completion latency, touch response latency, and scrolling response latency. More details are provided in Performance Experience Design.
Tuning analysis plays a key role in app optimization, helping you identify issues, locate bottlenecks, and improve system performance. The specific method is as follows:
Tuning analysis is a crucial step in app optimization. Through the preceding procedure, you can identify and solve app performance issues, improving the efficiency and stability of apps.
Provided by DevEco Studio, DevEco Profiler helps you identify performance problems in your app. It offers the following scenario-based optimization tools:
Other common performance tuning tools include HiDumper and SmartPerf.
DevEco Profiler does not support emulators.
Introduction
You can use Inspector bidirectional preview to view the component layout of the app on a real device via DevEco Studio. By viewing the UI status after multiple operations, you can quickly analyze and locate issues such as status variables, component nesting layers, and UI layout problems.
Usage
For details, see:
The DFX subsystem of HarmonyOS provides performance traces for the app framework and core modules of the system. Each trace records the task execution time, formatted data at runtime, and process or thread information. You can use the frame of DevEco Studio to parse traces and identify key rendering processes in a lane graph.
In HarmonyOS, thread states recorded by trace are classified into Running, Runnable, Sleep, Uninterruptible Sleep - IO, and Uninterruptible Sleep - non IO. The following figure shows the state transition.

Different colors are used in the traces to identify different thread states. Each method is provided with a corresponding thread state to identify the current thread state. By viewing the thread state, you can analyze the current performance bottleneck.
(1) Running

Running: indicates that only threads in the Running state can run on the CPU. Multiple threads may be executable at the same time. The task_struct structure of these threads is placed in the executable queue of the corresponding CPU (one thread can appear in the executable queue of only one CPU). From the executable queue of each CPU, the scheduler selects a thread to run on the CPU.
(2) Runnable

Runnable: indicates that a thread can run but is waiting for CPU scheduling. The longer the Runnable state lasts, the busier the CPU scheduling is, and the task has not been processed promptly.
(3) Sleep

Sleep: indicates that the thread is not working. This could be because the thread is blocked on a mutex or waiting for an operation to complete, often in the context of event-driven operations.
(4) Uninterruptible Sleep (IO)

Uninterruptible Sleep (IO): indicates that the thread is blocked in the I/O operations or waits for the disk operation to complete. When the system memory is low, a page fault may be triggered during memory allocation, leading to a large number of uninterruptible sleep states. In the page cache linked list of the Linux system, some pages are not ready sometimes (that is, the contents in the disk have not been fully read). At this time, a page fault occurs when a user accesses the page.
(5) Uninterruptible Sleep (non-IO)

Uninterruptible Sleep (non-IO): indicates that the thread is blocked on another kernel operations (such as memory management). The thread is in the kernel mode, which is normal in some cases and needs further analysis in other cases.
In HarmonyOS, the graphics subsystem uses a unified rendering mode, following the typical pipeline mode. For example, if the refresh rate is 60 Hz, the Vsync period is 16.7 ms; if the refresh rate is 90 Hz, the Vsync period is 11.1 ms; if the refresh rate is 120 Hz, the Vsync period is 8.3 ms.

In the rendering process, the app responds to input events, such as screen touches, processes the events, and submits the processed events to Render Service. Render Service coordinates resources such as the GPU to carry out the rendering tasks and presents the final image on the display.
The following figure shows the rendering process on the app. By learning about the ArkUI rendering process, you can better locate freezing issues within the app.

Throughout the entire process, both the app side and the Render Service side can encounter frame freezing, resulting in frame loss that end users can notice. These two situations are called AppDeadlineMissed and RenderDeadlineMissed, respectively. AppDeadlineMissed is usually caused by inefficient app logic processing code, whereas RenderDeadlineMissed may be caused by complex UI structures or high GPU loads. The two fault models can be viewed through the frame template. The following figures show the fault models.


The following figure shows typical traces used by the UI backend engine in the rendering process of a frame.

The following table describes each part of a trace.
No. | Trace | Parameter | Description |
|---|---|---|---|
1 | OnVsyncEvent now:%" PRIu64 " | Current timestamp, in nanoseconds. | Starts the rendering process after the Vsync signal is received. |
2 | FlushVsync | Refreshes the view synchronization events, including recording frame information, refreshing tasks, drawing and rendering the context, and processing user input. | |
3 | UITaskScheduler::FlushTask | Refreshes the UI, including the layout, rendering, and animation. | |
4 | FlushMessages | Sends a message to instruct the graphics side to perform rendering. | |
5 | FlushLayoutTask | Executes the layout task. | |
6 | FlushRenderTask %zu | Number of nodes to be rendered on the current page. | Executes the rendering task. |
7 | Layout | Lays out the nodes. | |
8 | FrameNode::RenderTask | Executes a single rendering task. | |
9 | ListLayoutAlgorithm::MeasureListItem:%d | Index of the current list item. | Calculates the layout size of the list item. |
Render Service in the graphics subsystem is responsible for drawing UI content, processing unified rendering tasks from apps, combining layers of different apps, and sending them for display. In each Vsync period, Render Service first processes instructions from apps, including adding, deleting, and modifying rendering tree nodes. It then performs animation calculation and occlusion calculation to update the unified rendering tree. After that, it draws the rendering tree, preprocesses each node, calculates the absolute position and dirty areas, and draws the dirty areas. The hardware synthesizer is preferentially used for drawing. If the hardware synthesizer cannot be used, the GPU is used for redrawing. All results are stored in the screen buffer and then sent for display.
The following figure shows a trace lane graph when the Vsync signal is refreshed.

The following table describes each part of a trace.
No. | Trace | Description |
|---|---|---|
1 | RSMainThread::DoComposition | Composites the layers of nodes in the rendering tree. |
2 | RSMainThread::ProcessCommand | Processes app instructions. |
3 | Animate | Processes the animation. |
4 | ProcessDisplayRenderNode[x] | Performs drawing on a single display. |
5 | Repaint | Performs drawing by the hardware synthesizer. |
6 | RenderFrame | Performs drawing by the GPU. |
7 | SwapBuffers | Refreshes the display buffer. |
8 | Commit | Presents the drawing result on the display. |
Lazy loading is implemented using LazyForEach, which iterates over provided data sources and creates corresponding components during each iteration. When LazyForEach is used in a scrolling container, the framework creates components as required within the viewpoint area of the scrolling container. When a component slides out of the visible area, the framework destroys the component to reduce memory usage.
The following figure shows the trace lane graph of a frame during lazy loading.

No. | Trace | Parameter | Description |
|---|---|---|---|
1 | OnIdle, targettime:%" PRId64 " | Timestamp, before which the task is completed. | In the idle event loop, the framework checks whether there are new events to be processed. If yes, the task scheduler is added to the UI thread and executes the predicted task. |
2 | Builder:BuildLazyItem [%d] | Index of the item to be created. | Builds an item when needed and caches it. |
3 | CustomNode:BuildRecycle %s | Name of the JS view. | Triggers rendering recycling. |
4 | ExecuteJS | Executes JS code. | |
5 | List predict | Adds a predicted layout task. | |
6 | Layout | Completes the layout of the current frame node. |
You can use HiTraceMeter to track custom traces in light of service requirements. For details, see Using hiTraceMeter (ArkTS/JS) and Using HiTraceMeter (C/C++).
After adding custom traces, you can view it on the SmartPerf-Host debugging tool. Custom trace information is displayed as an independent lane in the corresponding process. The following figure shows two lanes that record the duration between the calls to startTrace and finishTrace. The figure records the durations of CUSTOM_TRACE_TAG_1 and CUSTOM_TRACE_TAG_2.
Example of a custom trace

Example of a custom status value
