1 package leakcanary 2 3 import android.os.SystemClock 4 import leakcanary.Profiler.runWithMethodTracing 5 import shark.SharkLog 6 7 /** 8 * Set of tools for benchmarking and tracing blocks of code 9 */ 10 object Benchmark { 11 12 /** 13 * Executes the given function [block] twice (without and with method tracing to SD card) and 14 * returns the result of the function execution. 15 * First execution of [block] is done to warm up code and load any necessary libs. Second 16 * execution is measured with [runWithMethodTracing] 17 */ benchmarkWithMethodTracingnull18 fun <T> benchmarkWithMethodTracing(block: () -> T): T { 19 SharkLog.d { "Dry run to warm up the code." } 20 block() 21 SharkLog.d { "Run with sampling" } 22 return runWithMethodTracing(block) 23 } 24 25 /** 26 * Executes the given function [block] multiple times measuring the average execution time and 27 * returns the result of the function execution. 28 * Number of executions is [times] + 1, where 1 execution is done for code warm up and other 29 * [times] executions are measured. Results of measurement will be outputted to LogCat at each 30 * iteration and in the end of measurement. 31 */ benchmarkCodenull32 fun <T> benchmarkCode( 33 times: Int = 10, 34 block: () -> T 35 ): T { 36 // Warm-up run, no benchmarking 37 val result = block() 38 val measurements = mutableListOf<Long>() 39 repeat(times) { 40 val start = SystemClock.uptimeMillis() 41 block() 42 val end = SystemClock.uptimeMillis() 43 SharkLog.d { "BenchmarkCode, iteration ${it + 1}/$times, duration ${end - start}" } 44 measurements.add(end - start) 45 } 46 measurements.sort() 47 val median: Double = if (times % 2 == 0) { 48 (measurements[times / 2] + measurements[times / 2 - 1]).toDouble() / 2 49 } else { 50 measurements[times / 2].toDouble() 51 } 52 SharkLog.d { 53 "BenchmarkCode complete, $times iterations. Durations (ms): median $median, " + 54 "min ${measurements.first()}, max ${measurements.last()}" 55 } 56 return result 57 } 58 }