From 940718098dd588860e33aefde1d027a80dfdf61b Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Wed, 10 Mar 2021 21:35:28 +0700 Subject: [PATCH] Revise benchmarks code Revise benchmarks code by using kotlinx.benchmark type aliases (it will simplify creating multiplatform benchmarks), using Blackhole class to consume results, moving all the constant state to private companion objects --- .../kmath/benchmarks/ArrayBenchmark.kt | 32 +++++++------ .../kmath/benchmarks/BufferBenchmark.kt | 10 ++--- .../kscience/kmath/benchmarks/DotBenchmark.kt | 27 +++++------ .../ExpressionsInterpretersBenchmark.kt | 37 ++++++++------- .../benchmarks/LinearAlgebraBenchmark.kt | 19 ++++---- .../kmath/benchmarks/NDFieldBenchmark.kt | 28 +++++++----- .../kmath/benchmarks/ViktorBenchmark.kt | 42 ++++++++++------- .../kmath/benchmarks/ViktorLogBenchmark.kt | 45 ++++++++++--------- 8 files changed, 134 insertions(+), 106 deletions(-) diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt index 535778844..43b698c03 100644 --- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt @@ -1,34 +1,38 @@ package space.kscience.kmath.benchmarks -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State import java.nio.IntBuffer @State(Scope.Benchmark) internal class ArrayBenchmark { @Benchmark - fun benchmarkArrayRead() { + fun benchmarkArrayRead(blackhole: Blackhole) { var res = 0 - for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.array[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i] + for (i in 1..size) res += array[size - i] + blackhole.consume(res) } @Benchmark - fun benchmarkBufferRead() { + fun benchmarkBufferRead(blackhole: Blackhole) { var res = 0 - for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.arrayBuffer[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i] + for (i in 1..size) res += arrayBuffer[size - i] + blackhole.consume(res) } @Benchmark - fun nativeBufferRead() { + fun nativeBufferRead(blackhole: Blackhole) { var res = 0 - for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.nativeBuffer[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i] + for (i in 1..size) res += nativeBuffer[size - i] + blackhole.consume(res) } - companion object { - const val size: Int = 1000 - val array: IntArray = IntArray(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) { it } - val arrayBuffer: IntBuffer = IntBuffer.wrap(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.array) - val nativeBuffer: IntBuffer = IntBuffer.allocate(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size).also { for (i in 0 until space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) it.put(i, i) } + private companion object { + private const val size = 1000 + private val array = IntArray(size) { it } + private val arrayBuffer = IntBuffer.wrap(array) + private val nativeBuffer = IntBuffer.allocate(size).also { for (i in 0 until size) it.put(i, i) } } } diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt index 1afb4e52c..1c3bbab75 100644 --- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt @@ -1,8 +1,8 @@ package space.kscience.kmath.benchmarks -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.complex import space.kscience.kmath.structures.MutableBuffer @@ -28,7 +28,7 @@ internal class BufferBenchmark { } } - companion object { - const val size: Int = 100 + private companion object { + private const val size = 100 } } diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 39eeb24d3..93b5c5549 100644 --- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -1,8 +1,9 @@ package space.kscience.kmath.benchmarks import kotlinx.benchmark.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State import space.kscience.kmath.commons.linear.CMMatrixContext import space.kscience.kmath.ejml.EjmlMatrixContext import space.kscience.kmath.linear.BufferMatrixContext @@ -17,7 +18,7 @@ import kotlin.random.Random internal class DotBenchmark { companion object { val random = Random(12224) - val dim = 1000 + const val dim = 1000 //creating invertible matrix val matrix1 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } @@ -31,37 +32,37 @@ internal class DotBenchmark { } @Benchmark - fun cmDot() { + fun cmDot(blackhole: Blackhole) { CMMatrixContext { - cmMatrix1 dot cmMatrix2 + blackhole.consume(cmMatrix1 dot cmMatrix2) } } @Benchmark - fun ejmlDot() { + fun ejmlDot(blackhole: Blackhole) { EjmlMatrixContext { - ejmlMatrix1 dot ejmlMatrix2 + blackhole.consume(ejmlMatrix1 dot ejmlMatrix2) } } @Benchmark - fun ejmlDotWithConversion() { + fun ejmlDotWithConversion(blackhole: Blackhole) { EjmlMatrixContext { - matrix1 dot matrix2 + blackhole.consume(matrix1 dot matrix2) } } @Benchmark - fun bufferedDot() { + fun bufferedDot(blackhole: Blackhole) { BufferMatrixContext(RealField, Buffer.Companion::real).invoke { - matrix1 dot matrix2 + blackhole.consume(matrix1 dot matrix2) } } @Benchmark - fun realDot() { + fun realDot(blackhole: Blackhole) { RealMatrixContext { - matrix1 dot matrix2 + blackhole.consume(matrix1 dot matrix2) } } } diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index a9c0fe703..9c150f074 100644 --- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -1,64 +1,62 @@ package space.kscience.kmath.benchmarks -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State import space.kscience.kmath.asm.compile import space.kscience.kmath.ast.mstInField import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.expressionInField import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.bindSymbol import kotlin.random.Random @State(Scope.Benchmark) internal class ExpressionsInterpretersBenchmark { - private val algebra: Field = RealField - val x by symbol - @Benchmark - fun functionalExpression() { + fun functionalExpression(blackhole: Blackhole) { val expr = algebra.expressionInField { val x = bindSymbol(x) x * const(2.0) + const(2.0) / x - const(16.0) } - invokeAndSum(expr) + invokeAndSum(expr, blackhole) } @Benchmark - fun mstExpression() { + fun mstExpression(blackhole: Blackhole) { val expr = algebra.mstInField { val x = bindSymbol(x) x * 2.0 + 2.0 / x - 16.0 } - invokeAndSum(expr) + invokeAndSum(expr, blackhole) } @Benchmark - fun asmExpression() { + fun asmExpression(blackhole: Blackhole) { val expr = algebra.mstInField { val x = bindSymbol(x) x * 2.0 + 2.0 / x - 16.0 }.compile() - invokeAndSum(expr) + invokeAndSum(expr, blackhole) } @Benchmark - fun rawExpression() { + fun rawExpression(blackhole: Blackhole) { val expr = Expression { args -> val x = args.getValue(x) x * 2.0 + 2.0 / x - 16.0 } - invokeAndSum(expr) + + invokeAndSum(expr, blackhole) } - private fun invokeAndSum(expr: Expression) { + private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { val random = Random(0) var sum = 0.0 @@ -66,6 +64,11 @@ internal class ExpressionsInterpretersBenchmark { sum += expr(x to random.nextDouble()) } - println(sum) + blackhole.consume(sum) + } + + private companion object { + private val algebra = RealField + private val x by symbol } } diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt index 22e735e12..30cb6c0b9 100644 --- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt @@ -1,8 +1,9 @@ package space.kscience.kmath.benchmarks import kotlinx.benchmark.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State import space.kscience.kmath.commons.linear.CMMatrixContext import space.kscience.kmath.commons.linear.CMMatrixContext.dot import space.kscience.kmath.commons.linear.inverse @@ -18,7 +19,7 @@ import kotlin.random.Random internal class LinearAlgebraBenchmark { companion object { val random = Random(1224) - val dim = 100 + const val dim = 100 //creating invertible matrix val u = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } @@ -27,21 +28,21 @@ internal class LinearAlgebraBenchmark { } @Benchmark - fun kmathLupInversion() { - MatrixContext.real.inverseWithLup(matrix) + fun kmathLupInversion(blackhole: Blackhole) { + blackhole.consume(MatrixContext.real.inverseWithLup(matrix)) } @Benchmark - fun cmLUPInversion() { + fun cmLUPInversion(blackhole: Blackhole) { with(CMMatrixContext) { - inverse(matrix) + blackhole.consume(inverse(matrix)) } } @Benchmark - fun ejmlInverse() { + fun ejmlInverse(blackhole: Blackhole) { with(EjmlMatrixContext) { - inverse(matrix) + blackhole.consume(inverse(matrix)) } } } diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt index 5bcc09cdb..aeee0dafe 100644 --- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -1,8 +1,9 @@ package space.kscience.kmath.benchmarks -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State import space.kscience.kmath.nd.* import space.kscience.kmath.operations.RealField import space.kscience.kmath.structures.Buffer @@ -10,35 +11,38 @@ import space.kscience.kmath.structures.Buffer @State(Scope.Benchmark) internal class NDFieldBenchmark { @Benchmark - fun autoFieldAdd() { + fun autoFieldAdd(blackhole: Blackhole) { with(autoField) { var res: NDStructure = one repeat(n) { res += one } + blackhole.consume(res) } } @Benchmark - fun specializedFieldAdd() { + fun specializedFieldAdd(blackhole: Blackhole) { with(specializedField) { var res: NDStructure = one repeat(n) { res += 1.0 } + blackhole.consume(res) } } @Benchmark - fun boxingFieldAdd() { + fun boxingFieldAdd(blackhole: Blackhole) { with(genericField) { var res: NDStructure = one repeat(n) { res += 1.0 } + blackhole.consume(res) } } - companion object { - const val dim: Int = 1000 - const val n: Int = 100 - val autoField = NDAlgebra.auto(RealField, dim, dim) - val specializedField: RealNDField = NDAlgebra.real(dim, dim) - val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim) + private companion object { + private const val dim = 1000 + private const val n = 100 + private val autoField = NDAlgebra.auto(RealField, dim, dim) + private val specializedField = NDAlgebra.real(dim, dim) + private val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim) } } diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index 370258bc6..c511173a9 100644 --- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -1,51 +1,61 @@ package space.kscience.kmath.benchmarks +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.NDAlgebra +import space.kscience.kmath.nd.NDStructure +import space.kscience.kmath.nd.auto +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.RealField import space.kscience.kmath.viktor.ViktorNDField @State(Scope.Benchmark) internal class ViktorBenchmark { - final val dim: Int = 1000 - final val n: Int = 100 - - // automatically build context most suited for given type. - final val autoField: NDField = NDAlgebra.auto(RealField, dim, dim) - final val realField: RealNDField = NDAlgebra.real(dim, dim) - final val viktorField: ViktorNDField = ViktorNDField(dim, dim) - @Benchmark - fun automaticFieldAddition() { + fun automaticFieldAddition(blackhole: Blackhole) { with(autoField) { var res: NDStructure = one repeat(n) { res += 1.0 } + blackhole.consume(res) } } @Benchmark - fun realFieldAddition() { + fun realFieldAddition(blackhole: Blackhole) { with(realField) { var res: NDStructure = one repeat(n) { res += 1.0 } + blackhole.consume(res) } } @Benchmark - fun viktorFieldAddition() { + fun viktorFieldAddition(blackhole: Blackhole) { with(viktorField) { var res = one repeat(n) { res += 1.0 } + blackhole.consume(res) } } @Benchmark - fun rawViktor() { + fun rawViktor(blackhole: Blackhole) { val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim)) var res = one repeat(n) { res = res + one } + blackhole.consume(res) + } + + private companion object { + private const val dim = 1000 + private const val n = 100 + + // automatically build context most suited for given type. + private val autoField = NDAlgebra.auto(RealField, dim, dim) + private val realField = NDAlgebra.real(dim, dim) + private val viktorField = ViktorNDField(dim, dim) } } diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index 9f99b002a..c48c86af9 100644 --- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -1,48 +1,53 @@ package space.kscience.kmath.benchmarks +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.NDAlgebra +import space.kscience.kmath.nd.auto +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.RealField import space.kscience.kmath.viktor.ViktorNDField @State(Scope.Benchmark) internal class ViktorLogBenchmark { - final val dim: Int = 1000 - final val n: Int = 100 - - // automatically build context most suited for given type. - final val autoField: NDField = NDAlgebra.auto(RealField, dim, dim) - final val realField: RealNDField = NDAlgebra.real(dim, dim) - final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim)) - - @Benchmark - fun realFieldLog() { + fun realFieldLog(blackhole: Blackhole) { with(realField) { val fortyTwo = produce { 42.0 } var res = one repeat(n) { res = ln(fortyTwo) } + blackhole.consume(res) } } @Benchmark - fun viktorFieldLog() { + fun viktorFieldLog(blackhole: Blackhole) { with(viktorField) { val fortyTwo = produce { 42.0 } var res = one repeat(n) { res = ln(fortyTwo) } + blackhole.consume(res) } } @Benchmark - fun rawViktorLog() { + fun rawViktorLog(blackhole: Blackhole) { val fortyTwo = F64Array.full(dim, dim, init = 42.0) - var res: F64Array - repeat(n) { - res = fortyTwo.log() - } + lateinit var res: F64Array + repeat(n) { res = fortyTwo.log() } + blackhole.consume(res) + } + + private companion object { + private const val dim = 1000 + private const val n = 100 + + // automatically build context most suited for given type. + private val autoField = NDAlgebra.auto(RealField, dim, dim) + private val realField = NDAlgebra.real(dim, dim) + private val viktorField = ViktorNDField(intArrayOf(dim, dim)) } }