Some fixes for <perf>

- Extracted number of attempts to a parameter
- Show 95% confidence intervals instead of standard deviation
This commit is contained in:
Igor Chevdar
2018-11-21 14:08:07 +03:00
parent 99d4d93488
commit 1c62b882bd
3 changed files with 36 additions and 18 deletions
+6 -4
View File
@@ -26,6 +26,7 @@ repositories {
//TODO: property //TODO: property
def jvmWarmup = 10000 def jvmWarmup = 10000
def nativeWarmup = 10 def nativeWarmup = 10
def attempts = 10
ext."konan.home" = distDir ext."konan.home" = distDir
@@ -64,7 +65,7 @@ task jvmRun(type: JavaExec) {
def output = new ByteArrayOutputStream() def output = new ByteArrayOutputStream()
classpath sourceSets.main.runtimeClasspath classpath sourceSets.main.runtimeClasspath
main = "MainKt" main = "MainKt"
args "$jvmWarmup" args "$jvmWarmup", "$attempts"
standardOutput = output standardOutput = output
doLast { doLast {
dumpReport('jvmReport', output) dumpReport('jvmReport', output)
@@ -80,7 +81,7 @@ private void dumpReport(String name, ByteArrayOutputStream output) {
task konanRun(type: Exec) { task konanRun(type: Exec) {
dependsOn 'build' dependsOn 'build'
def output = new ByteArrayOutputStream() def output = new ByteArrayOutputStream()
commandLine konanArtifacts.Ring.getByTarget('host').artifact.absolutePath, "$nativeWarmup" commandLine konanArtifacts.Ring.getByTarget('host').artifact.absolutePath, "$nativeWarmup", "$attempts"
standardOutput = output standardOutput = output
doLast { doLast {
dumpReport('konanReport', output) dumpReport('konanReport', output)
@@ -105,11 +106,12 @@ task bench(type:DefaultTask) {
.each { k, v -> .each { k, v ->
def konanValue = konanReport.report[k] def konanValue = konanReport.report[k]
def ratio = konanValue.mean / v.mean def ratio = konanValue.mean / v.mean
// This is a hack since neither mean nor variance of ratio of two distributions is known.
def minRatio = (konanValue.mean - konanValue.stdDev) / (v.mean + v.stdDev) def minRatio = (konanValue.mean - konanValue.stdDev) / (v.mean + v.stdDev)
def maxRatio = (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 ratioConfInt = 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 formattedKonanValue = String.format('%.4f us +- %.4f us', konanValue.mean / 1000, konanValue.stdDev / 1000)
def formattedRatio = String.format('%.2f +- %.2f', ratio, ratioStdDev) def formattedRatio = String.format('%.2f +- %.2f', ratio, ratioConfInt)
if (k == 'RingAverage') { if (k == 'RingAverage') {
average = formattedRatio average = formattedRatio
absoluteAverage = formattedKonanValue absoluteAverage = formattedKonanValue
+15 -4
View File
@@ -17,12 +17,23 @@
import org.jetbrains.ring.Launcher import org.jetbrains.ring.Launcher
fun main(args: Array<String>) { fun main(args: Array<String>) {
var numWarmIterations = 0 // Should be 100000 for jdk based run var numWarmIterations = 0 // Should be 100000 for jdk based run
var numberOfAttempts = 10
if (args.size == 1) when (args.size) {
numWarmIterations = args[0].toInt() 0 -> { }
1 -> numWarmIterations = args[0].toInt()
2 -> {
numWarmIterations = args[0].toInt()
numberOfAttempts = args[1].toInt()
}
else -> {
println("Usage: perf [# warmup iterations] [# attempts]")
return
}
}
println("Ring starting") println("Ring starting")
println(" warmup iterations count: $numWarmIterations") println(" warmup iterations count: $numWarmIterations")
Launcher(numWarmIterations).runBenchmarks() Launcher(numWarmIterations, numberOfAttempts).runBenchmarks()
} }
@@ -17,13 +17,14 @@
package org.jetbrains.ring package org.jetbrains.ring
import octoTest import octoTest
import kotlin.math.sqrt
import kotlin.system.measureNanoTime import kotlin.system.measureNanoTime
val BENCHMARK_SIZE = 100 val BENCHMARK_SIZE = 100
//-----------------------------------------------------------------------------// //-----------------------------------------------------------------------------//
class Launcher(val numWarmIterations: Int) { class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
class Results(val mean: Double, val variance: Double) class Results(val mean: Double, val variance: Double)
val results = mutableMapOf<String, Results>() val results = mutableMapOf<String, Results>()
@@ -48,8 +49,7 @@ class Launcher(val numWarmIterations: Int) {
autoEvaluatedNumberOfMeasureIteration *= 2 autoEvaluatedNumberOfMeasureIteration *= 2
} }
val attempts = 10 val samples = DoubleArray(numberOfAttempts)
val samples = DoubleArray(attempts)
for (k in samples.indices) { for (k in samples.indices) {
i = autoEvaluatedNumberOfMeasureIteration i = autoEvaluatedNumberOfMeasureIteration
val time = measureNanoTime { val time = measureNanoTime {
@@ -60,8 +60,8 @@ class Launcher(val numWarmIterations: Int) {
} }
samples[k] = time * 1.0 / autoEvaluatedNumberOfMeasureIteration samples[k] = time * 1.0 / autoEvaluatedNumberOfMeasureIteration
} }
val mean = samples.sum() / attempts val mean = samples.sum() / numberOfAttempts
val variance = samples.indices.sumByDouble { (samples[it] - mean) * (samples[it] - mean) } / attempts val variance = samples.indices.sumByDouble { (samples[it] - mean) * (samples[it] - mean) } / numberOfAttempts
return Results(mean, variance) return Results(mean, variance)
} }
@@ -110,19 +110,24 @@ class Launcher(val numWarmIterations: Int) {
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private val zStar = 1.96 // For 95% confidence interval.
fun printResultsNormalized() { fun printResultsNormalized() {
var totalMean = 0.0 var totalMean = 0.0
var totalVariance = 0.0 var totalVariance = 0.0
results.asSequence().sortedBy { it.key }.forEach { results.asSequence().sortedBy { it.key }.forEach {
val niceName = it.key.padEnd(50, ' ') val niceName = it.key.padEnd(50, ' ')
println("$niceName : ${it.value.mean.toString(9)} : ${kotlin.math.sqrt(it.value.variance).toString(9)}") val mean = it.value.mean
val variance = it.value.variance
val confidenceInterval = sqrt(variance / numberOfAttempts) * zStar
println("$niceName : ${mean.toString(9)} : ${confidenceInterval.toString(9)}")
totalMean += it.value.mean totalMean += mean
totalVariance += it.value.variance totalVariance += variance
} }
val averageMean = totalMean / results.size val averageMean = totalMean / results.size
val averageStdDev = kotlin.math.sqrt(totalVariance) / results.size val averageConfidenceInterval = sqrt(totalVariance / numberOfAttempts) * zStar / results.size
println("\nRingAverage: ${averageMean.toString(9)} : ${averageStdDev.toString(9)}") println("\nRingAverage: ${averageMean.toString(9)} : ${averageConfidenceInterval.toString(9)}")
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//