Android Application Performance — Step 2: Compute

Elif Boncuk
10 min readDec 27, 2015

--

I am moving on with Compute. You can reach my previous story about performance from the link.

From pre-compiler to compiler, optimiser, code’s itself, lots of thing work on the device. Because of this, compute performance is so important which actually is related with how algorithms’, computing processes have been executed. (Compiler’s generating the code and virtual machine’s executing it on the hardware)

Let’s start with slow function performance. In real, we write our code to solve a specific problem but then we realize that it takes too long when executing the code according to our expectations.

How we write our code effects the performance depending on from hardware’s using which programming language to how the silicon chips are structured. And we have to understand the system if we optimise our performance.

Slow function performance usually comes in two different ways. Firstly, you have only one slow function form. This is easy to understand. You have a function takes 2x or 5x longer according to normally expected duration. In that case, we can solve the problem as finding the code that is slow function, examining, finding and fixing.

It is harder to solve the second type of slow function performance problems. If every function in millions takes one millisecond longer according to expected, it takes extra 100 millions ms when the program is executed. It is harder to find the solution in this kind of situations because in real, we have to examine every little piece of our code to be able to get little gains. This can be done by profiling. It means measuring our code to be able to find the slower parts. So we can find which parts of our code takes slower or takes too long. And then as doing the same operation on lines, we can find the problematic code block. On the other hand, if you are not an expert on this are this would be very tough.

Android SDK involves some useful tools which is very helpful at this kind of situations.

Profiling with Traceview

Traceview is a graphic viewer to be used for executions logs’s tracing in your code as using Debug class. Traceview helps to debug your application and profile your performance.

Tool->Android->Android Device Monitor

Firstly you have to click the process that you want to profile on DDMS and then click the button that is marked at picture below, then it starts to record. You can try the trace operation on your own application or google’s sample project — Project Sunhine. The needed instructions to be able to installations lie on github.

When you click, you will see the screen below. You can choose sample and 1000 microsecond. It means the profiling will get information about which method being executed at that moment from your application at every 1 millisecond. Trace based profiling which is the second option traces every methods.

The trace operation will be started after clicking OK. Meanwhile, we can use the application which we choose. You can click the same icon which is on the image below to stop again.

You will see an output as below. As seen on the image, Traceview has two panes. One of them is Timeline Pane and other one is Profiling Pane. You can use Find which is at the very bottom of the screen to filter the profiling results. For example, if you want to learn how long a method takes to be executed, you can find by searching.

Timeline pane visualizes how your code executes over time.

  • Each row shows a thread.
  • Each bar on the timeline is a method executing.
  • Each color is for a different method; every time a method executes, you see the same color bar.
  • The width of its bar indicates how long the method takes to execute.

If you double-click one of the bars, you will see it on profiling pane, too. So, if you see a bar takes too long and click it, you will see its equivalent on the profiling pane and find the problematic method easily.

On the other hand, Profiling pane shows the list your methods.

  • You can select a method to see who called it (Parent) and who it’s calling (Children).
  • The selected method is also highlighted in the Timeline pane.
  • The columns show exclusive and inclusive CPU and real times, percentages, ratios, and how often a method was called.
  • The exclusive time is the time spent just in the method itself, which can help you find issues within that specific method.
  • The inclusive time is for the method and all methods it calls, which can help you find problems with your call tree.
  • The Calls+Rec column shows how many times a method was called recursively, which can help you track down performance issues.

Batching And Caching

We can say that Batching and Caching are the most important performance techniques. Actually, all we know them and use them but it is worthwhile to mention about briefly.

Some functions or operations could take longer and need to as like this, although they are written in how should be. As an example, we may need to load data to a location on memory before execution or sort the datas before search. But if we do these operation in many times, we can create serious performance problems.

What need to be done to solve this kind of performance issues is batching which means elimination of operations being done at every execution. This is mostly done on preparing date before using it.

For example, we need to search and also sort related to search algorithm before search operation. Basically, we can write a function giving the target array and target value as parameters. Sorting and then we can write the searched value. But if we search 10.000 value and target array is formed from millions values, then it will be much more complicated. In that case, instead of sorting at every search, we should sort whole list at ones and as keeping this information, search operation can be done according to this. This is totally batching.

Another technique similar to batching and very important is caching. In modern computer architecture, the whole aim of RAM is keeping the short term information in cache and providing quick access. For example, we can say that the total aim of data centers saving frequently accessed data. Thanks to this, we do not have to go to miles away servers at every time.

Blocking the UI Thread

To be able to our app’s perform well, each function should be executed efficiently and also where and when being executed are very important.

When we start an Android application, firstly the main(ui) thread is created. Main thread is responsible from executing our code, event’s being associated with related views and executing drawing functions.

Why it is said that main thread is also ui thread is being the thread of users’ interacted with. For example, when we touch a button on screen, UI thread dispatches view’s touch event, view sets the button state as pressed and sends a request to the event queue. And then, ui thread process this request and notifies the button as setting itself pressed. This process is repeated in the middle of the operation at each touch event and if onTouch function’s being processed takes too long, then the time that the users’ waiting to see the update will increase. (You can examine from the process below.)

If we move on examining the the pic. above, the code that our input will be handled, rendering and update operation share the same cycle. It means that, UI can not draw itself in the middle of the computing.

Basically, it can cause missing the 16 ms. (dropping rendering frame)

So how can we solve this?

Firstly, we need to define the works that we do not need to do in main thread, it can be questioned as asking “Do I need to this for draw process?” After that, this operations should be transferred to another thread, so ui thread is not locked.

For example, we have a submit button and we order something when we click the button. In that case, taking the approval and sending mail could be done in a different thread.

In addition, Android UI toolkit is not trade-safe. It means, you can trigger the ui thread from worker threads but you shouldn’t do. Android has two simple rules for this, single thread model:

  1. Do not block the UI thread
  2. Do no reach the Android UI toolkit outside of the UI thread

For instance, the code below loads image from url and then shows it and also does it in another thread. But, we are chewing the most basic rule here. UI toolkit was reached from outside. At this example, imageview is updated by worker thread and this can cause another problems.

public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork("http://example.com/image.png");
mImageView.setImageBitmap(b);
}
}).start();
}

To solve this problem, Android gives us some method to reach the UI thread from worker thread:

For example, we could solve this problem with using View.post(Runnable) method.

public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap bitmap =
loadImageFromNetwork("http://example.com/image.png");
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}

At the sample above, network operation is done by another thread and imageView is updated from UI thread.

We can use Handler at more complicated situations, but the best option is using AsyncTasks.

Async Tasks: AsycnTask provides doing async task in user interface. It does the blocking operations in worker thread and forward the results to UI thread. While using AsycnTask, we do not have to handle threads on by own.

Its structure is simply like below. I calls blocking operations in doInBackground method and ones it is completed, onPostExecute() method is called.

public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}

Container Performance:

Another subject is using the data structure effectively. You see the comparison between hashmaps below.

We can identify the problematic data structures as profiling Android MPIs.

Analyzing UI Performance with Systrace

The Systrace tool allows you to collect and control. (trace)It shows where time and CPU cycles are being spent, displaying what each thread and process is doing at any given time. In addition, it inspects the captured tracing information to highlight problems that it observes, from list item recycling to rendering content, and provide recommendations about how to fix them.

Simply, we should put the code that we want to trace between this two lines.

Trace.beginSection("Data Structures");
// TODO:
Trace.endSection();

The sample above shows how it will look like for 5sn, if the app’s performance is not well.

Each app has a line involving frame circles. And it is mostly green. If it is yellow or red then it means we missed the 16.6 ms frame window. While doing zoom-in, we can get information about long-lasting frames.

If we click the problematic frame, it gives us a solution for it.

In addition, if we click the alert tab lying on right corner, we can see each alert.

Referances:

--

--

Elif Boncuk

Engineering Manager, Digital Banking @GarantiBBVA | #Android #GDE | formerly volunteer @MobilerDev @gdgIstanbul @wtmist | #CE @Hacettepe1967 #MBA @Bahcesehir