65e280bb70
Adds --alloc=<gc|bump> to ail build/run. Bump path links a 256MB no-free arena C stub instead of libgc; IR is byte-identical except for the @GC_malloc → @bump_malloc symbol swap. Bench harness times two allocation-heavy workloads (list cons/sum and balanced tree build/walk) under both modes. Numbers (RUNS=5, median of 4): bench_list_sum gc 0.141s bump 0.048s +194% bench_tree_walk gc 0.103s bump 0.041s +151% Bucket: large. ~60% of runtime is Boehm on these workloads — upper bound for any realistic program. Both fixtures hold the heap fully live, so the cost we're seeing is Boehm's allocate path itself, not collection work; that fact narrows the design space for the GC discussion. - crates/ailang-codegen: AllocStrategy enum, three callsites and the IR header parameterised. - crates/ail/src/main.rs: --alloc flag plumbed; bump runtime located + compiled on demand. - runtime/bump.c: 256MB static arena, abort-on-overflow. - examples/bench_list_sum, bench_tree_walk: accumulator-form fixtures (textbook recursive sum was constructor-blocked). - bench/run.sh: harness with Python timing helper (Arch's /usr/bin/time isn't part of the base install). No language-level changes; default --alloc=gc, all 141 workspace tests green, all 5 IR snapshots unchanged, 11 prior fixtures produce identical stdout. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
41 lines
1.5 KiB
C
41 lines
1.5 KiB
C
/* Bench-only bump allocator stub.
|
|
*
|
|
* Used by `ail build --alloc=bump` (Bench iter) to A/B compare AILang
|
|
* binaries against the default Boehm-GC build. The whole runtime is a
|
|
* 256 MB statically-allocated arena and a single bump pointer; there
|
|
* is no `free`, no scan, no anything. If the workload exceeds 256 MB
|
|
* we abort — this is bench code, the right response to overflow is to
|
|
* notice and pick a smaller workload.
|
|
*
|
|
* The signature mirrors `GC_malloc` from libgc: `void *bump_malloc(size_t)`.
|
|
* The codegen replaces every `call ptr @GC_malloc` with
|
|
* `call ptr @bump_malloc` when `--alloc=bump` is set, so the AILang IR
|
|
* is otherwise byte-identical between the two strategies.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define ARENA_BYTES (256ul * 1024ul * 1024ul)
|
|
|
|
static uint8_t arena[ARENA_BYTES];
|
|
static size_t cursor = 0;
|
|
|
|
void *bump_malloc(size_t n) {
|
|
/* Align bump pointer up to 8 bytes — AILang's allocations are all
|
|
* 8-byte aligned (tag + 8-byte fields, env pointers, closure pairs
|
|
* of two `ptr`s). Matches the alignment Boehm gives us. */
|
|
size_t aligned = (cursor + 7ul) & ~((size_t)7ul);
|
|
if (aligned + n > ARENA_BYTES) {
|
|
fprintf(stderr,
|
|
"bump_malloc: arena exhausted (cursor=%zu, requested=%zu, arena=%zu)\n",
|
|
aligned, n, (size_t)ARENA_BYTES);
|
|
abort();
|
|
}
|
|
void *p = (void *)(arena + aligned);
|
|
cursor = aligned + n;
|
|
return p;
|
|
}
|