[Kotlin] 코드 실행 시간 측정

수행 시간 측정

val startTime = getCurrentTime()
// do something
val endTime = getCurrentTime()
println("elapsedTime : ${endTime - startTime}")

일반적으로 성능을 측정할때는 어떤 기능을 수행하는데 걸리는 시간을 측정합니다. 위 코드는 어떤 기능을 수행하는데 소요된 시간을 보여줍니다.

Java

Java에서는 시스템의 시간을 가져오는데 기본적으로 System.currentTimeMillis(), System.nanoTime()을 제공합니다.

System.currentTimeMillis()

System.currentTimeMillis()1970/1/1 00:00:00 UTC을 기준으로 현재 시간을 리턴합니다. 시스템의 TimeZone에 관계없이 항상 UTC 시간을 리턴하기 때문에 보통 "Unix time", "epoch time"이라고 부릅니다.

System.nanoTime()

System.nanoTime()은 로컬 시스템에서 가장 정확한 현재 timestamp를 나노초 단위로 리턴합니다. (리눅스의 CLOCK_MONOTONIC과 같습니다) 정확한 현재 시간을 나타내는건 아니므로, 시간을 측정할때만 사용되어야 하며, 같은 프로세스, 같은 디바이스 간의 timestamp와 비교하여야 합니다. 현재 시간을 알고 싶으면 System.currentTimeMillis()을 사용해야 합니다.

Kotlin

코틀린에서는 시간 측정을 보다 간편하게 할 수 있도록 몇가지 함수를 제공합니다.

measureTimeMillis(block: () -> Unit): Long

위의 Java에서 설명한 System.currentTimeMillis() 사용하여 block 을 실행하는데 소요된 시간을 Long 형식으로 반환 합니다.

val elapsed: Long = measureTimeMillis {
    Thread.sleep(100)
}
println(elapsed)
measureNanoTime(block: () -> Unit): Long

위의 Java에서 설명한 System.nanoTime() 사용하여 block 을 실행하는데 소요된 시간을 Long 형식으로 반환 합니다.

val elapsed: Long = measureNanoTime {
    Thread.sleep(100)
}
println(elapsed)

위 두 함수를 이용하면 이전보다 더 편하게 시간을 측정 할 수 있지만, block 내에서 실행된 값을 얻어 오기 불편하다는 단점이 있습니다.

이땐 kotlin 1.3에서 experimental로 추가된 함수를 이용 할 수 있습니다.

measureTimedValue(block: () -> T): TimedValue
val timedValue: TimedValue<User> = measureTimedValue {
    service.getUser()
}
val duration: Duration = timedValue.duration
val user: User = timedValue.value

measureTimedValue은 블록에 소요된 시간만 Long으로 반환 하는 대신, TimedValue라는 클래스를 통해 block의 결과값과 시간을 함께 반환합니다.

measureTime(block: () -> Unit): Duration
val duration: Duration = measureTimedValue {
    Thread.sleep(100)
}
println(duration)

measureTime은 위에 설명한 measureTimeMillis와 같이 블록에 소요된 시간만 반환하지만, milliseoncd 단위가 아닌 Duration이라는 클래스로 반환합니다.

Duration

kotlin 1.3에서 experimental로 추가된 클래스입니다.

println("elapsed: ${duration.inSeconds}")
println("elapsed: ${duration.inMilliseconds}")
println("elapsed: $duration") // elapsed: 35.8us

위와 같이 seconds, milliseconds로(Double) 쉽게 변환 할 수 있고, toString()을 하게 되면 적당한 단위를 골라서 변환합니다.

val duration1 = 3600.toDuration(DurationUnit.SECONDS)
println(duration1) // => 60.0m

val duration2 = 0.5.toDuration(DurationUnit.HOURS)
println(duration1 + duration2) // => 90.0m

위와 같이 duration을 직접 만들 수 있으며, 합치거나 뺄 수 있습니다.

위의 모든 메소드에서 리턴값이 밀리초, 나노초 단위여도 그정도 수준의 정확도를 보장하는것은 아닙니다.

요약

  • 수행 시간 측정을 편하게 하려면, kotlin 1.3에 추가된 measureTimedValue을 이용하면 된다.

주의 사항

  • kotlin.system.measureTimeMillis은 1.3.50기준 JVM, Native에서만 동작. (JavaScript는 불가능)
  • kotlin.time.measureTimedValue은 experimental이므로 API가 변경 될 수 있음. (JavaScript도 사용 가능)

참고자료