lumbda/friction.sh
russell@unturf.com 73440106c3 Add friction.sh benchmark: C is 3-6x faster than Python impl
fib(35):     C 0.1ms vs Python 0.6ms (6x)
fib-rec(20): C 44ms vs Python 283ms (6.4x)
ack(3,4):    C 31ms vs Python 93ms (3x)
sum-to(50k): C 129ms vs Python 515ms (4x)

Both still ~20-30x slower than native CPython (interpreter overhead).
SBCL would be within 2-5x of C with native compilation.
2026-04-14 15:11:43 -04:00

127 lines
5.2 KiB
Bash

#!/bin/bash
# friction.sh — Head-to-head benchmark: CPython vs uncommonlisp-Python vs uncommonlisp-C
#
# Usage: bash friction.sh
set -e
cd "$(dirname "$0")"
echo "═══════════════════════════════════════════════════════════════"
echo "Friction Benchmark: CPython vs uncommonlisp-Python vs uncommonlisp-C"
echo "═══════════════════════════════════════════════════════════════"
echo
# Build C version
make -C c all -s 2>/dev/null
# ── fib(35) iterative ──────────────────────────────────────────
echo ">>> fib(35) iterative"
printf " CPython: "
python3 -c "
import time
def fib(n):
a, b = 0, 1
for _ in range(n): a, b = b, a+b
return a
t=time.perf_counter(); r=fib(35); print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-Python: "
python3 -c "
import time; from uncommonlisp import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1)))))')]
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(fib 35)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-C: "
/usr/bin/time -f "%e s" ./c/uncommonlisp -e '(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1))))) (display (fib 35)) (newline)' 2>&1
echo
# ── fib(20) tree-recursive ──────────────────────────────────────
echo ">>> fib(20) tree-recursive"
printf " CPython: "
python3 -c "
import time
def fib(n):
if n <= 1: return n
return fib(n-1) + fib(n-2)
t=time.perf_counter(); r=fib(20); print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-Python: "
python3 -c "
import time,sys; sys.setrecursionlimit(50000); from uncommonlisp import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2)))))')]
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(fib 20)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-C: "
/usr/bin/time -f "%e s" ./c/uncommonlisp -e '(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2))))) (display (fib 20)) (newline)' 2>&1
echo
# ── ackermann(3,4) ──────────────────────────────────────────────
echo ">>> ackermann(3,4)"
printf " CPython: "
python3 -c "
import time,sys; sys.setrecursionlimit(50000)
def ack(m,n):
if m==0: return n+1
if n==0: return ack(m-1,1)
return ack(m-1, ack(m, n-1))
t=time.perf_counter(); r=ack(3,4); print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-Python: "
python3 -c "
import time,sys; sys.setrecursionlimit(50000); from uncommonlisp import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1))))))')]
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(ack 3 4)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-C: "
/usr/bin/time -f "%e s" ./c/uncommonlisp -e '(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1)))))) (display (ack 3 4)) (newline)' 2>&1
echo
# ── sum-to(50000) tail-recursive ────────────────────────────────
echo ">>> sum-to(50000) tail-recursive"
printf " CPython: "
python3 -c "
import time
def s(n):
acc=0
while n>0: acc+=n; n-=1
return acc
t=time.perf_counter(); r=s(50000); print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-Python: "
python3 -c "
import time; from uncommonlisp import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (sum-to n) (let loop ((i n) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i)))))')]
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(sum-to 50000)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-C: "
/usr/bin/time -f "%e s" ./c/uncommonlisp -e '(define (sum-to n) (let loop ((i n) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i))))) (display (sum-to 50000)) (newline)' 2>&1
echo
echo "═══════════════════════════════════════════════════════════════"