I regularly benchmark Riff as I implement new features into the language or new optimizations for the VM. These benchmarks are very useful for finding incorrect and/or poorly-performing parts of the interpreter.

`luajit` |
0.090s |

`luajit -j off` |
0.463s |

`riff` |
0.541s |

`lua` |
0.757s |

`ruby` |
0.829s |

`luajit` |
0.136s |

`luajit -j off` |
0.578s |

`riff` |
0.791s |

`lua` |
1.015s |

`ruby` |
1.376s |

`luajit` |
0.020s |

`luajit -j off` |
0.256s |

`lua` |
0.449s |

`riff` |
0.522s |

`ruby` |
1.224s |

## Notable Recent Improvements

The implementation of computed goto in Riff’s virtual machine sparked a significant overall performance boost for programs which relied heavily on VM control flow (recursive Fibonacci and Ackermann programs are good examples). Before, the interpreter loop was a standard giant `switch`

-`case`

construct inside a `while`

loop^{1}.

Program | Before | After | Δ |
---|---|---|---|

`fib(35)` |
0.638s | 0.541s | -15.21% |

`ack(3,10)` |
1.146s | 0.791s | -30.98% |

`s-n(500)` |
0.615s | 0.522s | -15.12% |

These improvements line up with the improvements noted in Eli Bendersky’s blog post.

I did some simple benchmarking with random opcodes and the

`goto`

version is 25% faster than the`switch`

version.

Comments inside the CPython implementation note that using computed goto made the Python VM 15-20% faster

## Methodology

Programs were benchmarked on a 2018 Mac mini with a 3.0 GHz 6-core processor and 32GB of 2667 MHz DDR4 RAM. Programs were timed using the builtin shell utility `time`

. Each program was run ten times, with the best time being kept.

`riff`

was compiled with Apple clang 12.0 (`clang-1200.0.32.27`

) with `-O3`

optimizations enabled.

Interpreter | Version | Source |
---|---|---|

Lua | 5.4.2 | Homebrew-installed |

LuaJIT | 2.0.5 | Homebrew-installed |

Ruby | 2.6.3p62 | Default interpreter on macOS 11.2 |

## Programs Used

Recursive Fibonacci (Lua)

```
function fib(n)
if n < 2 then
return n
end
return fib(n-1) + fib(n-2)
end
print(fib(35))
```

Recursive Fibonacci (Riff)

```
fn fib(n) {
return n < 2 ? n : fib(n-1) + fib(n-2)
}35) fib(
```

Recursive Fibonacci (Ruby)

```
def fib(n)
if n < 2 then
nelse
-1) + fib(n-2)
fib(nend
end
puts fib(35)
```

Ackermann (Lua)

```
function ack(M,N)
if M == 0 then return N + 1 end
if N == 0 then return ack(M-1,1) end
return ack(M-1,ack(M, N-1))
end
print(ack(3,10))
```

Ackermann (Riff)

```
fn ack(m, n) {
if m == 0
return n + 1
elif n == 0
return ack(m-1, 1)
else
return ack(m-1, ack(m, n-1))
}3,10) ack(
```

Ackermann (Ruby)

```
def ack(m, n)
if m == 0
+ 1
n elsif n == 0
-1, 1)
ack(melse
-1, ack(m, n-1))
ack(mend
end
puts ack(3,10)
```

Spectral norm (Riff)

```
fn A(i, j) {
local ij = i+j
return 1.0 / (ij*(ij+1)/2+i+1)
}
fn Av(x, y, N) {
for i in N-1 {
local a = 0
for j in N-1
a += x[j] * A(i, j)
y[i] = a
}
}
fn Atv(x, y, N) {
for i in N-1 {
local a = 0
for j in N-1
a += x[j] * A(j, i)
y[i] = a
}
}
fn AtAv(x, y, t, N) {
Av(x, t, N)
Atv(t, y, N)
}
local u = {},
v = {},
t = {},1] ? num(arg[1]) : 100
N = arg[
for i in N-1
1
u[i] =
for i in 9 {
AtAv(u, v, t, N)
AtAv(v, u, t, N)
}
local vBv = 0, vv = 0
for i in N-1 {
local vi = v[i]
vBv += u[i] * vi
vv += vi * vi
}
fmt("%0.9f", sqrt(vBv / vv))
```

Spectral norm programs (Lua, Ruby) were sourced from the Computer Language Benchmarks Game.

It still is, actually, if the compiler doesn’t support GNU C extensions[return]