more optimizations

This commit is contained in:
sergeych committed 2025-11-10 02:14:18 +01:00
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)
}
}