Writing your profiler to analyze application performance on Android

FunCorp
5 min readAug 5, 2021

As the application grows, it should be audited to detect implicit performance degradation. A while ago, I was auditing the iFunny comment section and developed a custom profiler. It will not replace the tools available on the market like Android Profile from Android Studio, Battery Historian, and Systrace, but it brings several advantages:

  1. The negative impact of the profiler on application performance is minimized.
  2. Documentation of iterations of the application performance optimization.
  3. Flexibility in obtaining metrics.

Further, we’ll tell you more about the existing tools and move on to analyzing CPU time, memory, network usage, and battery consumption with the help of a custom solution.

Commonly Known Tools

There are not many of them, and I have already listed the main ones, let’s take a closer look at them:

Android Profiler

Built into Android Studio, it allows you to monitor consumption of CPU, Memory, Network, and Energy while using the application and provides many valuable tools. But it has both advantages and disadvantages.

Disadvantages —

  • In the app’s functioning, there appear lags due to the mechanisms of obtaining metrics. It does not allow you to control the main resource consumption parameters, close-in use to the actual conditions.
  • The application may crash spontaneously.
  • Lack of flexibility in obtaining metrics. For example, to not constantly dump the heap memory at critical indicators, it is desirable to have Android Profiler do it for you.

Systrace

A tool that allows you to gather and inspect the running time of the code parts for all the processes on the device.

Battery Historian

It is needed to get additional information on the application’s performance, such as the percentage of battery consumption and conditions that affect consumption.

Initially, we chose the Android Profiler as the primary profiling tool, but its disadvantages became critical. I want to show clearly and quantitatively, with the slightest error, the stages of comments optimization. That’s why we decided to develop a custom profiler and build charts based on it in any convenient tool, for example, Excel or Numbers.

The Espresso autotest framework can be used as an engine to perform long, routine, repetitive actions.

CPU

Getting the CPU time used by the application process is quite tricky, but since Android is developed on the Linux operating system, you can run a particular command, parse the response, and record the value obtained.

For example, you can use the command /proc/<PID>/stat, and get the PID from Android.os.Process.myPid(). But in Android O, they’ve limited the access to /proc, which forced us to use another command top -n 1, where -n is the number of updates iterations. Below is the code that captures the CPU consumption value of the corresponding process.

recordCpu() is wrapped in try-catch, because errors may occur on some devices. All obtained values are written in cpu_usage.txt, from where data is taken to build analytical information and charts.

Memory

As for memory, it is pretty simple. There are Debug and Runtime classes, which provide the necessary functionality. If the heap memory is 90% full, the memory dumping mechanism is started automatically. Thus, the developer does not need to monitor the progress of the tests and can safely take a break for coffee. After the tests are completed, the dump can be opened using the Android Profiler in Android Studio (Profiler → + → Load from file). Below is the code analyzing the consumption of the memory by the application.

Thus, there appear several columns with the necessary information in the mem_usage.txt file, which can be analyzed in different ways from the analytical point of view.

Network

The android.net.TrafficStats class is in place for network usage metrics, it can be used to get received and transmitted traffic. Below is the code for recording data traffic. All data is recorded in the file network_usage.txt.

Battery

Obtaining battery consumption metrics is also a relatively simple task. BatteryManager stores the current battery charge status in sticky Intent, which can be obtained by passing Intent.ACTION_BATTERY_CHANGED to the registerReceiver IntentFilter with action Intent without registering the receiver (of course, it can be provided, but this is not required in this task).

Below is the code for obtaining battery usage metrics.

All metrics exporters are managed by the AppMetricUsageManager. Once a second, resource consumption is analyzed and the corresponding values are recorded in files specified in the exporters. Its code is quite simple:

safeDispose() is an extension that executes “dispose” if the Observable is not null or has not been disposed of before.

After the tests are completed, you can get beautiful charts:

A reasonable question arises. What is the point of all this if there exists a profiler?

At the beginning of the article, the custom solution has some advantages over the Android Profiler — no crashes, lags, flexibility in obtaining metrics, and creating documentation for analysis of optimization progress. At the same time, this approach is not a replacement for Android Profiler, Systrace, or Battery Historian. It only supplements them.

--

--

FunCorp

Since 2004, we’ve been doing our part in changing the entertainment & tech space. Learn more at http://bit.ly/3XWJemV