lyng/lynglib/src/commonTest/kotlin/NestedRangeBenchmarkTest.kt

102 lines
3.8 KiB
Kotlin

/*
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import kotlinx.coroutines.test.runTest
import net.sergeych.lyng.Benchmarks
import net.sergeych.lyng.Compiler
import net.sergeych.lyng.ForInStatement
import net.sergeych.lyng.Script
import net.sergeych.lyng.Statement
import net.sergeych.lyng.bytecode.CmdDisassembler
import net.sergeych.lyng.bytecode.BytecodeStatement
import net.sergeych.lyng.obj.ObjInt
import kotlin.time.TimeSource
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.Ignore
@Ignore
class NestedRangeBenchmarkTest {
@Test
fun benchmarkHappyNumbersNestedRanges() = runTest {
if (!Benchmarks.enabled) return@runTest
val bodyScript = """
var count = 0
for( n1 in 0..9 )
for( n2 in 0..9 )
for( n3 in 0..9 )
for( n4 in 0..9 )
for( n5 in 0..9 )
for( n6 in 0..9 )
if( n1 + n2 + n3 == n4 + n5 + n6 ) count++
count
""".trimIndent()
val compiled = Compiler.compile(bodyScript)
dumpNestedLoopBytecode(compiled.debugStatements())
val script = """
fun naiveCountHappyNumbers() {
$bodyScript
}
""".trimIndent()
val scope = Script.newScope()
scope.eval(script)
val fnDisasm = scope.disassembleSymbol("naiveCountHappyNumbers")
println("[DEBUG_LOG] [BENCH] nested-happy function naiveCountHappyNumbers cmd:\n$fnDisasm")
runMode(scope)
}
private suspend fun runMode(scope: net.sergeych.lyng.Scope) {
val start = TimeSource.Monotonic.markNow()
val result = scope.eval("naiveCountHappyNumbers()") as ObjInt
val elapsedMs = start.elapsedNow().inWholeMilliseconds
println("[DEBUG_LOG] [BENCH] nested-happy elapsed=${elapsedMs} ms")
assertEquals(55252L, result.value)
}
private fun dumpNestedLoopBytecode(statements: List<Statement>) {
var current: Statement? = statements.firstOrNull { stmt ->
stmt is BytecodeStatement && stmt.original is ForInStatement
}
var depth = 1
while (current is BytecodeStatement && current.original is ForInStatement) {
val original = current.original as ForInStatement
println(
"[DEBUG_LOG] [BENCH] nested-happy loop depth=$depth " +
"constRange=${original.constRange} canBreak=${original.canBreak} " +
"loopSlotPlan=${original.loopSlotPlan}"
)
val fn = current.bytecodeFunction()
val slots = fn.scopeSlotNames.mapIndexed { idx, name ->
val slotName = name ?: "s$idx"
"$slotName@${fn.scopeSlotIndices[idx]}"
}
println("[DEBUG_LOG] [BENCH] nested-happy slots depth=$depth: ${slots.joinToString(", ")}")
val disasm = CmdDisassembler.disassemble(fn)
println("[DEBUG_LOG] [BENCH] nested-happy cmd depth=$depth:\n$disasm")
current = original.body
depth += 1
}
if (depth == 1) {
println("[DEBUG_LOG] [BENCH] nested-happy cmd: <not found>")
}
}
}