use std::time::Instant;
#[inline(never)]
fn fib_direct(k: i64) -> i64 {
if k < 2 {
k
} else {
fib_direct(k - 1).wrapping_add(fib_direct(k - 2))
}
}
type FibFn = unsafe extern "C" fn(i64) -> i64;
#[inline(never)]
extern "C" fn fib_recurse_via_ptr(k: i64) -> i64 {
if k < 2 {
k
} else {
let f: FibFn = FIB_INDIRECT;
let a = unsafe { f(k - 1) };
let b = unsafe { f(k - 2) };
a.wrapping_add(b)
}
}
static FIB_INDIRECT: FibFn = fib_recurse_via_ptr;
#[inline(never)]
fn fib_indirect(k: i64) -> i64 {
fib_recurse_via_ptr(k)
}
fn main() {
const N: i64 = 22;
const ITERS: u32 = 5_000;
for _ in 0..50 {
let _ = std::hint::black_box(fib_direct(std::hint::black_box(N)));
let _ = std::hint::black_box(fib_indirect(std::hint::black_box(N)));
}
let t0 = Instant::now();
let mut acc = 0i64;
for _ in 0..ITERS {
acc = acc.wrapping_add(fib_direct(std::hint::black_box(N)));
}
let d_direct = t0.elapsed();
std::hint::black_box(acc);
let t0 = Instant::now();
let mut acc = 0i64;
for _ in 0..ITERS {
acc = acc.wrapping_add(fib_indirect(std::hint::black_box(N)));
}
let d_indirect = t0.elapsed();
std::hint::black_box(acc);
println!(
"fib({N}) x {ITERS}: direct={:>10} ns total ({:>6.1} ns/call), \
indirect={:>10} ns total ({:>6.1} ns/call), delta/call={:>6.2} ns",
d_direct.as_nanos(),
d_direct.as_nanos() as f64 / (ITERS as f64 * fib_call_count(N) as f64),
d_indirect.as_nanos(),
d_indirect.as_nanos() as f64 / (ITERS as f64 * fib_call_count(N) as f64),
(d_indirect.as_nanos() as f64 - d_direct.as_nanos() as f64)
/ (ITERS as f64 * fib_call_count(N) as f64),
);
}
fn fib_call_count(k: i64) -> i64 {
if k < 2 {
1
} else {
fib_call_count(k - 1) + fib_call_count(k - 2) + 1
}
}