more optimizations
This commit is contained in:
1 parent
1498140892
commit
029fde2883
7 files changed
+475
-50
No files matched your search
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* JVM micro-benchmarks for primitive arithmetic and comparison fast paths.
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.sergeych.lyng.PerfFlags
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.obj.ObjInt
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ArithmeticBenchmarkTest {
|
||||
@Test
|
||||
fun benchmarkIntArithmeticAndComparisons() = runBlocking {
|
||||
val n = 400_000
|
||||
val sumScript = """
|
||||
var s = 0
|
||||
var i = 0
|
||||
while (i < $n) {
|
||||
s = s + i
|
||||
i = i + 1
|
||||
}
|
||||
s
|
||||
""".trimIndent()
|
||||
|
||||
// Baseline: disable primitive fast ops
|
||||
PerfFlags.PRIMITIVE_FASTOPS = false
|
||||
val scope1 = Scope()
|
||||
val t0 = System.nanoTime()
|
||||
val r1 = (scope1.eval(sumScript) as ObjInt).value
|
||||
val t1 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] int-sum x$n [PRIMITIVE_FASTOPS=OFF]: ${(t1 - t0)/1_000_000.0} ms")
|
||||
|
||||
// Optimized
|
||||
PerfFlags.PRIMITIVE_FASTOPS = true
|
||||
val scope2 = Scope()
|
||||
val t2 = System.nanoTime()
|
||||
val r2 = (scope2.eval(sumScript) as ObjInt).value
|
||||
val t3 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] int-sum x$n [PRIMITIVE_FASTOPS=ON]: ${(t3 - t2)/1_000_000.0} ms")
|
||||
|
||||
val expected = (n.toLong() - 1L) * n / 2L
|
||||
assertEquals(expected, r1)
|
||||
assertEquals(expected, r2)
|
||||
|
||||
// Comparison heavy (branchy) loop
|
||||
val cmpScript = """
|
||||
var s = 0
|
||||
var i = 0
|
||||
while (i < $n) {
|
||||
if (i % 2 == 0) s = s + 1 else s = s + 2
|
||||
i = i + 1
|
||||
}
|
||||
s
|
||||
""".trimIndent()
|
||||
|
||||
PerfFlags.PRIMITIVE_FASTOPS = false
|
||||
val scope3 = Scope()
|
||||
val t4 = System.nanoTime()
|
||||
val c1 = (scope3.eval(cmpScript) as ObjInt).value
|
||||
val t5 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] int-cmp x$n [PRIMITIVE_FASTOPS=OFF]: ${(t5 - t4)/1_000_000.0} ms")
|
||||
|
||||
PerfFlags.PRIMITIVE_FASTOPS = true
|
||||
val scope4 = Scope()
|
||||
val t6 = System.nanoTime()
|
||||
val c2 = (scope4.eval(cmpScript) as ObjInt).value
|
||||
val t7 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] int-cmp x$n [PRIMITIVE_FASTOPS=ON]: ${(t7 - t6)/1_000_000.0} ms")
|
||||
|
||||
// Expected: half of n even add 1, half odd add 2 (n even assumed)
|
||||
val expectedCmp = (n / 2) * 1L + (n - n / 2) * 2L
|
||||
assertEquals(expectedCmp, c1)
|
||||
assertEquals(expectedCmp, c2)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* JVM micro-benchmarks for function/method call overhead and argument building.
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.sergeych.lyng.PerfFlags
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.obj.ObjInt
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class CallBenchmarkTest {
|
||||
@Test
|
||||
fun benchmarkSimpleFunctionCalls() = runBlocking {
|
||||
val n = 300_000 // keep it fast for CI
|
||||
|
||||
// A tiny script with 0, 1, 2 arg functions and a loop using them
|
||||
val script = """
|
||||
fun f0() { 1 }
|
||||
fun f1(a) { a }
|
||||
fun f2(a,b) { a + b }
|
||||
|
||||
var s = 0
|
||||
var i = 0
|
||||
while (i < $n) {
|
||||
s = s + f0()
|
||||
s = s + f1(1)
|
||||
s = s + f2(1, 1)
|
||||
i = i + 1
|
||||
}
|
||||
s
|
||||
""".trimIndent()
|
||||
|
||||
// Disable ARG_BUILDER for baseline
|
||||
PerfFlags.ARG_BUILDER = false
|
||||
val scope1 = Scope()
|
||||
val t0 = System.nanoTime()
|
||||
val r1 = (scope1.eval(script) as ObjInt).value
|
||||
val t1 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] calls x$n [ARG_BUILDER=OFF]: ${(t1 - t0)/1_000_000.0} ms")
|
||||
|
||||
// Enable ARG_BUILDER for optimized run
|
||||
PerfFlags.ARG_BUILDER = true
|
||||
val scope2 = Scope()
|
||||
val t2 = System.nanoTime()
|
||||
val r2 = (scope2.eval(script) as ObjInt).value
|
||||
val t3 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] calls x$n [ARG_BUILDER=ON]: ${(t3 - t2)/1_000_000.0} ms")
|
||||
|
||||
// Correctness: each loop adds 1 + 1 + (1+1) = 4
|
||||
val expected = 4L * n
|
||||
assertEquals(expected, r1)
|
||||
assertEquals(expected, r2)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* JVM micro-benchmarks for FieldRef and MethodCallRef PICs.
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.sergeych.lyng.PerfFlags
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.obj.ObjInt
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class PicBenchmarkTest {
|
||||
@Test
|
||||
fun benchmarkFieldGetSetPic() = runBlocking {
|
||||
val iterations = 300_000
|
||||
val script = """
|
||||
class C() {
|
||||
var x = 0
|
||||
fun add1() { x = x + 1 }
|
||||
fun getX() { x }
|
||||
}
|
||||
val c = C()
|
||||
var i = 0
|
||||
while(i < $iterations) {
|
||||
c.x = c.x + 1
|
||||
i = i + 1
|
||||
}
|
||||
c.x
|
||||
""".trimIndent()
|
||||
|
||||
// PIC OFF
|
||||
PerfFlags.FIELD_PIC = false
|
||||
val scope1 = Scope()
|
||||
val t0 = System.nanoTime()
|
||||
val r1 = (scope1.eval(script) as ObjInt).value
|
||||
val t1 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] Field PIC=OFF: ${(t1 - t0) / 1_000_000.0} ms")
|
||||
assertEquals(iterations.toLong(), r1)
|
||||
|
||||
// PIC ON
|
||||
PerfFlags.FIELD_PIC = true
|
||||
val scope2 = Scope()
|
||||
val t2 = System.nanoTime()
|
||||
val r2 = (scope2.eval(script) as ObjInt).value
|
||||
val t3 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] Field PIC=ON: ${(t3 - t2) / 1_000_000.0} ms")
|
||||
assertEquals(iterations.toLong(), r2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun benchmarkMethodPic() = runBlocking {
|
||||
val iterations = 200_000
|
||||
val script = """
|
||||
class C() {
|
||||
var x = 0
|
||||
fun add(v) { x = x + v }
|
||||
fun get() { x }
|
||||
}
|
||||
val c = C()
|
||||
var i = 0
|
||||
while(i < $iterations) {
|
||||
c.add(1)
|
||||
i = i + 1
|
||||
}
|
||||
c.get()
|
||||
""".trimIndent()
|
||||
|
||||
// PIC OFF
|
||||
PerfFlags.METHOD_PIC = false
|
||||
val scope1 = Scope()
|
||||
val t0 = System.nanoTime()
|
||||
val r1 = (scope1.eval(script) as ObjInt).value
|
||||
val t1 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] Method PIC=OFF: ${(t1 - t0) / 1_000_000.0} ms")
|
||||
assertEquals(iterations.toLong(), r1)
|
||||
|
||||
// PIC ON
|
||||
PerfFlags.METHOD_PIC = true
|
||||
val scope2 = Scope()
|
||||
val t2 = System.nanoTime()
|
||||
val r2 = (scope2.eval(script) as ObjInt).value
|
||||
val t3 = System.nanoTime()
|
||||
println("[DEBUG_LOG] [BENCH] Method PIC=ON: ${(t3 - t2) / 1_000_000.0} ms")
|
||||
assertEquals(iterations.toLong(), r2)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user