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 }