use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use fusevm::{Chunk, ChunkBuilder, JitCompiler, Op};
static UNIQ: AtomicU64 = AtomicU64::new(1);
fn slot_chunk(salt: i64, n: usize) -> Chunk {
let mut b = ChunkBuilder::new();
b.emit(Op::GetSlot(0), 1);
b.emit(Op::LoadInt(salt), 1);
b.emit(Op::Add, 1);
for _ in 0..n {
b.emit(Op::LoadInt(1), 1);
b.emit(Op::Add, 1);
b.emit(Op::LoadInt(2), 1);
b.emit(Op::Mul, 1);
b.emit(Op::LoadInt(2), 1);
b.emit(Op::Div, 1);
}
b.build()
}
fn block_chunk(limit: i32) -> Chunk {
let mut b = ChunkBuilder::new();
b.emit(Op::PushFrame, 1);
b.emit(Op::LoadInt(0), 1);
b.emit(Op::SetSlot(0), 1);
b.emit(Op::LoadInt(0), 1);
b.emit(Op::SetSlot(1), 1);
b.emit(Op::GetSlot(0), 1);
b.emit(Op::GetSlot(1), 1);
b.emit(Op::Add, 1);
b.emit(Op::SetSlot(0), 1);
b.emit(Op::PreIncSlotVoid(1), 1);
b.emit(Op::SlotLtIntJumpIfFalse(1, limit, 12), 1);
b.emit(Op::Jump(5), 1);
b.emit(Op::GetSlot(0), 1);
b.build()
}
fn bench_dir() -> PathBuf {
let dir = std::env::temp_dir().join(format!("fusevm_bench_jit_cache_{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn bench(c: &mut Criterion) {
let dir = bench_dir();
let slots = [7i64];
let n = 400;
c.bench_function("cold_jit_compile", |b| {
b.iter(|| {
let salt = UNIQ.fetch_add(1, Ordering::Relaxed) as i64;
let chunk = slot_chunk(salt, n);
std::thread::spawn(move || {
let jit = JitCompiler::new();
jit.set_jit_cache_dir(None);
black_box(jit.try_run_linear(black_box(&chunk), black_box(&slots)))
})
.join()
.unwrap()
})
});
let cached_chunk = slot_chunk(-999, n);
{
let jit = JitCompiler::new();
jit.set_jit_cache_dir(Some(dir.clone()));
let _ = jit.try_run_linear(&cached_chunk, &slots); jit.set_jit_cache_dir(None);
}
c.bench_function("cached_native_load", |b| {
b.iter(|| {
let chunk = cached_chunk.clone();
let dir = dir.clone();
std::thread::spawn(move || {
let jit = JitCompiler::new();
jit.set_jit_cache_dir(Some(dir));
let r = black_box(jit.try_run_linear(black_box(&chunk), black_box(&slots)));
jit.set_jit_cache_dir(None);
r
})
.join()
.unwrap()
})
});
c.bench_function("cold_block_compile", |b| {
b.iter(|| {
let salt = (UNIQ.fetch_add(1, Ordering::Relaxed) as i32) % 100_000 + 1;
let chunk = block_chunk(salt);
std::thread::spawn(move || {
let jit = JitCompiler::new();
jit.set_jit_cache_dir(None);
let mut s = vec![0i64; 4];
black_box(jit.try_run_block_eager(black_box(&chunk), &mut s))
})
.join()
.unwrap()
})
});
let cached_block = block_chunk(1234);
{
let jit = JitCompiler::new();
jit.set_jit_cache_dir(Some(dir.clone()));
let mut s = vec![0i64; 4];
let _ = jit.try_run_block_eager(&cached_block, &mut s); jit.set_jit_cache_dir(None);
}
c.bench_function("cached_block_load", |b| {
b.iter(|| {
let chunk = cached_block.clone();
let dir = dir.clone();
std::thread::spawn(move || {
let jit = JitCompiler::new();
jit.set_jit_cache_dir(Some(dir));
let mut s = vec![0i64; 4];
let r = black_box(jit.try_run_block_eager(black_box(&chunk), &mut s));
jit.set_jit_cache_dir(None);
r
})
.join()
.unwrap()
})
});
let _ = std::fs::remove_dir_all(&dir);
}
criterion_group!(benches, bench);
criterion_main!(benches);