Add naive benchmarks to compare MSTExpression, FunctionalExpressions and ASM Expressions API #108
@ -24,6 +24,7 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":kmath-ast"))
|
||||||
implementation(project(":kmath-core"))
|
implementation(project(":kmath-core"))
|
||||||
implementation(project(":kmath-coroutines"))
|
implementation(project(":kmath-coroutines"))
|
||||||
implementation(project(":kmath-commons"))
|
implementation(project(":kmath-commons"))
|
||||||
|
@ -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())
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,6 @@ kotlin.sourceSets {
|
|||||||
implementation("com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3")
|
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:8.0.1")
|
||||||
implementation("org.ow2.asm:asm-commons:8.0.1")
|
implementation("org.ow2.asm:asm-commons:8.0.1")
|
||||||
implementation(kotlin("reflect"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,10 @@ import org.objectweb.asm.MethodVisitor
|
|||||||
import org.objectweb.asm.Opcodes
|
import org.objectweb.asm.Opcodes
|
||||||
import scientifik.kmath.asm.internal.AsmBuilder.ClassLoader
|
import scientifik.kmath.asm.internal.AsmBuilder.ClassLoader
|
||||||
import scientifik.kmath.operations.Algebra
|
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.
|
* 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.
|
* @param T the type of AsmExpression to unwrap.
|
||||||
@ -205,7 +206,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
|
|
||||||
private fun loadThis(): Unit = invokeMethodVisitor.visitLoadObjectVar(invokeThisVar)
|
private fun loadThis(): Unit = invokeMethodVisitor.visitLoadObjectVar(invokeThisVar)
|
||||||
|
|
||||||
internal fun loadNumberConstant(value: Number) {
|
private fun loadNumberConstant(value: Number) {
|
||||||
val clazz = value.javaClass
|
val clazz = value.javaClass
|
||||||
val c = clazz.name.replace('.', '/')
|
val c = clazz.name.replace('.', '/')
|
||||||
val sigLetter = SIGNATURE_LETTERS[clazz]
|
val sigLetter = SIGNATURE_LETTERS[clazz]
|
||||||
@ -280,7 +281,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
|
|
||||||
internal companion object {
|
internal companion object {
|
||||||
private val SIGNATURE_LETTERS: Map<Class<out Any>, String> by lazy {
|
private val SIGNATURE_LETTERS: Map<Class<out Any>, String> by lazy {
|
||||||
mapOf(
|
hashMapOf(
|
||||||
java.lang.Byte::class.java to "B",
|
java.lang.Byte::class.java to "B",
|
||||||
java.lang.Short::class.java to "S",
|
java.lang.Short::class.java to "S",
|
||||||
java.lang.Integer::class.java to "I",
|
java.lang.Integer::class.java to "I",
|
||||||
|
@ -3,12 +3,14 @@ package scientifik.kmath.asm.internal
|
|||||||
import org.objectweb.asm.Opcodes
|
import org.objectweb.asm.Opcodes
|
||||||
import scientifik.kmath.operations.Algebra
|
import scientifik.kmath.operations.Algebra
|
||||||
|
|
||||||
private val methodNameAdapters: Map<String, String> = mapOf("+" to "add", "*" to "multiply", "/" to "divide")
|
private val methodNameAdapters: Map<String, String> by lazy {
|
||||||
|
hashMapOf("+" to "add", "*" to "multiply", "/" to "divide")
|
||||||
|
}
|
||||||
|
|
||||||
internal fun <T> hasSpecific(context: Algebra<T>, name: String, arity: Int): Boolean {
|
internal fun <T> hasSpecific(context: Algebra<T>, name: String, arity: Int): Boolean {
|
||||||
val aName = methodNameAdapters[name] ?: name
|
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 false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -17,7 +19,7 @@ internal fun <T> hasSpecific(context: Algebra<T>, name: String, arity: Int): Boo
|
|||||||
internal fun <T> AsmBuilder<T>.tryInvokeSpecific(context: Algebra<T>, name: String, arity: Int): Boolean {
|
internal fun <T> AsmBuilder<T>.tryInvokeSpecific(context: Algebra<T>, name: String, arity: Int): Boolean {
|
||||||
val aName = methodNameAdapters[name] ?: name
|
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 false
|
||||||
|
|
||||||
val owner = context::class.java.name.replace('.', '/')
|
val owner = context::class.java.name.replace('.', '/')
|
||||||
|
Loading…
Reference in New Issue
Block a user