Threading out of a performance labyrinth with Systrace

TJ
4 min readNov 15, 2018

I really love animations in Android. They add so much to the UX of an app that I really wish more product owners added them as part of their acceptance criteria for new features in a mobile app.

The thing with animations however is that they can be quite tricky; timing them has to be perfect especially when Views have other dependent View’s in their layout hierarchy. Perhaps more foreboding, is the need to keep animations running at a consistent 60 frames per second, else they begin to hurt the user experience, rather than help it, and at that point why even bother?

In my app Teammate, I had an issue. On screens with editable text, the initial transition to bring the fragment container in stuttered terribly. This was very bad as the screen typically had 3 animations to run concurrently on entrance:

  1. It had to use a SharedElementTransition to expand a thumbnail image to a header image.
  2. It had to apply a dark tint to the header image to make the Toolbar title easier to read.
  3. I had to animate the FloatingActionButton as it’s text, size and icon changed.

I ruled out the usual suspects, inefficient layouts, api calls on the UI thread, everything, and was still feeling flummoxed. Certain my current approach would take me nowhere, I turned to systrace.

What is systrace?

From the description at the Android Developer’s site:

The systrace command allows you to collect and inspect timing information across all processes running on your device at the system level. It combines data from the Android kernel, such as the CPU scheduler, disk activity, and app threads, to generate an HTML report.

A sample systrace report, culled from the Android Developers site

What this is saying is that systrace is an amazing way to find out exactly what your app is doing and where it’s doing it. To run it, you simply navigate to your Android sdk’s platfoorm-tools directory, and go into the systrace folder. once there run the following command:

python systrace.py -o mynewtrace.html -a <your app's package name> sched freq idle am wm gfx view binder_driver hal dalvik camera input res

And the output will be a lovely html report. If you have an idea of where your bottleneck may be, the Trace utility class is indispensable as it let’s you add markers to the generated html report.

The following is a very simplified usage of the Trace class to demonstrate it’s ease of use. It’s a slightly modified version of that on the Android developer site, formatted so it’s easier to read, as it omits the try / finally blocks when calling Trace. While not explicitly necessary, your trace markers will be mismatched if an exception is thrown and Trace.endSection() isn’t called for the associated section.

A sample utilization of the Trace utility class

Let’s look at a sample trace report shall we?

A trace of a rather ill performing app

Handily, RecyclerView already adds method to trace both the layout and bind methods internally. From this, it appears that binding my ViewHolder takes an abnormally long time, 95 milliseconds to exact. It wasn’t because my layout was inefficient either, the purple marker next to RV onBindView is the inflation of the View in the ViewHolder; it takes 4 times as long to set properties on the ViewHolder than to create it. Zooming in closer on the trace markers so that my custom markers become visible yields the following:

systrace snapshot with custom markers

My custom markers areInput entrance, Input Params, Input Set, and Input Misc. Input Set is the super tiny one in a light purple and all it does is actually set values to fields; methods like EditText.setText() and the like. The issue therefore was my code and not the Android Framework.

Further digging let me realize for each other custom marker, I was actually pulling a rather large String from SharedPreferences; the same string in fact, both in Input Params and Input Misc, hence why they both took the exact same amount of time.

This is where systrace really shines, the ability to glean exactly where in your code the hiccups occur, especially when custom markers are used. I know for a fact it would have taken me much longer to identify the root cause without systrace, and I highly encourage reading the Android Developer’s site for more information. It’s a very, very handy tool, and doesn’t get enough love in my opinion.

Finally, lets look at the frame performance with systrace with the SharedPreference bottleneck removed.

A sequence of wonderfully rendered frames, well at least to the end anyway

Look at all that green! A lovely sequence of highly performant frames in quick succession, even the most ardent pixel peepers would be pressed trying to find jank.

That’s it! I really hope this convinces you to give systrace a try, I really cannot emphasize more how lovely it is. Thanks for reading!

--

--