Measuring Time

How much time an operation or sequence of operations takes to complete is a critical piece of information when it is time to optimize code. Without knowing how much time is spent doing something, your optimizations are impossible to measure. Java and Android provide the following simple APIs your application can use to measure time and therefore performance:

  • System.currentTimeMillis
  • System.nanoTime
  • Debug.threadCpuTimeNanos
  • SystemClock.currentThreadTimeMillis
  • SystemClock.elapsedRealtime
  • SystemClock.uptimeMillis

Typically, your application needs to make two calls to these methods as a single call is hardly meaningful. To measure time, your application needs a start time and an end time, and performance is measured as the difference between these two values. At the risk of sounding overly patronizing, now is a good time to state that there are 1,000,000,000 nanoseconds in one second, or in other words, a nanosecond is one billionth of a second.

NOTE: Even though some methods return a time expressed in nanoseconds, it does not imply nanosecond accuracy. The actual accuracy depends on the platform and may differ between devices. Similarly, System.currentTimeMillis() returns a number of milliseconds but does not guarantee millisecond accuracy.

A typical usage is shown in Listing 6–1.

Listing 6–1. Measuring Time

    long startTime = System.nanoTime();

    // perform operation you want to measure here

    long duration = System.nanoTime() - startTime;

    System.out.println(“Duration: ” + duration);

An important detail is the fact that Listing 6–1 does not use anything Android-specific. As a matter of fact, this measurement code is only using the java.lang.System, java.lang.String and java.io.PrintStream packages. Consequently, you could use similar code in another Java application that is not meant to run on an Android device. The Debug and SystemClock classes are, on the other hand, Android-specific.

While System.currentTimeMillis() was listed as a method to measure time, it is actually not recommended to use this method, for two reasons:

  • Its precision and accuracy may not be good enough.
  • Changing the system time can affect the results.

Instead, your application should use System.nanoTime() as it offers better precision and accuracy.

System.nanoTime()

Because the reference time is not defined, you should only use System.nanoTime() to measure time intervals, as shown in Listing 6–1. To get the time (as a clock), use System.currentTimeMillis() as it defines the return value as the number of milliseconds since January 1, 1970 00:00:00 UTC.

Listing 6–2 shows you how to measure, roughly, the time it takes for System.nanoTime() to complete.

Listing 6–2. Measuring System.nanoTime()

private void measureNanoTime() {
    final int ITERATIONS = 100000;
    long total = 0;
    long min = Long.MAX_VALUE;
    long max = Long.MIN_VALUE;

    for (int i = 0; i < ITERATIONS; i++) {
        long startTime = System.nanoTime();
        long time = System.nanoTime() - startTime;
        total += time;
        if (time < min) {
            min = time;
        }
        if (time > max) {
            max = time;
        }
    }

    Log.i(TAG, "Average time: " + ((float)total / ITERATIONS) + " nanoseconds");
    Log.i(TAG, " Minimum: " + min);
    Log.i(TAG, " Maximum: " + max);
}

On a Samsung Galaxy Tab 10.1, the average time is about 750 nanoseconds.

NOTE: How much time a call to System.nanoTime() takes depends on the implementation and the device.

Because the scheduler is ultimately responsible for scheduling threads to run on the processing units, the operation you want to measure may sometimes be interrupted, possibly several times, to make room for another thread. Therefore, your measurement may include time spent on executing some other code, which can make your measurement incorrect, and therefore misleading.

To have a better idea of how much time your own code needs to complete, you can use the Android-specific Debug.threadCpuTimeNanos() method.

Debug.threadCpuTimeNanos()

Because it measures only the time spent in the current thread, Debug.threadCpuTimeNanos() should give you a better idea of how much time your own code takes to complete. However, if what you are measuring is executed in multiple threads, a single call to Debug.threadCpuTimeNanos() won't give you an accurate estimate, and you would have to call this method from all the threads of interest and sum the results.

Listing 6–3 shows a simple example of how Debug.threadCpuTimeNanos() can be used. The usage is no different from System.nanoTime()'s, and it should only be used to measure a time interval.

Listing 6–3. Using Debug.threadCpuTimeNanos()

    long startTime = Debug.threadCpuTimeNanos();
    // warning: this may return -1 if the system does not support this operation

    // simply sleep for one second (other threads will be scheduled to run during that
time)
    try {
        TimeUnit.SECONDS.sleep(1);
        // same as Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    long duration = Debug.threadCpuTimeNanos() - startTime;

    Log.i(TAG, "Duration: " + duration + " nanoseconds");

While the code will take about one second to complete because of the call to TimeUnit.SECONDS.sleep(), the actual time spent executing code is much less. In fact, running that code on a Galaxy Tab 10.1 shows that the duration is only about 74 microseconds. This is expected as nothing much is done in between the two calls to Debug.threadCpuTimeNanos() other than putting the thread to sleep for one second.

NOTE: Refer to the TimeUnit class documentation. TimeUnit offers convenient methods for converting time between different units and also performing thread-related operations such as Thread.join() and Object.wait().

Of course, you can also measure time in your application's C code using “standard” C time functions, as shown in Listing 6–4.

Listing 6–4. Using C Time Function

#include <time.h>

void foo() {
    double duration;
    time_t time = time(NULL);

    // do something here you want to measure

    duration = difftime(time(NULL), time); // duration in seconds
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.239.182