4.1A: Using the Profile GPU Rendering tool

Contents:

Every app is different and could have different performance issues. While there are best practices, you need to analyze the unique configuration of your app to find and fix performance issues.

To discover what causes your app's specific performance problems, use tools to collect data about your app's execution behavior. Understand and analyze what you see, then improve your code. Android Studio and your device provide profiling tools to record and visualize the rendering, compute, memory, and battery performance of your app.

In this practical, you use the Profile GPU Rendering tool on your device to visualize how long it takes an app to draw frames to the screen.

Important: To run the Profile GPU Rendering tool and complete this practical exercise, you need a physical or virtual device running at least Android 4.1 (API level 16) with Developer Options turned on.

Your app must consistently draw the screen fast enough for your users to see smooth, fluid motions, transitions, and responses. To this end, typically, modern devices strive to display 60 frames per second (a frame rate of 60 FPS), making 16 milliseconds available to each frame. Therefore, your app has to do its work in 16 milliseconds or less for every screen refresh.

Important: For real-world performance tuning, run your app and the tools on a physical device, not an emulator, as the data you get from running on an emulator may not be accurate. Always test on the lowest-end device that your app is targeting. If you do not have a physical device, you can use an emulator to get an idea of how your app is performing, even though some performance data from the emulator may not be accurate.

What you should already KNOW

  • You should be able to download an app from GitHub, open it with Android Studio, and run it.
  • It helps to be familiar with the following concepts and terminology:
  • CPU: A central processing unit (CPU) is the electronic circuitry within a computer that carries out the instructions of a computer program by performing the basic arithmetic, logical, control, and input/output (I/O) operations specified by the instructions.
  • GPU: A graphics processing unit (GPU) is a specialized electronic circuit designed to rapidly manipulate and display images.
  • Frame rate: Frame rate (expressed in frames per second, or FPS) is the frequency (rate) at which consecutive images, called frames , are displayed in an animated display. Mobile devices typically display 60 frames per second, which appears as smooth motion to the human eye.
  • Display list: A display list (or display file) is a series of graphics commands that define an output image as a series of primitives (such as lines and basic shapes).
  • Rendering pipeline: A conceptual model that describes the steps that a graphics system performs when it renders graphical information on the screen. At the highest level, the pipeline creates a display list from program instructions in the CPU, passes the display list to the GPU, and the GPU executes the display list to draw the screen.

As a refresher, watch the Invalidation, Layouts, and Performance video for an overview of the Android rendering pipeline. Read the Rendering and Layout concept chapter as well as How Android Draws Views.

What you will LEARN

You will learn how to:

  • Use the Profile GPU Rendering tool to visualize Android drawing the screen.

What you will DO

  • Run the Profile GPU Rendering tool on the RecyclerView app and examine the results.
  • Create a simple app that has performance problems and run the Profile GPU Rendering tool on it.

App overview

  • For the first part of this practical, use the RecyclerView app.
  • For the second part of this practical, you build an app that loads images, LargeImages, to see how image size affects performance. In a later practical, you learn more about using images correctly.

The following screenshot shows one way of implementing the LargeImages app.  One way of implementing the LargeImages app is with a background image for a <code>TextView</code>

Task 1. Run the Profile GPU Rendering tool

Putting pixels on the screen involves four primary pieces of hardware:

  • The CPU computes display lists. Each display list is a series of graphics commands that define an output image.
  • The GPU (graphics processing unit) renders images to the display.
  • The memory stores your app's images and data, among other things.
  • The battery provides electrical power for all the hardware on the device.

Each of these pieces of hardware has constraints. Stressing or exceeding those constraints can cause your app to be slow, have bad display performance, or exhaust the battery.

The Profile GPU Rendering tool gives you a quick visual representation of how much time it takes to render the frames of a UI window relative to the 16-ms-per-frame benchmark. The tool shows a colored bar for each frame. Each bar has colored segments indicating the relative time that each stage of the rendering pipeline takes, as shown in the screenshot below.  Profile GPU Rendering bars for RecyclerView app

What it's good for:

  • Quickly seeing how screens perform against the 16-ms-per-frame target.
  • Identifying whether the time taken by any part of the rendering pipeline stands out.
  • Looking for spikes in frame rendering time associated with user or program actions.

1.1 Disable Instant Run

Note: While profiling an app, disable Instant Run inAndroidStudio. There is a small performance impact when using Instant Run. This performance impact could interfere with information provided by performance profiling tools. Additionally, the stub methods generated while using Instant Run can complicate stack traces. See About Instant Run for details.

In Android Studio, turn off Instant Run for the physical and virtual devices you want to profile.

  1. Open the Settings or Preferences dialog: On Windows or Linux, select File > Settings from the menu bar. On Mac OSX, select Android Studio > Preferences from the menu bar.
  2. Navigate to Build, Execution, Deployment > Instant Run.
  3. Deselect the Restart activity on code changes checkbox.

1.2 Install and run the RecyclerView app

For this tool walkthrough, use the RecyclerView app from the Android Developer Fundamentals course.

  1. Download the RecyclerView app.
  2. Open the app in Android Studio and run it. You may need to uninstall previous versions of the app.
  3. Interact with the app. Does the app scroll smoothly?
  4. Press the + button and add words to the list. Does this change how you perceive the performance of the app?

RecyclerView is an efficient way of displaying information, and on most devices and recent versions of Android, the app performs smoothly. What users perceive and how they experience the app are your ultimate benchmarks for performance.

1.3 Turn on the Profile GPU Rendering tool

Ensure that developer options is turned on, and allow USB Debugging if prompted.

Go to Settings > Developer options and follow the steps as illustrated in the screenshot below.

  1. Scroll down to the Monitoring section.
  2. Select Profile GPU rendering.
  3. Choose On screen as bars in the dialog box. Immediately, you see colored bars on your screen. The bars vary depending on your device and version of Android, so they may not look exactly as illustrated.  In Settings > Developer options > Profile GPU rendering, select

  4. Switch to the RecyclerView app and interact with it.

Note the following:

  • Each bar represents one frame rendered.
  • If a bar goes above the green line, the frame took more than 16ms to render. Ideally, most of the bars stay below the green line most of the time.

    This is not an absolute requirement. For example, when you first load an image, the bar may go above the green line, but users may not notice a problem, because they may expect to wait a moment for an image to load. Having some tall bars does not mean your app has a performance problem. However, if your app does have a performance problem, tall bars can give you a hint as to where to start looking.

  • The colors in each bar represent the different stages in rendering the frame. The colored sections visualize the stages and their relative times. The table below gives an explanation.

The image below shows the bars and color legend for a device that is running Android 6.0 or higher. The bars for older versions use different coloring. See the Profile GPU Rendering Walkthrough for the bar legend for older versions.  Profile GPU Rendering bars.

 Legend for the Profile GPU Rendering tool for Android 6.0 or higher

The following table shows the component bars in Android 6.0 and higher.

Color Rendering stage Description
Swap buffers Represents the time the CPU is waiting for the GPU to finish its work. If this part of the bar is tall, the app is doing too much work on the GPU.
Command issue Represents the time spent by Android's 2-D renderer as it issues commands to OpenGL to draw and redraw display lists. The height of this part of the bar is directly proportional to the sum of the time it takes for all the display lists to execute—more display lists equals a taller red segment of the bar.
Sync and upload Represents the time it take to upload bitmap information to the GPU. If this part of the bar is tall, the app is taking considerable time loading large amounts of graphics.
Draw Represents the time used to create and update the view's display lists. If this part of the bar is tall, there may be a lot of custom view drawing, or a lot of work in onDraw methods.
Measure and layout Represents the amount of time spent on onLayout and onMeasure callbacks in the view hierarchy. A large segment indicates that the view hierarchy is taking a long time to process.
Animation Represents the time spent evaluating animators. If this part of the bar is tall, your app could be using a custom animator that's not performing well, or unintended work is happening as a result of properties being updated.
Input handling Represents the time that the app spent executing code inside of an input event callback. If this part of the bar is tall, the app is spending too much time processing user input. Consider offloading such processing to a different thread.
Misc. time / Vsync delay Represents the time that the app spends executing operations between consecutive frames. It might indicate too much processing happening in the UI thread that could be offloaded to a different thread. (Vsync is a display option found in some 3-D apps.)

For example, if the green Input handling portion of the bar is tall, your app spends a lot of time handling input events, executing code called as a result of input event callbacks. To improve this, consider when and how your app requests user input, and whether you can handle it more efficiently.

Note that RecyclerView scrolling can show up in the Input handling portion of the bar. RecyclerView scrolls immediately when it processes the touch event. For this reason, processing the touch event needs to be as fast as possible.

If you spend time using the Profile GPU Rendering tool on your app, it will help you identify which parts of the UI interaction are slower than expected, and then you can take action to improve the speed of your app's UI.

Important: As the Android system and tools improve, recommendations may change. Your best and most up-to-date source of information on performance is the Android developer documentation.

Task 2. Run the Profile GPU Rendering tool on an app with performance issues

Important: We do not want to teach you how to write bad apps. We don't even want to show you the code. However, we can simulate a slow app by using images that are too large; in a different chapter, you learn how to improve performance by using the right image sizes and types for your app.

2.1 Create an app with image backgrounds

Build a LargeImages app that has performance problems. (You re-use this app in a later practical.)  LargeImages app screenshot

One way to implement the LargeImages app is to show simple instructions in a TextView and the large background image that is provided with the solution code.

Do the following:

  1. Create an app named LargeImages using the Empty Template.
  2. Choose 5.1, Lollipop (API 22) as the minimum SDK. (Lossless and transparent WebP images that you use later in this app are supported in Android 4.3, API level 18 and higher, and API 22 is recommended.)
  3. Put at least one small and one large image into the drawables resource folder.

    • You can copy images from the solution code in GitHub.
    • Small images should be around 12KB.
    • The largest image should be a few hundred KB. The dinosaur_medium.jpg supplied with the solution code is 495KB and a good starting point. The max size of the image you can load depends on the amount of device memory available to your app. You can look at the specifications for a phone model to find out how much RAM it has. Not all of this is available to a single app, so you may have to experiment a bit. You may need to try different size images to find the largest image that won't crash your app.
  4. Add an Activity.

  5. Create a layout with a LinearLayout with a TextView. Set the height and width of the TextView to match_parent.
  6. Set the background (android:background) on the TextView to the small image.
  7. Add this text to this to the TextView: "Click to swap image."
  8. Add a click handler to the TextView that changes the background when the screen is tapped. Use the following code snippet as a template. The code uses a numeric toggle so that you can experiment with any number of images.
     private int toggle = 0;
     ...
     public void changeImage(View view){ 
          if (toggle == 0) {
            view.setBackgroundResource(R.drawable.dinosaur_medium);
            toggle = 1;
        } else {
            view.setBackgroundResource(R.drawable.ankylo);
            toggle = 0;
        }
     }
    
  9. Run the app with Profile GPU Rendering turned on and tap to swap pictures. When you load the small image, you should see relatively short bars. When you load the large image, there should be relatively tall bars, similar to the ones shown below.  Profile GPU Rendering bars for the large image app. The detail on the left shows the faint short bars for the small image (1) staying below the green line (2). The screenshot on the right show the bars as they appear on your device emphasizing the bars that cross the green line (3,4).

Profile GPU Rendering bars for the large image app are shown in the previous screenshots. The detail on the left shows the faint short bars for the small image (1) staying below the green line (2). The screenshot on the right show the bars as they appear on your device emphasizing the bars that cross the green line (3,4).

  1. The narrow, faint bar for the small image is below the green line, so there is no performance issue.
  2. The green horizontal line indicates the 16 millisecond rendering time. Ideally, most bars should be close to or below this line.
  3. After the small image is replaced by the large image, the red bar segment is huge. This Command issue segment represents the time spent by Android's 2D renderer issuing commands to draw and redraw display lists.
  4. The large image also has a huge orange segment. This Swap buffers segment represents the time the CPU is waiting for the GPU to finish its work.

    The GPU works in parallel with the CPU. The Android system issues draw commands to the GPU, and then moves on to its next task. The GPU reads those draw commands from a queue. When the CPU issues commands faster than the GPU consumes them, the queue between the processors becomes full, and the CPU blocks. The CPU waits until there is space in the queue to place the next command.

    To mitigate this problem, reduce the complexity of work occurring on the GPU, similar to what you would do for the "Command issue" phase.

See Analyzing with Profile GPU Rendering for details on each stage.

To fix the app, you would use a different or smaller image. Finding problems can be as straightforward as this, or it can take additional analysis to pinpoint what is happening in your app's code.

Troubleshooting

  • If your app crashes with the images provided for the sample app, you may need to use smaller images for your device.
  • If your app crashes on the emulator, edit the emulator configuration in the AVD Manager. Use your computer's graphics card instead of simulating the device's graphic software by selecting "Graphics: Hardware - GLES" on the configuration screen.
  • If you get a failed to find style 'textviewstyle' in current theme or other rendering error in the Design view in Android Studio, click the refresh link provided with the error message.

2.2 Simulate long input processing

To demonstrate how doing too much work on the UI thread slows down your app, slow down drawing by putting the app to sleep:

  1. Add code to the click handler of the LargeImages app to let your app sleep for two screen refreshes before switching the background to the smaller image. This means that instead of refreshing the screen every 16 ms, your app now refreshes every 48 ms with new content. This will be reflected in the bars displayed by the Profile GPU Rendering tool.
     public void changeImage(View view){
        if (toggle == 0) {
            view.setBackgroundResource(R.drawable.dinosaur_large);
            toggle = 1;
        } else {
            try {
                Thread.sleep(32); // two refreshes
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            view.setBackgroundResource(R.drawable.ankylo);
            toggle = 0;
        }
     }
    
  2. Run your app. The previously short bars for the small image should now be much taller. Wait a while before clicking the TextView to get the next image; otherwise, the Android system may display an ANR.

If your app is only swapping backgrounds, the impact from this change may not be significant for the user. However, if you are running animated content, skipping two out of three frames will result in a stuttering and jagged animation.

While Profile GPU Rendering cannot tell you exactly what to fix in your code, it can hint at where you should start looking. And let's admit it, the on-screen bars are pretty cool!

Solution code

Android Studio project: LargeImages.

Summary

  • You can use the Profile GPU Rendering tool on your device to visualize the relative times it takes for your app to render frames on screen.
  • Because it can be turned on quickly and its results are immediate and graphical, this tool is a good first step when analyzing potential app performance issues related to rendering.
  • The sections of the colored bars can indicate where in your app you might look for performance problems.
  • Common reasons for slow drawing are an app taking too long to process user input on the UI thread, and backgrounds and images that are unnecessary or too large.

The related concept documentation is in Rendering and layout.

Learn more

results matching ""

    No results matching ""