Identify UI Rendering Issues
Slow user interface (UI) frame generation in your app can reduce fluidity or frame rate, resulting in jank. Jank refers to stuttering or lag in the UI, which can make your app slow or unresponsive. Fluidity refers to how smoothly and responsively your app's interface moves and reacts to user input.
Vega apps require a fluidity key performance indicator (KPI) score of 99% or higher for smooth interaction. A KPI is a measurable value that demonstrates how effectively your app is achieving key objectives.
The following sections explain how to identify UI rendering issues in your app to achieve smooth performance and meet your fluidity KPI score.
Prerequisites
Before you proceed, make sure you complete the setup in Measure Fluidity and Foreground.
Identify UI rendering jank
After you run the fluidity KPI test in Vega App KPI Visualizer, the system generates artifacts that help identify causes of UI lag. These artifacts include a fluidity graph, CPU profile graph, and Perfetto trace.
Understand the Fluidity graph
The fluidity graph visually represents your app's rendering performance over time. When examining the graph, look for drops in fluidity that indicate potential performance issues. These drops often correlate with specific events or code execution that cause lag in the UI.
To identify the cause of drops in fluidity
- Examine the Perfetto trace.
Analyze the CPU profile graph
The CPU profile graph shows the time spent in different functions within your app. When you see performance issues in the Fluidity graph, expand the CPU profile graph at the timestamp. The expanded view is called a flamegraph, which is a visualization of the CPU profile that shows which functions use the most processing time.
To collapse the flamegraph
- Select the root bar.
- If the view remains expanded, use the
Developer: Reload Webviews
command pallete.
Work with Perfetto traces
Perfetto is an open-source tool that records system traces with minimal impact on performance. When you start a fluidity test, Perfetto automatically collects traces on the Vega device that you're testing. After test completion, the trace files download to your workstation.
You can find the trace files in the test output directory. Each file is in the following format:
iter_<ITERATION_NUMBER>_vs_trace.protobuf
Example file: iter_3_vs_trace.protobuf
To analyze system behavior during testing
- Open the trace files Perfetto UI.
- To identify UI rendering issues, examine the
Toolkit/Render thread
trace. - Look for extended or recurring events that might cause performance degradation.
Common cause of janks and resolution
Frame size mismatch
When rendering frames, the system loads bitmaps to the graphics processing unit (GPU) as an OpenGL texture. An OpenGL texture is an image used in rendering graphics, typically stored in the GPU's memory.
If the frame size and display resolution don't match, the following actions occur:
- The GPU must map the frame pixels to the display.
- If the frame is larger than the display, more pixels than needed are loaded onto the GPU.
These mismatches can degrade performance and waste rendering time.
To investigate frame size mismatch
- In Perfetto (System Trace), locate the
Tools/Render
thread around the time when the lag was observed. - Check for delays in the render process.
- Verify that the frame width and height match the target device's display size.
Frame overdraw
Frame overdraw occurs when an app renders the same pixel multiple times within a single frame, wasting computational resources. This happens because the app draws new objects over previously drawn objects without first clearing the screen.
To detect app overdraw
- Follow the steps in Detect Overdraw.
Add custom trace with React Native Systrace
The Vega SDK supports the React Native Systrace API so that you can add trace markers and measure the time elapsed between function calls in your app's source code. Custom traces help you pinpoint performance issues in specific parts of your code.
The following code block shows how to add trace markers.
const App = () => {
const setCustomTrace = () => {
Systrace.setEnabled(true); // Call setEnabled to turn on the profiling.
Systrace.beginEvent('custom_label');
Systrace.counterEvent('custom_label', 10);
};
...
const functionToTrace = () => {
...
enableProfiling()
...
};
}
Custom traces help you identify which functions or code in your app are time-consuming. However, adding custom trace might introduce heavy overhead if not implemented carefully, resulting to false-positive results.
Best practices
To avoid janks or slow rendering, follow the Vega app guidelines in App Performance Best Practices.
Related topics
Last updated: Sep 30, 2025