@@ -19,9 +19,10 @@ abstract class CommonSuitExecutor(
19
19
benchmark.suite.setup(instance)
20
20
var exception: Throwable ? = null
21
21
val samples = try {
22
- val cycles = warmup(benchmark, configuration, instance)
22
+ val measurer = createIterationMeasurer(instance, benchmark, configuration)
23
+ val cycles = warmup(benchmark, configuration, measurer)
23
24
DoubleArray (configuration.iterations) { iteration ->
24
- val nanosecondsPerOperation = measure(instance, benchmark, cycles )
25
+ val nanosecondsPerOperation = measure(cycles, measurer )
25
26
val text = nanosecondsPerOperation.nanosToText(configuration.mode, configuration.outputTimeUnit)
26
27
reporter.output(executionName, id, " Iteration #$iteration : $text " )
27
28
nanosecondsPerOperation
@@ -74,86 +75,60 @@ abstract class CommonSuitExecutor(
74
75
complete()
75
76
}
76
77
77
- @Suppress(" REDUNDANT_ELSE_IN_WHEN" )
78
- private val BenchmarkTimeUnit .asDurationTimeUnit: DurationUnit get() = when (this ) {
79
- BenchmarkTimeUnit .NANOSECONDS -> DurationUnit .NANOSECONDS
80
- BenchmarkTimeUnit .MICROSECONDS -> DurationUnit .MICROSECONDS
81
- BenchmarkTimeUnit .MILLISECONDS -> DurationUnit .MILLISECONDS
82
- BenchmarkTimeUnit .SECONDS -> DurationUnit .SECONDS
83
- BenchmarkTimeUnit .MINUTES -> DurationUnit .MINUTES
84
- else -> TODO (" Implement ${this .name} " )
85
- }
78
+ private inline fun measure (cycles : Int , measurer : () -> Long ): Double {
79
+ var iterations = 0
80
+ var elapsedTime = 0L
81
+ do {
82
+ val subIterationDuration = measurer()
83
+ elapsedTime + = subIterationDuration
84
+ iterations++
85
+ } while (iterations < cycles)
86
86
87
- @OptIn(ExperimentalTime ::class )
88
- private inline fun measure (cycles : Int , payload : () -> Unit ): Double {
89
- var counter = cycles
90
- val time = TimeSource .Monotonic .measureTime {
91
- while (counter-- > 0 ) {
92
- payload()
93
- }
94
- }
95
- return time.inWholeNanoseconds.toDouble() / cycles
87
+ return elapsedTime.toDouble() / cycles
96
88
}
97
89
98
- @OptIn(ExperimentalTime ::class )
99
- private inline fun <T > measureWarmup (benchmark : BenchmarkDescriptor <T >, configuration : BenchmarkConfiguration , payload : () -> Unit ): Int {
90
+ private fun <T > warmup (benchmark : BenchmarkDescriptor <T >, configuration : BenchmarkConfiguration , measurer : () -> Long ): Int {
100
91
var iterations = 0
101
- val benchmarkIterationTimeAsDuration =
102
- configuration.iterationTime.toDuration(configuration.iterationTimeUnit.asDurationTimeUnit)
103
-
92
+ val benchmarkIterationTime = configuration.iterationTime * configuration.iterationTimeUnit.toMultiplier()
104
93
var currentIteration = 0
105
94
106
- val timeSource: TimeSource = TimeSource .Monotonic
107
95
while (currentIteration < configuration.warmups) {
108
96
iterations = 0
109
- var elapsedTime: Duration
110
- val startTime = timeSource.markNow()
111
- val maxTime = startTime + benchmarkIterationTimeAsDuration
97
+ var elapsedTime = 0L
112
98
do {
113
- payload ()
114
- elapsedTime = startTime.elapsedNow()
99
+ val subIterationDuration = measurer ()
100
+ elapsedTime + = subIterationDuration
115
101
iterations++
116
- } while (maxTime.hasNotPassedNow() )
102
+ } while (elapsedTime < benchmarkIterationTime )
117
103
118
- val metricInNanos = elapsedTime.inWholeNanoseconds. toDouble() / iterations
104
+ val metricInNanos = elapsedTime.toDouble() / iterations
119
105
val sample = metricInNanos.nanosToText(configuration.mode, configuration.outputTimeUnit)
120
106
reporter.output(executionName, benchmark.name, " Warm-up #$currentIteration : $sample " )
121
107
currentIteration++
122
108
}
123
109
return iterations
124
110
}
125
111
126
- private fun <T > warmup (benchmark : BenchmarkDescriptor <T >, configuration : BenchmarkConfiguration , instance : T ): Int = when (benchmark) {
127
- is BenchmarkDescriptorWithBlackholeParameter -> {
128
- val blackhole = benchmark.blackhole
129
- val delegate = benchmark.function
130
- measureWarmup(benchmark, configuration) {
131
- blackhole.consume(instance.delegate(blackhole))
132
- }
133
- }
134
- is BenchmarkDescriptorWithNoBlackholeParameter -> {
135
- val blackhole = benchmark.blackhole
136
- val delegate = benchmark.function
137
- measureWarmup(benchmark, configuration) {
138
- blackhole.consume(instance.delegate())
139
- }
140
- }
141
- else -> error(" Unexpected ${benchmark::class .simpleName} " )
142
- }
143
-
144
- private fun <T > measure (instance : T , benchmark : BenchmarkDescriptor <T >, cycles : Int ): Double = when (benchmark) {
112
+ @OptIn(ExperimentalTime ::class )
113
+ protected open fun <T > createIterationMeasurer (instance : T , benchmark : BenchmarkDescriptor <T >, configuration : BenchmarkConfiguration ): () -> Long = when (benchmark) {
145
114
is BenchmarkDescriptorWithBlackholeParameter -> {
146
- val blackhole = benchmark.blackhole
147
- val delegate = benchmark.function
148
- measure(cycles) {
149
- blackhole.consume(instance.delegate(blackhole))
115
+ {
116
+ val localBlackhole = benchmark.blackhole
117
+ val localDelegate = benchmark.function
118
+ val localInstance = instance
119
+ TimeSource .Monotonic .measureTime {
120
+ localBlackhole.consume(localInstance.localDelegate(localBlackhole))
121
+ }.inWholeNanoseconds
150
122
}
151
123
}
152
124
is BenchmarkDescriptorWithNoBlackholeParameter -> {
153
- val blackhole = benchmark.blackhole
154
- val delegate = benchmark.function
155
- measure(cycles) {
156
- blackhole.consume(instance.delegate())
125
+ {
126
+ val localBlackhole = benchmark.blackhole
127
+ val localDelegate = benchmark.function
128
+ val localInstance = instance
129
+ TimeSource .Monotonic .measureTime {
130
+ localBlackhole.consume(localInstance.localDelegate())
131
+ }.inWholeNanoseconds
157
132
}
158
133
}
159
134
else -> error(" Unexpected ${benchmark::class .simpleName} " )
0 commit comments