use std::time::{Duration, Instant};
use typelisp::{Checker, Heap, Interp, Reader};
const WORKLOADS: &[(&str, &str)] = &[
(
"i64 gcd",
r#"
(defun bench ((n i32)) i64
(let ((acc (as i64 0)))
(dotimes (i n)
(setf acc (+ acc (gcd (+ (as i64 i) 4620) 1071))))
acc))
(bench 20000)
"#,
),
(
"i64 abs/signum/rem",
r#"
(defun bench ((n i32)) i64
(let ((acc (as i64 0)))
(dotimes (i n)
(setf acc (+ acc (abs (- (rem (as i64 i) 7) 3)) (signum (- (as i64 i) 100)))))
acc))
(bench 50000)
"#,
),
(
"int abs/+",
r#"
(defun bench ((n int)) int
(let ((acc 0))
(dotimes (i n)
(setf acc (+ acc (abs (- i 500)))))
acc))
(bench 20000)
"#,
),
(
"f64 abs/signum",
r#"
(defun bench ((n i32)) f64
(let ((acc 0.0))
(dotimes (i n)
(setf acc (+ acc (abs (- (as f64 (as i64 i)) 250.0)) (signum (- (as f64 (as i64 i)) 250.0)))))
acc))
(bench 50000)
"#,
),
];
fn load(compiled: bool) -> (Heap, Checker, Interp, Duration) {
let mut heap = Heap::with_capacity(1 << 18);
let mut chk = Checker::new();
let mut interp = Interp::new();
let t0 = Instant::now();
if compiled {
typelisp::load_prelude(&mut heap, &mut chk, &mut interp);
} else {
typelisp::prelude::load_interpreted(&mut heap, &mut chk, &mut interp);
}
let elapsed = t0.elapsed();
typelisp::load_compiler_aot(&mut heap, &mut chk, &mut interp);
(heap, chk, interp, elapsed)
}
fn run(heap: &mut Heap, chk: &mut Checker, interp: &Interp, src: &str) -> Duration {
let r = Reader::new();
let forms = r.read_all(heap, src).expect("read failed");
let checked: Vec<_> =
forms.into_iter().map(|v| chk.check_form(heap, interp, v).expect("check failed")).collect();
let t0 = Instant::now();
for tl in checked {
interp.exec(heap, tl).expect("eval failed");
}
t0.elapsed()
}
fn startup_breakdown() {
use typelisp::compile::bootstrap::island_source_hash;
use typelisp::Value;
println!("startup breakdown (one process, fresh 1<<18-cell heap per measurement):");
for (label, source) in [("prelude", typelisp::prelude::SOURCE), ("island", typelisp::compiler::SOURCE)] {
let mut heap = Heap::with_capacity(1 << 18);
let mut chk = Checker::new();
let mut interp = Interp::new();
if label == "island" {
typelisp::prelude::load_interpreted(&mut heap, &mut chk, &mut interp);
typelisp::compile::install_llvm_backend();
}
let r = Reader::new();
let t0 = Instant::now();
let forms = r.read_all(&mut heap, source).expect("read failed");
let read = t0.elapsed();
let t0 = Instant::now();
let predeclare = t0.elapsed();
let mut checked: Vec<Value> = Vec::with_capacity(forms.len());
let mut check = Duration::ZERO;
let mut exec = Duration::ZERO;
for v in forms {
let t0 = Instant::now();
let tl = chk.check_form(&mut heap, &interp, v).expect("check failed");
check += t0.elapsed();
let _ = chk.take_warnings();
heap.push_root(tl);
checked.push(tl);
let t0 = Instant::now();
interp.exec(&mut heap, tl).expect("exec failed");
exec += t0.elapsed();
}
let rehash = if label == "island" {
let t0 = Instant::now();
island_source_hash(source).expect("hash failed");
t0.elapsed()
} else {
Duration::ZERO
};
let ms = |d: Duration| d.as_secs_f64() * 1000.0;
println!(
" {:<8} read {:>7.1} ms | predeclare {:>6.1} ms | check {:>7.1} ms | exec {:>7.1} ms | re-hash {:>6.1} ms",
label, ms(read), ms(predeclare), ms(check), ms(exec), ms(rehash)
);
}
let mut heap = Heap::with_capacity(1 << 18);
let mut chk = Checker::new();
let mut interp = Interp::new();
let t0 = Instant::now();
typelisp::load_prelude(&mut heap, &mut chk, &mut interp);
let prelude_total = t0.elapsed();
let t0 = Instant::now();
typelisp::load_compiler_aot(&mut heap, &mut chk, &mut interp);
let island_total = t0.elapsed();
println!(
" real loaders: load_prelude {:.1} ms, load_compiler_aot {:.1} ms (the excess over the rows \
above is the bitcode install)",
prelude_total.as_secs_f64() * 1000.0,
island_total.as_secs_f64() * 1000.0
);
let t0 = Instant::now();
let sig = chk.signature(&heap).expect("signature");
println!(
" baseline signature for (dump ...): {:.1} ms over {} entries",
t0.elapsed().as_secs_f64() * 1000.0,
sig.len()
);
println!();
}
fn main() {
startup_breakdown();
let (_h1, _c1, _i1, compiled_load) = load(true);
let (_h2, _c2, _i2, interpreted_load) = load(false);
println!("prelude load (read+check+exec, plus the bitcode install for compiled):");
println!(" compiled {:>8.1} ms", compiled_load.as_secs_f64() * 1000.0);
println!(" interpreted {:>8.1} ms", interpreted_load.as_secs_f64() * 1000.0);
println!(
" cost of installing the artifact: {:+.1} ms",
(compiled_load.as_secs_f64() - interpreted_load.as_secs_f64()) * 1000.0
);
println!();
println!("{:<24} {:>12} {:>12} {:>10}", "workload", "compiled", "interpreted", "speedup");
for (name, src) in WORKLOADS {
let (mut ch, mut cc, ci, _) = load(true);
let compiled = run(&mut ch, &mut cc, &ci, src);
let (mut ih, mut ic, ii, _) = load(false);
let interpreted = run(&mut ih, &mut ic, &ii, src);
println!(
"{:<24} {:>9.1} ms {:>9.1} ms {:>9.2}x",
name,
compiled.as_secs_f64() * 1000.0,
interpreted.as_secs_f64() * 1000.0,
interpreted.as_secs_f64() / compiled.as_secs_f64()
);
}
}