How to understand Android SDK profile traceview...?

2.4k views Asked by At

I have some code that uses Jsoup to get and parse some html pages, and then I manipulate the html tree, before passing it to a WebView that draws it. If I bypass my manipulations, the code runs in acceptable times (2-3 seconds) on the Android SDK simulator, but when I do my manipulations the time jumps to unacceptable (~60 seconds to just load a single page!).

Using Eclipse and the Android SDK I had a run profiled, and now I'm trying to interpret the results. from here http://android-developers.blogspot.com/2010/10/traceview-war-story.html took the tip to sort profile on the "Exclusive Cpu Time %". To my surprise, my own code did not even list at 1%. The biggest time consumer is android.view.ViewGroup.drawChild() at 11.9%. The first non-android function listed (as sorted by exclusive cpu %) is java.lang.ref.Reference.get() and it lists at 0.4%.

But I guess teh strangest thing is that of my own code, I can only find my AsyncTask's doInBackground() listed; the functions this calls in turn are not even present, even though I can see by the debug output that they are called. Why are those not listed?

I don't understand what to make of any of this. Any hints are very much appreciated.

1

There are 1 answers

0
class stacker On

Although I don't have a reference at hand, I think it's safe to assume that Android executes AsyncTask.doInBackground() in a Thread with priority android.os.Process.THREAD_PRIORITY_BACKGROUND

This means that this Thread is scheduled in the context of a Linux cgroup (scheduling class) for which -- always or under frequent circumstances, I'm not sure and have read various claims -- an upper bound of common CPU time of 5% or 10% -- again, different sources make different claims -- is applied.

In other words, all background threads have to share 5% or 10% of the available CPU time. Again, I have read claims that this is dynamically adjusted if the foreground and real time tasks are idle, but I'd be happy to be pointed to a credible source myself. Also, I wouldn't count on it since the user can listen to a real time audio stream while using my app.

If you adjust the background Thread's priority, like so:

private static final int bgThreadPrio = Process.THREAD_PRIORITY_BACKGROUND +
                                        Process.THREAD_PRIORITY_MORE_FAVORABLE;
protected YourReturnType doInBackground() {
    Process.setThreadPriority(bgThreadPrio);
    ....
}

then you achieve two things.

  • You lift the Thread out of the background cgroup such that it does not have to share 10% of CPU time with the other background threads (at least currently, until Android changes its policies in this regard).
  • You assign a priority to the Thread which usually will not have an extremely bad impact on User Interface and Real Time threads, because THREAD_PRIORITY_DEFAULT is 0 while THREAD_PRIORITY_BACKGROUND is 10. So your Thread will run at priority 9 which is much worse than 0 but it will avoid the artificial limit of the background tasks.

However, you also probably change the priority of the Thread which the underlying AsyncTask executor provides for your AsyncTask. This Thread is going to be recycled, and it may be a single Thread or chosen from a pool. So it might be a good idea to set the priority in all doInBackground() methods in all AsyncTasks in your app.