App Performance — Improving the app startup time

Tanvi Goyal
Team Pratilipi
Published in
5 min readOct 21, 2022

With a DAU of 1.7M and MAU of around 15.6M, Pratilipi has crossed over a billion stories read per month. Considering the scale we operate in, and knowing the fact that most of our users belong to tier 2 and tier 3 cities, it has become imperative to focus on the performance of the app to ensure a smooth and seamless experience for all of our users irrespective of the device they are using.

App Startup is one of the key metrics when measuring and optimizing for the overall app performance. To make sure it is the right and important thing to do at this point of time and to align the business metrics and other stakeholders with its impact, we did an initial research and analysis of the current stats concerning the app startup performance. Android vitals provided some insightful statistics and a room for improvement was detected.

Here’s some of our insights which we decided to work upon:

  • Cold and Warm startup time
  • Allocation/Deallocation of resources
  • View Hierarchy

Let’s discuss all these in detail

A cold start refers to an app’s starting from scratch i.e the system’s process has not created the app’s process by this time. It happens when the app is launched for the first time since the device booted, or since the system killed the app. This type of start presents the greatest challenge in terms of minimizing startup time, because the system and app have more work to do as compared to the other launch states.

A warm start is the time when the system’s process is initiated but application’s and activity’s onCreate have not been called as of now.

The resources we were allocating during startup was another major factor to consider. Other than Android Vitals, we used Android Studio inbuilt profiler to analyze the in depth process of allocation/deallocation of resources while app startup to understand what things take the most amount of time and resources from the user’s device.

Though we did not find much optimizations to be done in Application’s onCreate method where we were already initializing only the required 3rd parties libraries and were doing things as asynchronously as it can be, we found the opportunity to optimize the view hierarchy of our Language selection screen which is the very first screen user sees after launching the app.

Other than Vitals and Android Profiler, going deeper in investigation, we also integrated the macro benchmark library to provide us with clear data points about average improvements we can expect through the optimization.

Macro benchmarking

The Macrobenchmark library measures larger end-user interactions, such as startup, interacting with the UI, and animations. Integrating the benchmark in the app was a simple process as mentioned in the Android Developers Documentation. Below are some samples of the tests that we run:

The time to initial display (TTID) metric measures the time it takes for an application to produce its first frame, including process initialization (if a cold start), activity creation (if cold/warm), and displaying first frame. Android Runtime (ART) uses the data from these metrics to efficiently precompile code for optimization of future startups.

Adding baseline profiles to the app was one of the best solutions to optimize app startup time.

Baseline Profiles

Baseline profiles are a list of classes and methods included in an APK used by Android Runtime (ART) during installation to pre-compile critical paths to machine code.

The Macro benchmark library provides us a way to generate these profiles automatically using test cases as shown below —

@ExperimentalBaselineProfilesApi()
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
@get:Rule val baselineProfileRule = BaselineProfileRule()

@Test
fun startup() = baselineProfileRule.collectBaselineProfile(
packageName = packageName
) {
pressHome()
startActivityAndWait()
}
}

Internally, collectBaselineProfile function runs the app from scratch 3 times and lists down the functions that are frequently used and can be pre compiled when launching the app. It takes into consideration the libraries initialized during application’s and activity’s onCreate and optmizes for the precompilation for their code as well. It combines it all in a single file named baseline-prof.txt.

They are shipped as a part of the APK to play, and then sent from PlayStore to users when an app is downloaded. During installation, ART performs Ahead-of-Time (AOT) compilation of methods in the profile, resulting in those methods executing faster.

Testing Baseline profiles locally

One of the biggest benefits of Baseline Profiles is that they can be developed and evaluated locally so developers can see realistic end-user performance improvements. Macro benchmark provides a way to write certain tests to measure performance improvements with and without these profiles.

@RunWith(AndroidJUnit4::class)
class BaselineProfileBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()

@Test
fun startupNoCompilation() {
startup(CompilationMode.None())
}

@Test
fun startupBaselineProfile() {
startup(
CompilationMode.Partial(
baselineProfileMode = BaselineProfileMode.Require
)
)
}

private fun startup(compilationMode: CompilationMode) {
benchmarkRule.measureRepeated(
packageName = packageName,
metrics = listOf(StartupTimingMetric()),
iterations = 10,
startupMode = StartupMode.COLD,
compilationMode = compilationMode
) {
pressHome()
startActivityAndWait()
}
}
}

Below are some of the results we got:

Doing multiple rounds of testing with various device types and conditions, we were expecting around 10–15% improvement in the app startup.

Results in Production

Android vitals provided us with adequate data regarding this. The startup time metrics should show an improvement on p90 percentile ranging from 4625–4750 ms(without profiles) to 3875–4000 ms (with profiles) i.e around 16–17% improvement.

I hope you find this article informative. Any feedback, suggestions are always welcomed and appreciated!

Find out these resources for further references:

  1. https://proandroiddev.com/android-runtime-how-dalvik-and-art-work-6e57cf1c50e5
  2. https://android-developers.googleblog.com/2022/01/improving-app-performance-with-baseline.html

Keep Learning!

Tanvi Goyal

--

--