Perf: implemented many attempts computation

Mean and standard deviation are computed as result
This commit is contained in:
Igor Chevdar
2018-05-15 18:53:14 +03:00
parent 876de88df2
commit 54fa746813
2 changed files with 49 additions and 25 deletions
+23 -9
View File
@@ -96,33 +96,47 @@ task bench(type:DefaultTask) {
def average = "none" def average = "none"
def absoluteAverage = "none" def absoluteAverage = "none"
jvmReport.report jvmReport.report
.sort { konanReport.report[it.key] / it.value } .sort { konanReport.report[it.key].mean / it.value.mean }
.each { k, v -> .each { k, v ->
def konanValue = konanReport.report[k] def konanValue = konanReport.report[k]
def ratio = String.format('%.2f', konanValue / v) def ratio = konanValue.mean / v.mean
def formattedKonanValue = String.format('%.2f', konanValue / 1000) def minRatio = (konanValue.mean - konanValue.stdDev) / (v.mean + v.stdDev)
def maxRatio = (konanValue.mean + konanValue.stdDev) / (v.mean - v.stdDev)
def ratioStdDev = Math.min(Math.abs(minRatio - ratio), Math.abs(maxRatio - ratio))
def formattedKonanValue = String.format('%.4f us +- %.4f us', konanValue.mean / 1000, konanValue.stdDev / 1000)
def formattedRatio = String.format('%.2f +- %.2f', ratio, ratioStdDev)
if (k == 'RingAverage') { if (k == 'RingAverage') {
average = ratio average = formattedRatio
absoluteAverage = formattedKonanValue absoluteAverage = formattedKonanValue
} else {
println("$k : absolute = $formattedKonanValue, ratio = $formattedRatio")
} }
println("$k : absolute = $formattedKonanValue us, ratio = $ratio")
if (System.getenv("TEAMCITY_BUILD_PROPERTIES_FILE") != null) if (System.getenv("TEAMCITY_BUILD_PROPERTIES_FILE") != null)
println("##teamcity[buildStatisticValue key='$k' value='$ratio']") println("##teamcity[buildStatisticValue key='$k' value='$ratio']")
} }
println() println()
println("Average Ring score: absolute = $absoluteAverage us, ratio = $average") println("Average Ring score: absolute = $absoluteAverage, ratio = $average")
} }
} }
class Results {
def Double mean
def Double stdDev
Results(Double mean, Double stdDev) {
this.mean = mean
this.stdDev = stdDev
}
}
class Report { class Report {
def Map<String, Double> report = new TreeMap() def Map<String, Results> report = new TreeMap()
Report(File path) { Report(File path) {
path.readLines().drop(3).findAll { it.split(':').length == 2 }.each { path.readLines().drop(3).findAll { it.split(':').length == 3 }.each {
def p = it.split(':') def p = it.split(':')
report.put(p[0].trim(), Double.parseDouble(p[1].trim())) report.put(p[0].trim(), new Results(Double.parseDouble(p[1].trim()), Double.parseDouble(p[2].trim())))
} }
} }
} }
@@ -24,9 +24,11 @@ val BENCHMARK_SIZE = 100
//-----------------------------------------------------------------------------// //-----------------------------------------------------------------------------//
class Launcher(val numWarmIterations: Int) { class Launcher(val numWarmIterations: Int) {
val results = mutableMapOf<String, Long>() class Results(val mean: Double, val variance: Double)
fun launch(benchmark: () -> Any?): Long { // If benchmark runs too long - use coeff to speed it up. val results = mutableMapOf<String, Results>()
fun launch(benchmark: () -> Any?): Results { // If benchmark runs too long - use coeff to speed it up.
var i = numWarmIterations var i = numWarmIterations
while (i-- > 0) benchmark() while (i-- > 0) benchmark()
@@ -41,20 +43,27 @@ class Launcher(val numWarmIterations: Int) {
} }
cleanup() cleanup()
} }
if (time >= 200L * 1_000_000) // 200ms if (time >= 100L * 1_000_000) // 100ms
break break
autoEvaluatedNumberOfMeasureIteration *= 2 autoEvaluatedNumberOfMeasureIteration *= 2
} }
i = autoEvaluatedNumberOfMeasureIteration val attempts = 10
val time = measureNanoTime { val samples = DoubleArray(attempts)
while (i-- > 0) { for (k in samples.indices) {
benchmark() i = autoEvaluatedNumberOfMeasureIteration
val time = measureNanoTime {
while (i-- > 0) {
benchmark()
}
cleanup()
} }
cleanup() samples[k] = time * 1.0 / autoEvaluatedNumberOfMeasureIteration
} }
val mean = samples.sum() / attempts
val variance = samples.indices.sumByDouble { (samples[it] - mean) * (samples[it] - mean) } / attempts
return time / autoEvaluatedNumberOfMeasureIteration return Results(mean, variance)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -101,17 +110,18 @@ class Launcher(val numWarmIterations: Int) {
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun printResultsNormalized() { fun printResultsNormalized() {
var total = 0.0 var totalMean = 0.0
var totalVariance = 0.0
results.asSequence().sortedBy { it.key }.forEach { results.asSequence().sortedBy { it.key }.forEach {
val norma = it.value.toDouble()
val niceName = it.key.padEnd(50, ' ') val niceName = it.key.padEnd(50, ' ')
val niceNorma = norma.toString(9) println("$niceName : ${it.value.mean.toString(9)} : ${kotlin.math.sqrt(it.value.variance).toString(9)}")
println("$niceName : $niceNorma")
total += norma totalMean += it.value.mean
totalVariance += it.value.variance
} }
val average = total / results.size val averageMean = totalMean / results.size
println("\nRingAverage: ${average.toString(9)}") val averageStdDev = kotlin.math.sqrt(totalVariance) / results.size
println("\nRingAverage: ${averageMean.toString(9)} : ${averageStdDev.toString(9)}")
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//