성능 측정
long startTime = getCurrentTime();
// do something
long endTime = getCurrentTime();
Log.d(DEBUG, "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.currentTimeMillis()
는 시스템의 시간을 가져오지만, 시스템의 시간은 언제든지 변경될수 있기 때문에 시간 측정에는 적합하지 않습니다. (ACTION_TIME_TICK
, ACTION_TIME_CHANGED
, ACTION_TIMEZONE_CHANGED
과 같은 브로드캐스트에 의해 시간이 변경되는걸 알 수 있습니다.)
System.nanoTime()
System.nanoTime()
은 로컬 시스템에서 가장 정확한 현재 timestamp를 나노초 단위로 리턴합니다. (리눅스의 CLOCK_MONOTONIC
과 같습니다) 정확한 현재 시간을 나타내는건 아니므로, 시간을 측정할때만 사용되어야 하며, 같은 프로세스, 같은 디바이스 간의 timestamp와 비교하여야 합니다. 현재 시간을 알고 싶으면 System.currentTimeMillis()
을 사용해야 합니다.
Android
안드로이드에서는 SystemClock.currentThreadTimeMillis()
, SystemClock.elapsedRealtime()
, SystemClock.elapsedRealtimeNanos()
와 Debug.threadCpuTimeNanos()
를 제공합니다.
SystemClock.currentThreadTimeMillis()
SystemClock.currentThreadTimeMillis()
는 현재 스레드의 시간을 밀리초 단위로 리턴합니다.
SystemClock.elapsedRealtime()
SystemClock.elapsedRealtime(), SystemClock.elapsedRealtimeNanos()
는 부팅 이후의 시간을 리턴합니다. 이때 sleep으로 소모된 시간이 포함됩니다.
SystemClock.uptimeMillis()
SystemClock.uptimeMillis()
는 부팅 이후 시간을 리턴합니다. 이때 deep sleep으로 소모된 시간은 포함하지 않습니다.
Debug.threadCpuTimeNanos()
Debug.threadCpuTimeNanos()
는 현재 스레드에서 소모된 시간만 측정합니다. 현재 스레드에서 코드를 실행하거나 특정 I/O를 기다린 시간을 나노초 단위로 리턴합니다. 지원하지 않는 시스템에선 -1을 리턴할 수 있습니다. 다른 스레드에서 소모된 시간을 포함하지 않기 때문에 다른 스레드를 고려하지 않고 시간 측정을 할때 가장 정확한 시간을 측정 할 수 있습니다.
성능측정
위의 6개의 메소드를 이용하여 시간을 측정해 보겠습니다.
long currentTimeMillisStart = System.currentTimeMillis();
long nanoTimeStart = System.nanoTime();
long currentThreadTimeMillisStart = SystemClock.currentThreadTimeMillis();
long elapsedRealtimeStart = SystemClock.elapsedRealtime();
long uptimeMillisStart = SystemClock.uptimeMillis();
long threadCpuTimeNanosStart = Debug.threadCpuTimeNanos();
// some code
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
long currentTimeMillisEnd = System.currentTimeMillis();
long nanoTimeEnd = System.nanoTime();
long currentThreadTimeMillisEnd = SystemClock.currentThreadTimeMillis();
long elapsedRealtimeEnd = SystemClock.elapsedRealtime();
long uptimeMillisEnd = SystemClock.uptimeMillis();
long threadCpuTimeNanosEnd = Debug.threadCpuTimeNanos();
결과값
09-22 15:05:21.306 System.currentTimeMillis(); -> 138ms
09-22 15:05:21.306 System.nanoTime(); -> 138.020823ms
09-22 15:05:21.306 SystemClock.currentThreadTimeMillis(); -> 30ms
09-22 15:05:21.306 SystemClock.elapsedRealtime(); -> 138ms
09-22 15:05:21.306 SystemClock.uptimeMillis(); -> 138ms
09-22 15:05:21.306 Debug.threadCpuTimeNanos(); -> 29.924149ms
결과값을 보게되면 30ms, 138ms 두가지 값이 측정 되었습니다.
약 30ms로 측정 된 SystemClock.currentThreadTimeMillis()
, Debug.threadCpuTimeNanos()
는 다른 스레드의 작업을 수행하는데 걸리는 시간을 제외한, 현재 스레드에 소요된 시간을 보여주는 것을 알 수 있습니다.
위의 모든 메소드에서 리턴값이 밀리초, 나노초 단위여도 그정도 수준의 정확도를 보장하는것은 아닙니다.
요약
System.currentTimeMillis()
는 시간 측정용이 아니므로 다른 메소드를 사용할것. SystemClock.currentThreadTimeMillis()
, Debug.threadCpuTimeNanos()
는 스레드가 동작하는 시간 만 포함이된다.