From 44f9573eec255a47c9eb8834cd4f27071d70e6ce Mon Sep 17 00:00:00 2001 From: sergeych Date: Mon, 16 Feb 2026 17:33:05 +0300 Subject: [PATCH] Add mixed compare benchmark baseline --- .../kotlin/MixedCompareBenchmarkTest.kt | 93 +++++++++++++++++++ notes/fast_ops_optimizations_plan.md | 19 ++++ notes/mixed_compare_benchmark_baseline.md | 12 +++ 3 files changed, 124 insertions(+) create mode 100644 lynglib/src/commonTest/kotlin/MixedCompareBenchmarkTest.kt create mode 100644 notes/fast_ops_optimizations_plan.md create mode 100644 notes/mixed_compare_benchmark_baseline.md diff --git a/lynglib/src/commonTest/kotlin/MixedCompareBenchmarkTest.kt b/lynglib/src/commonTest/kotlin/MixedCompareBenchmarkTest.kt new file mode 100644 index 0000000..2ac1cec --- /dev/null +++ b/lynglib/src/commonTest/kotlin/MixedCompareBenchmarkTest.kt @@ -0,0 +1,93 @@ +/* + * 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.Script +import net.sergeych.lyng.obj.ObjInt +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.time.TimeSource + +class MixedCompareBenchmarkTest { + @Test + fun benchmarkMixedCompareOps() = runTest { + if (!Benchmarks.enabled) return@runTest + val iterations = 200000 + val script = """ + fun mixedCompareBench(n) { + var acc = 0 + var r = 0.0 + val strs = ["a","b","aa","bb","abc","abd","zzz",""] + var i = 0 + while(i < n) { + val si = strs[i % 8] + if( si == "a" ) acc += 1 else acc -= 1 + if( si != "zzz" ) acc += 2 + if( si == "" ) acc += 3 + + if( i < (i % 5) ) acc += 1 else acc -= 1 + if( (i % 3) == 0 ) acc += 2 + + val r1 = i + 0.5 + if( r1 > i ) acc += 1 + if( i < r1 ) acc += 1 + r += r1 * 0.25 + if( r > 1000.0 ) acc += 1 + + i++ + } + acc + } + """.trimIndent() + + val scope = Script.newScope() + scope.eval(script) + val expected = expectedValue(iterations) + + val start = TimeSource.Monotonic.markNow() + val result = scope.eval("mixedCompareBench($iterations)") as ObjInt + val elapsedMs = start.elapsedNow().inWholeMilliseconds + println("[DEBUG_LOG] [BENCH] mixed-compare elapsed=${elapsedMs} ms") + assertEquals(expected, result.value) + } + + private fun expectedValue(iterations: Int): Long { + val strs = arrayOf("a", "b", "aa", "bb", "abc", "abd", "zzz", "") + var acc = 0L + var r = 0.0 + var i = 0 + while (i < iterations) { + val si = strs[i % 8] + if (si == "a") acc += 1 else acc -= 1 + if (si != "zzz") acc += 2 + if (si == "") acc += 3 + + if (i < (i % 5)) acc += 1 else acc -= 1 + if ((i % 3) == 0) acc += 2 + + val r1 = i + 0.5 + if (r1 > i) acc += 1 + if (i < r1) acc += 1 + r += r1 * 0.25 + if (r > 1000.0) acc += 1 + + i += 1 + } + return acc + } +} diff --git a/notes/fast_ops_optimizations_plan.md b/notes/fast_ops_optimizations_plan.md new file mode 100644 index 0000000..b43af54 --- /dev/null +++ b/notes/fast_ops_optimizations_plan.md @@ -0,0 +1,19 @@ +# Fast Ops Optimizations Plan (Draft) + +Baseline +- See `notes/nested_range_baseline.md` + +Candidates (not started) +1) Primitive comparisons + - Emit fast CMP variants for known ObjString/ObjInt/ObjReal/ObjBool across all comparison operators. +2) Mixed numeric ops + - Ensure INT+REAL arithmetic uses INT_TO_REAL + REAL op with no extra moves/boxing. +3) Boolean conversion + - Skip OBJ_TO_BOOL when compiler already has a BOOL slot. +4) Range/loop hot path + - Keep range iteration in INT ops, avoid accidental boxing. + - Confirm loop-var slots avoid re-boxing in loop bodies. +5) String ops + - Extend fast path for string comparisons in hot loops. +6) Box/unbox audit + - Identify remaining BOX_OBJ / OBJ_TO_* in inner loops and eliminate when safe. diff --git a/notes/mixed_compare_benchmark_baseline.md b/notes/mixed_compare_benchmark_baseline.md new file mode 100644 index 0000000..8a52326 --- /dev/null +++ b/notes/mixed_compare_benchmark_baseline.md @@ -0,0 +1,12 @@ +# Mixed Compare Benchmark Baseline + +Date: 2026-02-16 + +Benchmark: +- MixedCompareBenchmarkTest.benchmarkMixedCompareOps + +Command: +`BENCHMARKS=true timeout 20s ./gradlew :lynglib:jvmTest --tests MixedCompareBenchmarkTest --rerun-tasks` + +Result: +- mixed-compare elapsed=374 ms