diff --git a/benchmarks/arith_loop.js b/benchmarks/arith_loop.js new file mode 100644 index 0000000..6019cb9 --- /dev/null +++ b/benchmarks/arith_loop.js @@ -0,0 +1,7 @@ +let i = 0; +let s = 0; +while (i < 200000) { + i += 1; + s += i; +} +console.log(s); diff --git a/benchmarks/arith_loop.py b/benchmarks/arith_loop.py new file mode 100644 index 0000000..e4010e8 --- /dev/null +++ b/benchmarks/arith_loop.py @@ -0,0 +1,6 @@ +i = 0 +s = 0 +while i < 200000: + i += 1 + s += i +print(s) diff --git a/benchmarks/arith_loop.ynt b/benchmarks/arith_loop.ynt new file mode 100644 index 0000000..1705e47 --- /dev/null +++ b/benchmarks/arith_loop.ynt @@ -0,0 +1,7 @@ +var i = 0 +var sum = 0 +while ${i} < 200000: + var i = ${i} + 1 calc + var sum = ${sum} + ${i} calc +end_while +print_line ${sum} diff --git a/benchmarks/func_call_loop.js b/benchmarks/func_call_loop.js new file mode 100644 index 0000000..e940613 --- /dev/null +++ b/benchmarks/func_call_loop.js @@ -0,0 +1,8 @@ +function add_one(x) { + return x + 1; +} +let i = 0; +while (i < 60000) { + i = add_one(i); +} +console.log(i); diff --git a/benchmarks/func_call_loop.py b/benchmarks/func_call_loop.py new file mode 100644 index 0000000..b49c64a --- /dev/null +++ b/benchmarks/func_call_loop.py @@ -0,0 +1,7 @@ +def add_one(x): + return x + 1 + +i = 0 +while i < 60000: + i = add_one(i) +print(i) diff --git a/benchmarks/func_call_loop.ynt b/benchmarks/func_call_loop.ynt new file mode 100644 index 0000000..4b93b0b --- /dev/null +++ b/benchmarks/func_call_loop.ynt @@ -0,0 +1,12 @@ +func add_one: + var x = %in + var y = ${x} + 1 calc + push_out ${y} +return + +var i = 0 +while ${i} < 60000: + call add_one with ${i} + var i = %out +end_while +print_line ${i} diff --git a/benchmarks/list_ops.js b/benchmarks/list_ops.js new file mode 100644 index 0000000..d2318a6 --- /dev/null +++ b/benchmarks/list_ops.js @@ -0,0 +1,9 @@ +const numbers = []; +for (let i = 0; i < 30000; i++) { + numbers.push(i); +} +let s = 0; +for (let i = 0; i < 30000; i++) { + s += numbers[i]; +} +console.log(s); diff --git a/benchmarks/list_ops.py b/benchmarks/list_ops.py new file mode 100644 index 0000000..6a95bb2 --- /dev/null +++ b/benchmarks/list_ops.py @@ -0,0 +1,7 @@ +numbers = [] +for i in range(30000): + numbers.append(i) +s = 0 +for i in range(30000): + s += numbers[i] +print(s) diff --git a/benchmarks/list_ops.ynt b/benchmarks/list_ops.ynt new file mode 100644 index 0000000..af52254 --- /dev/null +++ b/benchmarks/list_ops.ynt @@ -0,0 +1,15 @@ +list numbers new +var i = 0 +while ${i} < 30000: + list numbers add ${i} + var i = ${i} + 1 calc +end_while + +var i = 0 +var sum = 0 +while ${i} < 30000: + list numbers get ${i} + var sum = ${sum} + %out calc + var i = ${i} + 1 calc +end_while +print_line ${sum} diff --git a/benchmarks/run.ps1 b/benchmarks/run.ps1 new file mode 100644 index 0000000..c1138e5 --- /dev/null +++ b/benchmarks/run.ps1 @@ -0,0 +1,81 @@ +$ErrorActionPreference = 'Stop' +Set-Location $PSScriptRoot + +$benchmarks = @( + @{ Name='arith_loop'; YesNt='arith_loop.ynt'; Py='arith_loop.py'; Js='arith_loop.js' }, + @{ Name='func_call_loop'; YesNt='func_call_loop.ynt'; Py='func_call_loop.py'; Js='func_call_loop.js' }, + @{ Name='list_ops'; YesNt='list_ops.ynt'; Py='list_ops.py'; Js='list_ops.js' } +) + +$commands = @( + @{ Lang='YesNt'; Build={ param($b) "dotnet ../YesNt.Interpreter.App/bin/Release/net10.0/yesnt.dll $($b.YesNt)" } }, + @{ Lang='Python'; Build={ param($b) "python $($b.Py)" } }, + @{ Lang='Node'; Build={ param($b) "node $($b.Js)" } } +) + +function Invoke-Timed([string]$command) { + $sw = [System.Diagnostics.Stopwatch]::StartNew() + cmd /c $command > $null + $sw.Stop() + + if ($LASTEXITCODE -ne 0) { + throw "Command failed with exit code ${LASTEXITCODE}: $command" + } + + return [double]$sw.Elapsed.TotalMilliseconds +} + +$iterations = 8 +$results = @() + +foreach ($benchmark in $benchmarks) { + foreach ($command in $commands) { + $cmd = & $command.Build $benchmark + + [void](Invoke-Timed $cmd) # warm-up run + + $times = @() + for ($i = 0; $i -lt $iterations; $i++) { + $times += Invoke-Timed $cmd + } + + $sorted = $times | Sort-Object + $mean = ($times | Measure-Object -Average).Average + $median = if ($iterations % 2 -eq 0) { + ($sorted[$iterations / 2 - 1] + $sorted[$iterations / 2]) / 2 + } else { + $sorted[[int]($iterations / 2)] + } + + $results += [pscustomobject]@{ + Benchmark = $benchmark.Name + Language = $command.Lang + MeanMs = [math]::Round($mean, 2) + MedianMs = [math]::Round($median, 2) + MinMs = [math]::Round($sorted[0], 2) + MaxMs = [math]::Round($sorted[-1], 2) + } + } +} + +$results = $results | Sort-Object Benchmark, Language +$results | Format-Table -AutoSize + +Write-Host "`nRelative slowdown (lower baseline is better):" +$slowdowns = foreach ($name in ($results.Benchmark | Select-Object -Unique)) { + $group = $results | Where-Object Benchmark -eq $name + $yesnt = ($group | Where-Object Language -eq 'YesNt').MeanMs + $python = ($group | Where-Object Language -eq 'Python').MeanMs + $node = ($group | Where-Object Language -eq 'Node').MeanMs + + [pscustomobject]@{ + Benchmark = $name + YesNt_vs_Python_x = [math]::Round($yesnt / $python, 1) + YesNt_vs_Node_x = [math]::Round($yesnt / $node, 1) + } +} + +$slowdowns | Format-Table -AutoSize + +Write-Host "`nCSV:" +$results | ConvertTo-Csv -NoTypeInformation