How can I get the time it takes a function to test the performance of functions in Kotlin

Viewed 17993

I need to check how long does a function need to run. I have the following functions which address the same task:

mixAnimalsA

fun mixAnimalsA(a1: Animal, a2: Animal) =
        when (setOf(a1, a2)) {
            setOf(Animal.OWL, Animal.Leopard) -> Beast.OWLPARD
            setOf(Animal.ELEPHANT, Animal.BUTTERFLY) -> Beast.BUTTERPHANT
            else -> throw Exception("Not possible combination")
        }

mixAnimalsB

fun mixAnimalsB(a1: Animal, a2: Animal) =
        when (setOf(a1, a2)) {
            (c1 == Animal.OWL && c2 == Animal.Leopard) ||
                    (c2 == Animal.OWL && c1 == Animal.Leopard) -> Beast.OWLPARD
            (c1 == Animal.ELEPHANT && c2 == Animal.BUTTERFLY) ||
                    (c2 == Animal.ELEPHANT && c1 == Animal.BUTTERFLY)-> Beast.BUTTERPHANT
            else -> throw Exception("Not possible combination")
        }

Animal and Beast are enumerations. How can I measure how long each function takes to run?

6 Answers

Measure execution time and also keep the result

Standard Library

The standard library function measureTimedValue may be used to measure execution time and at the same time capture the result. This tuple of values is being exposed as a TimedValue(value: T, duration: Duration):

@ExperimentalTime
fun main() {
    val (result: String, duration: Duration) = measureTimedValue {
        operation()
    }
    
    print("Got $result after ${duration.inMilliseconds} ms.")
}

Note that this API is experimental and requires explicit opt-in.

Obsolete custom implementation

(This used to be my answer before the standard lib was extended)

If you want to measure the execution time and also access the measured function's return value afterward, here's a custom solution:

inline fun <R> executeAndMeasureTimeMillis(block: () -> R): Pair<R, Long> {
    val start = System.currentTimeMillis()
    val result = block()
    return result to (System.currentTimeMillis() - start)
}

You can call it like this:

val (response, duration) = executeAndMeasureTimeMillis {
    restTemplate.getForObject<AnyObject>(uri)
}

If it's enough to get the time as output on the console:

fun <T> timeIt(message: String = "", block: () -> T): T {
    val start = System.currentTimeMillis()
    val r = block()
    val end = System.currentTimeMillis()
    println("$message: ${end - start} ms")
    return r
}

Usage:

val result = timeIt("note about the code") {
   // do something...
}

Output (example):

note about the code: 1ms

For the benchmark of some code block and getting the result a same time, i do some refactor of the standard method in TimingKt class to give us output generic result and at the same time display a given log. Here is my example :

/**
     * Executes the given block and show the elapsed time in milliseconds in a given message.
     *
     * @param block which will be bench marked
     * @param logMessage log message to be displayed
     *
     * @return a generic result
     *
     */
    private fun <T> measureTime(block: () -> T, logMessage: String): T {
        val start = System.currentTimeMillis()
        val t = block()
        val consumedTime = System.currentTimeMillis() - start
        Log.d(TAG, "Calculation of $logMessage time :$consumedTime milliseconds")
        return t
    }

And how it will be used :

return measureTime({ 
// given block with return result
}, "message to be displayed typically the name of method which will be calculated") 

This is my simple time test code.

class TimeCounter(val name: String) {
    var totalTime: Long = 0
        private set

    var count: Int = 0
        private set

    var minTime: Long = Long.MAX_VALUE
        private set

    var maxTime: Long = Long.MIN_VALUE
        private set

    fun addTime(time: Long) {
        this.count++
        this.totalTime += time

        if (this.minTime > time) {
            this.minTime = time
        }

        if (this.maxTime < time) {
            this.maxTime = time
        }
    }

    val averageTime: Double
        get() = this.totalTime / this.count.toDouble()

    fun printTime() {
        println("(time about : '$name'), totalTime : $totalTime, count : $count, " +
                "average : $averageTime, minTime : $minTime, maxTime : $maxTime")
    }

    fun <T> runWithTimeCount(run: () -> T): T {
        val startTime = System.currentTimeMillis()
        return run().also {
            this.addTime(System.currentTimeMillis() - startTime)
        }
    }
}

you can use 'TimeCounter' like this, (example)

var sum = 0
val testTimeCounter = TimeCounter("logic1")
for(i in 0 until 100){
    sum += testTimeCounter.runWithTimeCount { 
        logic1(i) // your logic
    }
}

println(sum)
testTimeCounter.printTime() // totalTime, average, minTime, maxTime

Execute function, measure its performance and logs performance - in same call

this solution will help folks who want to measure and log performance, execute function at same time, also is a cleaner approach when there is multiple performance measurement involved of different functions

Create functions as such:

//the inline performance measurement method
private inline fun <T> measurePerformanceInMS(
        logger: (Long) -> Unit,
        function: () -> T)
: T {
    val startTime = System.currentTimeMillis()
    val result: T = function.invoke()
    val endTime = System.currentTimeMillis()
    logger.invoke( endTime - startTime)
    return result
}

//the logger function
fun logPerf(time: Long){
    Log.d("TAG","PERFORMANCE IN MS: $time ms ")
}

//the function whose performance needs to be checked
fun longRunningFunction() : Int{
    var x = 0
    for (i in 1..20000) x++
    return x
}

This way you can keep logging, performance computation and function execution under a single function call and no code replication needed.

If you require nano second measurement then use System.nanoTime()

USAGE :

val endResult = measurePerformanceInMS({time -> logPerf(time)}){
            longRunningFunction()
        }

NOTE : here the 'endResult' will carry the result of function whose performance was being measured.

Related