Compare commits

..

2 Commits

Author SHA1 Message Date
_ 5331b5a4d2 ♻️ refactor: mark where we can optimize tables for int keys
n-body actually doesn't need this, it's bottlenecked on string key
reads and writes.
2023-10-01 02:12:17 -05:00
_ 4e9f9a74c5 📝 doc: benchmark results 2023-10-01 02:00:23 -05:00
5 changed files with 57 additions and 3 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
/flamegraph.svg
/luac.out /luac.out
/perf.data*
/target /target
/untracked /untracked

View File

@ -10,3 +10,12 @@ edition = "2021"
# blake3, used to hash test vectors # blake3, used to hash test vectors
blake3 = "1.5.0" blake3 = "1.5.0"
[target.x86_64-unknown-linux-gnu]
linker = "/usr/bin/clang"
# Recommended for flamegraph
rustflags = ["-Clink-arg=-fuse-ld=lld", "-Clink-arg=-Wl,--no-rosegment"]
[profile.release]
# Recommended for profiling, e.g. flamegraph
debug = true

View File

@ -34,3 +34,33 @@
- [ ] Long strings - [ ] Long strings
- [ ] Using arrays internally for tables - [ ] Using arrays internally for tables
- [ ] Compiling Lua source code to bytecode - [ ] Compiling Lua source code to bytecode
# Benchmark
9x slower than PUC Lua, 90x slower than LuaJIT.
Based only on the n-body simulation from the computer language benchmarks,
because it's easy to run.
```
time target/release/lunar_wave_vm --script test_vectors/n_body.lua -- 500000; time lua test_vectors/n_body.lua 500000; time luajit test_vectors/n_body.lua 500000;
-0.169075164
-0.169096567
[src/main.rs:110] x = []
real 0m10.543s
user 0m10.535s
sys 0m0.000s
-0.169075164
-0.169096567
real 0m1.173s
user 0m1.165s
sys 0m0.004s
-0.169075164
-0.169096567
real 0m0.117s
user 0m0.116s
sys 0m0.000s
```

View File

@ -508,7 +508,7 @@ impl <'a> State <'a> {
let value = { let value = {
let table = self.reg (*b).as_table ().expect ("GetI only works on tables").borrow (); let table = self.reg (*b).as_table ().expect ("GetI only works on tables").borrow ();
table.get (key) table.get_int (key)
}; };
*self.reg_mut (*a) = value; *self.reg_mut (*a) = value;
@ -752,7 +752,7 @@ impl <'a> State <'a> {
let mut dst = self.reg_mut (*a).as_table ().expect ("SetI only works on tables").borrow_mut (); let mut dst = self.reg_mut (*a).as_table ().expect ("SetI only works on tables").borrow_mut ();
dst.insert (i64::from (*b), value); dst.insert_int (i64::from (*b), value);
}, },
Instruction::SetList (a, b, c, k) => { Instruction::SetList (a, b, c, k) => {
if *b == 0 { if *b == 0 {
@ -766,7 +766,7 @@ impl <'a> State <'a> {
for i in 1..=*b { for i in 1..=*b {
let src = self.reg (*a + i); let src = self.reg (*a + i);
dst.insert (Value::from (i64::from (*c + i)), src.clone ()); dst.insert_int (i64::from (*c + i), src.clone ());
} }
}, },
Instruction::SetTabUp (_a, _b, _c) => unimplemented! (), Instruction::SetTabUp (_a, _b, _c) => unimplemented! (),

View File

@ -261,10 +261,16 @@ impl Table {
self.get_inner (&(key.into ())) self.get_inner (&(key.into ()))
} }
pub fn get_int (&self, key: i64) -> Value {
self.get_inner (&(key.into ()))
}
fn insert_inner (&mut self, a: Value, b: Value) { fn insert_inner (&mut self, a: Value, b: Value) {
self.hash.insert (a, b); self.hash.insert (a, b);
} }
/// Insert value at arbitrary key
pub fn insert <A: Into <Value>, B: Into <Value>> ( pub fn insert <A: Into <Value>, B: Into <Value>> (
&mut self, &mut self,
a: A, a: A,
@ -273,6 +279,13 @@ impl Table {
self.insert_inner (a.into (), b.into ()) self.insert_inner (a.into (), b.into ())
} }
/// Insert value at integer key
pub fn insert_int <A: Into <Value>> (&mut self, k: i64, v: A)
{
self.insert_inner (k.into (), v.into ())
}
pub fn length (&self) -> i64 { pub fn length (&self) -> i64 {
for i in 1..i64::MAX { for i in 1..i64::MAX {
if self.get (i) == Value::Nil { if self.get (i) == Value::Nil {