How To Use Kotlin’s Built-In Functions To Measure Code Execution Time
Investigate performance issues or find out which implementation is best
Kotlin provides straightforward ways to measure execution time. This comes in handy in many places. You can use it to compare algorithms or check which part of your code is slow.
Let us first look at the classic (Java style) way to measure execution time. Only then can we appreciate the benefits of Kotlin.
As an illustrative example, we compare the performance of ArrayList
and LinkedList
. We measure the time it takes to add 50 million integers and then sum them up. Check out the code on GitHub.
The Classic Java-Style Way
If you have worked with Java for some time, you might have seen something like this (well, obviously, this is in Java, not in Kotlin).
val begin = System.nanoTime()
val result = arrayListCode()
val duration = System.nanoTime() - begin
println("ArrayList took ${TimeUnit.NANOSECONDS.toSeconds(duration)} seconds and got $result.")
val begin2 = System.nanoTime()
val result2 = linkedListCode()
println("LinkedList took ${TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - begin2)} seconds and got $result2.")
This approach works just fine, but it comes with downsides.
First, we must convert the result from nanoseconds to seconds. Second, we need to introduce either one or two variables and a long line of code to get our result.
This can become messy if you need to measure different parts of the same method. It easily happens that you calculate the differences with the wrong variables.
It is easy to see that there is a simple solution: extracting a method for time measuring. But why should we reinvent the wheel?
The Kotlin Way of Measuring Time
measureTimeNanos and measureTimeMillis
The simplest way in Kotlin is to use measureTimeNanos
and measureTimeMillis
from kotlin.time
.
val arrayListDuration = measureNanoTime {
arrayListCode()
}
println("ArrayList took ${TimeUnit.NANOSECONDS.toSeconds(arrayListDuration)} seconds and got ?")
val linkedListDuration = measureTimeMillis {
linkedListCode()
}
println("LinkedList took ${TimeUnit.MILLISECONDS.toSeconds(linkedListDuration)} seconds and got ?")
If you look under the hood, these functions do the same as you saw above:
public inline fun measureTimeMillis(block: () -> Unit): Long {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
val start = System.currentTimeMillis()
block()
return System.currentTimeMillis() - start
}
The methods return the execution time, so we do not need to calculate them manually. However, we still need to convert the unit manually. And there is a big caveat! You cannot get the return value of the measured function.
Another method you can use is measureTime.
This returns a Duration
object. Duratio n
offers you methods to convert the duration to the time unit you want. However, the return value is still lost:
val arrayListDuration = measureTime {
arrayListCode()
}
println("ArrayList took ${arrayListDuration.inWholeSeconds} seconds and got ?")
There is, of course, a better solution.
Best of both worlds: measureTimedValue
So far, I can get concise syntax but no return value or a return value and bloated syntax. Luckily, there is a way to get both: measureTimedValue
.
val arrayListValue = measureTimedValue {
arrayListCode()
}
println("ArrayList ook ${arrayListValue.duration.inWholeSeconds} seconds and got ${arrayListValue.value}.")
You can go further and use another cool Kotlin feature, namely destructuring:
val (value,duration) = measureTimedValue { linkedListCode() }
println("LinkedList took ${duration.inWholeSeconds} seconds and got ${value}.")
This enables you to sprinkle time measurements into your code. Just wrap it with measureTimedValue
and use Kotlin’s destructuring to get the duration and the code result in one go.
If you look at the code on GitHub, you’ll probably notice the annotation @OptIn(ExperimentalTime::class)
. We need this because JetBrains marked the more advanced time-measuring methods as experimental. The methods might change their behavior or syntax in the future. You need to keep this in mind. I wouldn’t recommend using these methods in production code long term, anyway.
Conclusion
Measuring execution time in Kotlin is very easy. You can just plug it in as needed without polluting your scope with ambiguous variables.
Here are some useful links:
Complete code on GitHub.
Thank you for your time!