Android Performance Metric Part 2

Anil Gudigar
8 min readJul 26, 2018

--

Let’s talk about the next performance metric which measures how responsive is your application.

2. Frames Per Second

So, we have built the great android application, but user complaining about the experience is not always consistent sometimes its slow and hitchy and it doesn’t scrolls as smooth as they would like.

So, its a Rendering Performance Issue term frame per second completely co-relates the concept of Rendering.

The android system attempts to redraw your activity every 16 milliseconds or so, which means your application should run all the logic and then update the screen in that 16 milliseconds frames in order to hit 60 frames per second.

The Math goes as below :

1 second = 1000 milliseconds we would like to have 60 frames per second

1000 milliseconds / 60 frames = 16.6 milliseconds we should redraw/update frames every 16 milliseconds.

Now if you miss that window and let’s say you take 24 milliseconds then you start to get what we call a dropped frame. the system tried to draw a new picture on the screen, but one wasn’t ready yet. so, it did not refresh anything so the user ended up seeing the same graphic for 32 milliseconds rather than 16 milliseconds this is what we call a laggy or janky experience. this we can easily observe when we drag a listview or type some data.

Reasons for missing 16 milliseconds frame window ??

  1. Spending too much time on redrawing your view hierarchy wastes the CPU cycle.
  2. Drawing too many objects on top of each other wastes valuable time on coloring which isn’t visible to the user.
  3. A ton of animation over and over which can cause a large amount of churn on both CPU and GPU.

To fix all these problems is important to understand how hardware is working, so you know the best ways of working with it.

Let’s understand the terms Refresh Rate and Frame Rate.

Refresh rate represents how any time a screen can update its display per second. this value is specified Hertz and its 60 Hertz is constant based on the hardware.

Now let’s look into Frame Rate which measures how many times your GPU can draw a frame per second for example 30 frames per second or 60 frames per second.

Now Refresh rate and Frame rate should work together in order to get your image drawn to the screen.

GPU will take the data, draw it, and the hardware will push the output of that to the screen this will happen over and over again during the lifetime of your application. But the problem is the refresh rate and the frame rate is not guaranteed to occur at the same frequency, for example, if your frame rate actually faster than the refresh rate then you are going to be seeing some visual problems.

This problem can be solved by VSYNC using Backbuffer and Framebuffer. For example, imagine taking a picture and rotating a camera about 5 degrees and taking another picture we merge the two pictures by cutting both into half there will be a tearing issue we can observe in the glued picture.

this is what happens in your application frame rate and the refresh rate is not matching.

the issue is your graphics card uses one region of memory to draw its frames into. Each new Frame will override the previous frame, outputting data online at a time, starting at the top. now the screen comes along to refresh it doesn’t know what state that buffer is actually in. As such it can grab a frame from a GPU that’s not entirely finished yet. meaning it got half of the previous frame and half of the current frame.

The solution to this call is double buffering effectively when the GPU has done drawing frame memory known as Backbuffer, it will copy it to its secondary area of memory known as Framebuffer. when it draws the next frames begin filling the back buffer while the frame buffer remains untouched. now when the screen comes along to refresh, it will do so from the frame buffer which isn’t in the middle of the next draw operation.

Now VSYNC's responsibility is to keep a copy operation happening from the Back buffer to the frame buffer if the screen is in the middle of refreshing from it.

Having a Frame rate higher than the Refresh rate is ideal since the GPU is refreshing faster than your screen is reading in this scenario after a successful screen refresh your GPU will be VSYNCed waiting for the next screen refresh to occur.in the scenario, your frame rate is effectively capped to the device refresh rate.

But what happens if your screen is refreshing twice as fast as the GPU is Drawing?

This means every single refresh will be sampling from the same frame or rather screen will be displaying the same GPU Frame twice in a row. when it happens intermittently you get the problem, for example, your frame rate higher than the refresh rate suddenly dips, then the user will see smooth animation broken up with sudden pauses followed by the rest of the animation this exact effect is called LAG, JUNK or HITCHING.

these are the things we should avoid. our application should strive to remove these sudden dips in frame rate but always ensure that the GPU gets its data quickly and has time to draw the content by the next screen refresh.

Now we have discussed CPU and GPU's role in rendering, Understanding how android systems utilize GPU can go a long way to understanding performance problems.

Questions are how are these activities rendered into the screen? how does that XML turn into pixels so that the user can see and understand?

this process is called as rasterization this is the process of taking some high-level object

like a string button or path or shape and turning it into a pixel or textures on your screen.

Now rasterization is a really time-consuming process and as such, there is a special piece of hardware in your smartphone that is designed to make it happen a lot faster that is GPU ( Graphics Processing Unit).

GPU uses a specific set of primitives like polygons and textures as we may call it as Images. and the CPU is responsible for feeding these primitives to the GPU before anything to drawn in your screen.

this is done common API in Android called OpenGL ES which means anytime your UI object like buttons paths or checkboxes needs to be drawn to the screen they first need to be converted on the CPU to polygons or textures before being passed off the GPU to rasterize.

the process below shows how the CPU converts the button object into polygons and textures and OpenGL API will help to upload it to the GPU.

This is how Android systems render the UI an example resource provided by your theme is bitmaps and drawables are grouped together into a single texture and uploaded to the GPU on your behalf alongside commonly used polygon meshes like nine patches.

this means anytime you draw a view that uses these resources, we don’t have to do any conversion because all the components are resident in the GPU.

So let’s check the tools or libraries available to find the UI performance and Frame drop issue.

The problem with performance is that it often decreases slowly so in day-by-day development it’s hard to notice that our app (or Activity or any other view) launches 50ms longer. And another 150ms longer, and another 100ms…

With AndroidDevMetrics you will be able to see how performant the most common operations like object initialization (in Dagger 2 graph), or Activity lifecycle methods ( onCreate(), onStart(), onResume()).

It won’t show you an exact reason for performance issues or bottlenecks (yet!) but it can point out where you should start looking first.

The first iteration of this tool (v0.3) is able to measure:

  • Objects (and dependencies) initialization in Dagger 2 graph
  • App and screens launch process (measuring lifecycle methods execution)
  • Frame drops on each screen

Getting started

The script below shows how to enable all available metrics.

In Application build.gradle add the classpath

add the plugin in the main build.gradle

In your Application class:

HOW DOES IT WORK?

A detailed description of how it works under the hood can be found on projects wiki pages:

I FOUND A PERFORMANCE ISSUE, WHAT SHOULD I DO NEXT?

There is no silver bullet for performance issues but here are a couple of steps that can help you with potential bug hunting.

If the measured time of object initialization or method execution looks suspicious you should definitely give it a try to TraceView. This tool logs method execution over time and shows execution data, per-thread timelines, and call stacks. A practical example of TraceView usage can be found in this blog post: Measuring Dagger 2 graph creation performance.

If it seems that layout or view can be a reason for performance issues you should start with those links from the official Android documentation:

Finally, if you want to understand where most of the performance issues come from, here is a collection of videos focused entirely on helping developers write faster, more performant Android Applications — Android Performance Patterns.

Originally published at http://androidtechieblog.wordpress.com on July 26, 2018.

--

--

No responses yet