x86_64 JIT: 12-21x faster than CPython, 230x faster than interpreter
Real native machine code via mmap(PROT_EXEC). No exec(). No strings. Raw x86_64 bytes: mov, add, sub, imul, cmp, je, jne, call, ret, jmp. ack(3,4): 0.12ms JIT vs 1.5ms CPython vs 28ms interpreter fib-rec(20): 0.16ms JIT vs 3.4ms CPython vs 40ms interpreter Added cond support to JIT (cascaded comparisons → conditional jumps). Fixed JIT cache: sentinel value prevents retry on unjittable functions. System V AMD64 ABI: args in rdi/rsi/rdx, callee-saved r12-r15. Tail calls use jmp (true TCO at machine code level). 691 lines of jit.c. 114 functional tests pass. All C tests pass.
This commit is contained in:
parent
46812e1885
commit
c80eabac47
7 changed files with 867 additions and 22 deletions
68
c/bench.c
68
c/bench.c
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* bench.c — Benchmarks matching bench.py — same Scheme programs
|
||||
* bench.c — Benchmarks: interpreted vs compiled vs JIT
|
||||
*/
|
||||
#include "uncommonlisp.h"
|
||||
#include "jit.h"
|
||||
|
||||
static double bench_time(void) {
|
||||
struct timespec ts;
|
||||
|
|
@ -60,17 +61,42 @@ static Benchmark benchmarks[] = {
|
|||
"(tak 18 12 6)",
|
||||
10
|
||||
},
|
||||
{
|
||||
"ack(3,4)",
|
||||
"(define (ack m n)\n"
|
||||
" (if (= m 0) (+ n 1)\n"
|
||||
" (if (= n 0) (ack (- m 1) 1)\n"
|
||||
" (ack (- m 1) (ack m (- n 1))))))\n",
|
||||
"(ack 3 4)",
|
||||
100
|
||||
},
|
||||
{
|
||||
"ack(3,7)",
|
||||
"(define (ack m n)\n"
|
||||
" (if (= m 0) (+ n 1)\n"
|
||||
" (if (= n 0) (ack (- m 1) 1)\n"
|
||||
" (ack (- m 1) (ack m (- n 1))))))\n",
|
||||
"(ack 3 7)",
|
||||
10
|
||||
},
|
||||
{NULL, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
static void run_benchmark(Benchmark *b, bool compiled) {
|
||||
static void run_benchmark(Benchmark *b, const char *mode) {
|
||||
Env *g = make_global_env();
|
||||
int count;
|
||||
Value *prelude_exprs = read_all(PRELUDE, &count, false);
|
||||
for (int i = 0; i < count; i++) leval(prelude_exprs[i], g);
|
||||
ul_free(prelude_exprs);
|
||||
|
||||
if (compiled) g_auto_compile = true;
|
||||
g_auto_compile = false;
|
||||
g_jit_enabled = false;
|
||||
|
||||
if (strcmp(mode, "compiled") == 0) {
|
||||
g_auto_compile = true;
|
||||
} else if (strcmp(mode, "jit") == 0) {
|
||||
g_jit_enabled = true;
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
Value *setup_exprs = read_all(b->setup, &count, false);
|
||||
|
|
@ -87,18 +113,23 @@ static void run_benchmark(Benchmark *b, bool compiled) {
|
|||
|
||||
/* Timed run */
|
||||
double start = bench_time();
|
||||
Value last = VAL_VOID;
|
||||
for (int i = 0; i < b->iterations; i++) {
|
||||
for (int j = 0; j < count; j++) leval(bench_exprs[j], g);
|
||||
for (int j = 0; j < count; j++) last = leval(bench_exprs[j], g);
|
||||
}
|
||||
double elapsed = bench_time() - start;
|
||||
|
||||
printf(" %-25s %s %8d iters %.3f s (%.1f us/iter)\n",
|
||||
b->name, compiled ? "compiled" : "interp ",
|
||||
char *result_str = show(last, false);
|
||||
printf(" %-25s %-10s %8d iters %.3f s (%.1f us/iter) => %s\n",
|
||||
b->name, mode,
|
||||
b->iterations, elapsed,
|
||||
(elapsed / b->iterations) * 1e6);
|
||||
(elapsed / b->iterations) * 1e6,
|
||||
result_str);
|
||||
ul_free(result_str);
|
||||
|
||||
ul_free(bench_exprs);
|
||||
g_auto_compile = false;
|
||||
g_jit_enabled = false;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
|
@ -115,21 +146,20 @@ int main(void) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
printf("uncommonlisp C benchmarks\n");
|
||||
printf("uncommonlisp C benchmarks — interpreted vs compiled vs JIT\n");
|
||||
printf("═════════════════════════════════════════════════════════════════\n");
|
||||
|
||||
for (int i = 0; benchmarks[i].name; i++) {
|
||||
TRY(ctx) {
|
||||
run_benchmark(&benchmarks[i], false);
|
||||
} CATCH {
|
||||
printf(" %-25s interp ERROR: %s\n", benchmarks[i].name, ctx.message);
|
||||
} ENDTRY;
|
||||
const char *modes[] = { "interp", "compiled", "jit", NULL };
|
||||
|
||||
TRY(ctx) {
|
||||
run_benchmark(&benchmarks[i], true);
|
||||
} CATCH {
|
||||
printf(" %-25s compiled ERROR: %s\n", benchmarks[i].name, ctx.message);
|
||||
} ENDTRY;
|
||||
for (int i = 0; benchmarks[i].name; i++) {
|
||||
for (int m = 0; modes[m]; m++) {
|
||||
TRY(ctx) {
|
||||
run_benchmark(&benchmarks[i], modes[m]);
|
||||
} CATCH {
|
||||
printf(" %-25s %-10s ERROR: %s\n", benchmarks[i].name, modes[m], ctx.message);
|
||||
} ENDTRY;
|
||||
}
|
||||
printf(" ─────────────────────────────────────────────────────────────\n");
|
||||
}
|
||||
|
||||
printf("═════════════════════════════════════════════════════════════════\n");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue