33

What is the most precise way to measure startup time of an Android app?

By startup time I mean the difference between 2. and 3. :

  1. The app process is not running
  2. User clicks on app icon in the launcher
  3. Main Activity is fully initialized

So I basically need to somehow get time elapsed since JVM started and log it.

fhucho
  • 34,062
  • 40
  • 136
  • 186
  • "By startup time I mean the difference between 2. and 3." That would be 1. Or possibly -1. :-) More seriously, are you building your own firmware, or are you trying to get this from a stock environment? Also, is this a development-time thing, or a production-runtime inquiry? – CommonsWare Jan 02 '13 at 15:55
  • I want this to track the startup time on different devices and Android versions during the development. Another reason is that some user complained that the app startup became slow since the last update, so it would be nice to see numbers. Of course I could simply measure only the time since onCreate() was called... but knowing the real startup time just feels better :) It also allows me to say "this slows startup time only by 5%", so it's not a big deal. – fhucho Jan 02 '13 at 16:17

9 Answers9

19

I understand I am too late to answer, nonetheless, this precisely answers the question.

This information gets logged on Logcat by default for API version 19 or higher.

From Android 4.4 (API level 19), logcat includes an output line containing a value called Displayed. This value represents the amount of time elapsed between launching the process and finishing drawing the corresponding activity on the screen.

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms

The key is looking for it in the right place -

If you’re tracking logcat output from the command line, or in a terminal, finding the elapsed time is straightforward. To find elapsed time in Android Studio, you must disable filters in your logcat view. Disabling the filters is necessary because the system server, not the app itself, serves this log.

The extracts are from the documentation.

Community
  • 1
  • 1
user2520215
  • 603
  • 8
  • 15
13

I'm going to interpret your question as 'Is my app startup time fast enough. How can I check I have done everything I can do?'

The startup time is largely a false metric as it will vary across devices and ROMs. I guess what you're most likely to be interested in is how much of your code is taking a long time to execute and what is potentially blocking the main thread.

I've found the most effective way of doing this is to use Traceview on the app start and then reviewing how long it takes the method to execute and if there are any gaps on the main thread.

Start tracing:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Debug.startMethodTracing("startup");
    }
}

Stop tracing:

@Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    Debug.stopMethodTracing();
}

Once the trace has been collected, you should be able to see anything that is having a major impact on startup time. In my case, seen below, there was a big gap on the UI thread where is was being blocked.

main thread blocked

It transpired that both Crashlytics and Coremetrics were requiring a call to randomUUID() which was then being synchronized across threads and blocking the main thread. The solution was just to spin up a new thread to initialise the Coremetrics code.

This is something I would not have otherwise picked up with just measuring the startup time, but it actually sped up the app 'startup time' by a few hundred milliseconds.

Here's another snapshot after spinning off a separate thread for Coremetrics initialisation:

main thread not blocked

Ben Pearson
  • 7,532
  • 4
  • 30
  • 50
  • Do you have any idea on how can 3rd party libraries can be initialized in another thread instead of main to reduce the app start time? – Rahulrr2602 May 16 '19 at 11:35
9

Check in adb shell in below manner.

adb shell
adb logcat -b events | grep am_activity_launch_time

[Output]
01-01 12:32:53.469 1236 1262 I am_activity_launch_time: 
    [0,205360373,com.sec.android.app.clockpackage/.ClockPackage,378,**378**,0]

Remarks:
Launch time for Clock is 378ms.
yennsarah
  • 5,467
  • 2
  • 27
  • 48
senapati
  • 101
  • 1
  • 3
  • 4
    On newer devices the ActivityManager logs this a bit differently, so use this: "adb logcat -s ActivityManager:I | grep Displayed". The result will be something like "I/ActivityManager( 288): Displayed com.foo.bar/.main.MainActivity: +1s313ms". – cermak.cz Mar 22 '16 at 15:08
5

Wrap the entire onCreate() method in a TimingLogger. Just put this at the beginning:

TimingLogger timings = new TimingLogger(TAG, "methodA");

and this at the end:

timings.dumpToLog();

If you want to drop times at some intermediate step, you can do timings.addSplit("name"); to get the time it took to get to that step.

Tim
  • 248
  • 3
  • 14
  • I didn't know about TimingLogger, thanks for the tip. However, this doesn't measure the time between the moment the app is launched by user and the moment onCreate() is called. – fhucho Jan 02 '13 at 19:43
2

A simple way to display startup time in android.

enter image description here

Sometimes the Displayed line in the logcat output contains an additional field for total time. For example:

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)

In this case, the first time measurement is only for the activity that was first drawn

Source: Time to initial display

Albert Khang
  • 621
  • 6
  • 17
1

It is possible to implement time tracking using the next code:

Override your Application:

public class CustomApplication extends Application {
    public final static long APP_START_TIME = System.currentTimeMillis();

    /**
     * Do all other application stuff
     */
}

And add few rows to your main Activity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final View contentView = findViewById(android.R.id.content);
        contentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (Build.VERSION.SDK_INT >= 16) {
                    contentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                } else {
                    contentView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }
                long launchTime = System.currentTimeMillis() - CustomApplication.APP_START_TIME;
                Log.e("TEST", "App launch time = " + launchTime);
            }
        });
    }
}

And don't forget to define your custom application in Manifest:

<application
    android:label="@string/app_name"
    android:name=".CustomApplication" >

</application>

Important: You have to kill your application before launch, because Application stores static variable which tracks initial time.

Oleksandr
  • 6,226
  • 1
  • 46
  • 54
  • 1
    reporting on `onGlobalLayout` is actually the correct measure. Thanks for sharing this. – Yash Jul 04 '18 at 23:35
1

Use SysTrace

Also the Trace class can be used to measure sections using

Trace.beginSection("name");
Trace.endSection();

This YouTube video is a quick primer as well.

easycheese
  • 5,859
  • 10
  • 53
  • 87
1

I think this has been built into Firebase Console, under performance now enter image description here enter image description here

ericn
  • 12,476
  • 16
  • 84
  • 127
-1

One possibility would be is to save the time at the beginning of the onCreate() method and at the end of the onCreate() method and then subtract those times from each other to get the time taken to initialize the app.

Luke Taylor
  • 9,481
  • 13
  • 41
  • 73
  • 1
    This unfortunately doesn't measure the time between the moment the app is launched by user and the moment onCreate() is called. – fhucho Jan 02 '13 at 19:43