diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 2fab47ac0..5c2da2bd4 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -24,6 +24,7 @@ sourceSets { } dependencies { + implementation(project(":kmath-ast")) implementation(project(":kmath-core")) implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) diff --git a/examples/src/main/kotlin/scientifik/kmath/ast/NaiveAstAndFEBenchmark.kt b/examples/src/main/kotlin/scientifik/kmath/ast/NaiveAstAndFEBenchmark.kt new file mode 100644 index 000000000..16d7d03f1 --- /dev/null +++ b/examples/src/main/kotlin/scientifik/kmath/ast/NaiveAstAndFEBenchmark.kt @@ -0,0 +1,55 @@ +package scientifik.kmath.ast + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking +import scientifik.kmath.asm.compile +import scientifik.kmath.expressions.expressionInField +import scientifik.kmath.expressions.invoke +import scientifik.kmath.operations.RealField +import java.time.Duration +import java.time.Instant +import kotlin.random.Random + +fun main() = runBlocking(Dispatchers.Default) { + val mstJob = async { runMst() } + val asmJob = async { runAsm() } + val feJob = async { runFE() } + println("ASM: ${asmJob.await()}") + println("FE: ${feJob.await()}") + println("MST: ${mstJob.await()}") +} + +fun runFE(): Any { + val startTime = Instant.now()!! + val rand = Random(System.currentTimeMillis()) + var sum = 0.0 + + val expr = + RealField.expressionInField { ((variable("x") * number(2.0) - 234) + 24.toByte()) * variable("x") * variable("x") } + + repeat(10_000_000) { sum += expr("x" to rand.nextDouble()) } + println("asm-fe = $sum") + return Duration.between(startTime, Instant.now()) +} + +fun runAsm(): Any { + val startTime = Instant.now()!! + val rand = Random(System.currentTimeMillis()) + var sum = 0.0 + val expr = RealField.mstInField { ((symbol("x") * number(2.0) - 234) + 24.0) * symbol("x") * symbol("x") }.compile() + repeat(10_000_000) { sum += expr("x" to rand.nextDouble()) } + println("asm-sum = $sum") + return Duration.between(startTime, Instant.now()) +} + +fun runMst(): Any { + val startTime = Instant.now()!! + val rand = Random(System.currentTimeMillis()) + var sum = 0.0 + val expr = RealField.mstInField { ((symbol("x") * number(2.0) - 234) + 24.0) * symbol("x") * symbol("x") } + repeat(10_000_000) { sum += expr("x" to rand.nextDouble()) } + println("asm-mst = $sum") + return Duration.between(startTime, Instant.now()) +} + diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 511571fc9..500157908 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -25,7 +25,6 @@ kotlin.sourceSets { implementation("com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3") implementation("org.ow2.asm:asm:8.0.1") implementation("org.ow2.asm:asm-commons:8.0.1") - implementation(kotlin("reflect")) } } diff --git a/kmath-ast/src/jvmMain/kotlin/scientifik/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/scientifik/kmath/asm/internal/AsmBuilder.kt index 337219029..34a2f5461 100644 --- a/kmath-ast/src/jvmMain/kotlin/scientifik/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/scientifik/kmath/asm/internal/AsmBuilder.kt @@ -6,9 +6,10 @@ import org.objectweb.asm.MethodVisitor import org.objectweb.asm.Opcodes import scientifik.kmath.asm.internal.AsmBuilder.ClassLoader import scientifik.kmath.operations.Algebra +import scientifik.kmath.ast.MST /** - * ASM Builder is a structure that abstracts building a class that unwraps [AsmExpression] to plain Java expression. + * ASM Builder is a structure that abstracts building a class that is used to unwrap [MST] to plain Java expression. * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. * * @param T the type of AsmExpression to unwrap. @@ -205,7 +206,7 @@ internal class AsmBuilder internal constructor( private fun loadThis(): Unit = invokeMethodVisitor.visitLoadObjectVar(invokeThisVar) - internal fun loadNumberConstant(value: Number) { + private fun loadNumberConstant(value: Number) { val clazz = value.javaClass val c = clazz.name.replace('.', '/') val sigLetter = SIGNATURE_LETTERS[clazz] @@ -280,7 +281,7 @@ internal class AsmBuilder internal constructor( internal companion object { private val SIGNATURE_LETTERS: Map, String> by lazy { - mapOf( + hashMapOf( java.lang.Byte::class.java to "B", java.lang.Short::class.java to "S", java.lang.Integer::class.java to "I", diff --git a/kmath-ast/src/jvmMain/kotlin/scientifik/kmath/asm/internal/optimization.kt b/kmath-ast/src/jvmMain/kotlin/scientifik/kmath/asm/internal/optimization.kt index a39dba6b1..11fd82305 100644 --- a/kmath-ast/src/jvmMain/kotlin/scientifik/kmath/asm/internal/optimization.kt +++ b/kmath-ast/src/jvmMain/kotlin/scientifik/kmath/asm/internal/optimization.kt @@ -3,12 +3,14 @@ package scientifik.kmath.asm.internal import org.objectweb.asm.Opcodes import scientifik.kmath.operations.Algebra -private val methodNameAdapters: Map = mapOf("+" to "add", "*" to "multiply", "/" to "divide") +private val methodNameAdapters: Map by lazy { + hashMapOf("+" to "add", "*" to "multiply", "/" to "divide") +} internal fun hasSpecific(context: Algebra, name: String, arity: Int): Boolean { val aName = methodNameAdapters[name] ?: name - context::class.java.methods.find { it.name == aName && it.parameters.size == arity } + context.javaClass.methods.find { it.name == aName && it.parameters.size == arity } ?: return false return true @@ -17,7 +19,7 @@ internal fun hasSpecific(context: Algebra, name: String, arity: Int): Boo internal fun AsmBuilder.tryInvokeSpecific(context: Algebra, name: String, arity: Int): Boolean { val aName = methodNameAdapters[name] ?: name - context::class.java.methods.find { it.name == aName && it.parameters.size == arity } + context.javaClass.methods.find { it.name == aName && it.parameters.size == arity } ?: return false val owner = context::class.java.name.replace('.', '/')