@@ -17,14 +17,10 @@ abstract class CommonSuiteExecutor(
17
17
benchmark.suite.setup(instance)
18
18
var exception: Throwable ? = null
19
19
val samples = try {
20
- val measurer = createIterationMeasurer(instance, benchmark, configuration)
21
- val cycles = warmup(benchmark, configuration, measurer)
22
- DoubleArray (configuration.iterations) { iteration ->
23
- val nanosecondsPerOperation = measure(cycles, measurer)
24
- val text = nanosecondsPerOperation.nanosToText(configuration.mode, configuration.outputTimeUnit)
25
- reporter.output(executionName, id, " Iteration #$iteration : $text " )
26
- nanosecondsPerOperation
27
- }
20
+ val cycles = estimateCycles(instance, benchmark, configuration)
21
+ val measurer = createIterationMeasurer(instance, benchmark, configuration, cycles)
22
+ warmup(id, configuration, cycles, measurer)
23
+ measure(id, configuration, cycles, measurer)
28
24
} catch (e: Throwable ) {
29
25
exception = e
30
26
doubleArrayOf()
@@ -73,47 +69,63 @@ abstract class CommonSuiteExecutor(
73
69
complete()
74
70
}
75
71
76
- private inline fun measure (cycles : Int , measurer : () -> Long ): Double {
77
- var iterations = 0
78
- var elapsedTime = 0L
79
- do {
80
- val subIterationDuration = measurer()
81
- elapsedTime + = subIterationDuration
82
- iterations++
83
- } while (iterations < cycles)
84
-
85
- return elapsedTime.toDouble() / cycles
86
- }
87
-
88
- private fun <T > warmup (benchmark : BenchmarkDescriptor <T >, configuration : BenchmarkConfiguration , measurer : () -> Long ): Int {
89
- var iterations = 0
90
- val benchmarkIterationTime = configuration.iterationTime * configuration.iterationTimeUnit.toMultiplier()
91
- var currentIteration = 0
92
-
93
- while (currentIteration < configuration.warmups) {
94
- iterations = 0
72
+ private fun <T > estimateCycles (
73
+ instance : T ,
74
+ benchmark : BenchmarkDescriptor <T >,
75
+ configuration : BenchmarkConfiguration
76
+ ): Int {
77
+ val estimator = wrapBenchmarkFunction(instance, benchmark) { body ->
78
+ var iterations = 0
95
79
var elapsedTime = 0L
80
+ val benchmarkIterationTime = configuration.iterationTime * configuration.iterationTimeUnit.toMultiplier()
96
81
do {
97
- val subIterationDuration = measurer( )
82
+ val subIterationDuration = measureTime(body )
98
83
elapsedTime + = subIterationDuration
99
84
iterations++
100
85
} while (elapsedTime < benchmarkIterationTime)
86
+ iterations
87
+ }
88
+ return estimator()
89
+ }
101
90
102
- val metricInNanos = elapsedTime.toDouble() / iterations
91
+ private fun warmup (
92
+ id : String ,
93
+ configuration : BenchmarkConfiguration ,
94
+ cycles : Int ,
95
+ measurer : () -> Long
96
+ ) {
97
+ var currentIteration = 0
98
+ while (currentIteration < configuration.warmups) {
99
+ val elapsedTime = measurer()
100
+ val metricInNanos = elapsedTime.toDouble() / cycles
103
101
val sample = metricInNanos.nanosToText(configuration.mode, configuration.outputTimeUnit)
104
- reporter.output(executionName, benchmark.name , " Warm-up #$currentIteration : $sample " )
102
+ reporter.output(executionName, id , " Warm-up #$currentIteration : $sample " )
105
103
currentIteration++
106
104
}
107
- return iterations
108
105
}
109
106
110
- protected open fun <T > createIterationMeasurer (instance : T , benchmark : BenchmarkDescriptor <T >, configuration : BenchmarkConfiguration ): () -> Long = when (benchmark) {
107
+ private fun measure (
108
+ id : String ,
109
+ configuration : BenchmarkConfiguration ,
110
+ cycles : Int ,
111
+ measurer : () -> Long
112
+ ) : DoubleArray = DoubleArray (configuration.iterations) { iteration ->
113
+ val nanosecondsPerOperation = measurer().toDouble() / cycles
114
+ val text = nanosecondsPerOperation.nanosToText(configuration.mode, configuration.outputTimeUnit)
115
+ reporter.output(executionName, id, " Iteration #$iteration : $text " )
116
+ nanosecondsPerOperation
117
+ }
118
+
119
+ private inline fun <T , R > wrapBenchmarkFunction (
120
+ instance : T ,
121
+ benchmark : BenchmarkDescriptor <T >,
122
+ crossinline wrapper : (() -> Unit ) -> R ): () -> R = when (benchmark) {
111
123
is BenchmarkDescriptorWithBlackholeParameter -> {
112
124
{
113
125
val localBlackhole = benchmark.blackhole
114
126
val localDelegate = benchmark.function
115
127
val localInstance = instance
116
- measureTime {
128
+ wrapper {
117
129
localBlackhole.consume(localInstance.localDelegate(localBlackhole))
118
130
}
119
131
}
@@ -123,12 +135,26 @@ abstract class CommonSuiteExecutor(
123
135
val localBlackhole = benchmark.blackhole
124
136
val localDelegate = benchmark.function
125
137
val localInstance = instance
126
- measureTime {
138
+ wrapper {
127
139
localBlackhole.consume(localInstance.localDelegate())
128
140
}
129
141
}
130
142
}
131
143
else -> error(" Unexpected ${benchmark::class .simpleName} " )
132
144
}
145
+
146
+ protected open fun <T > createIterationMeasurer (
147
+ instance : T ,
148
+ benchmark : BenchmarkDescriptor <T >,
149
+ configuration : BenchmarkConfiguration ,
150
+ cycles : Int
151
+ ): () -> Long = wrapBenchmarkFunction(instance, benchmark) { payload ->
152
+ var cycle = cycles
153
+ measureTime {
154
+ while (cycle-- > 0 ) {
155
+ payload()
156
+ }
157
+ }
158
+ }
133
159
}
134
160
0 commit comments