#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" BIN="$ROOT/target/release/hakorune" usage() { echo "Usage: $0 --case {loop|strlen|box} [--n N] [--runs R] [--backend {llvm|vm}] [--exe]"; } CASE="loop"; N=5000000; RUNS=5; BACKEND="llvm"; EXE_MODE=0 while [[ $# -gt 0 ]]; do case "$1" in --case) CASE="$2"; shift 2;; --n) N="$2"; shift 2;; --runs) RUNS="$2"; shift 2;; --backend) BACKEND="$2"; shift 2;; --exe) EXE_MODE=1; shift 1;; --help|-h) usage; exit 0;; *) echo "Unknown arg: $1"; usage; exit 2;; esac done if [[ ! -x "$BIN" ]]; then echo "[FAIL] hakorune not built: $BIN" >&2; exit 2; fi bench_hako() { local file="$1"; local backend="$2"; shift 2 local start end start=$(date +%s%N) if [[ "$backend" = "llvm" ]]; then # Ensure ny-llvmc exists; build if missing if [[ ! -x "$ROOT/target/release/ny-llvmc" ]]; then (cargo build -q --release -p nyash-llvm-compiler >/dev/null 2>&1) || true fi PYTHONPATH="${PYTHONPATH:-$ROOT}" \ NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}" \ NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}" \ NYASH_LLVM_USE_HARNESS=1 "$BIN" --backend llvm "$file" >/dev/null 2>&1 else "$BIN" --backend vm "$file" >/dev/null 2>&1 fi end=$(date +%s%N) echo $(( (end - start)/1000000 )) } bench_c() { local csrc="$1"; local exe="$2" cc -O3 -march=native -o "$exe" "$csrc" local start end start=$(date +%s%N) "$exe" >/dev/null 2>&1 end=$(date +%s%N) echo $(( (end - start)/1000000 )) } # Build once and time executable runs (ms) time_exe_run() { local exe="$1" local start end start=$(date +%s%N) "$exe" >/dev/null 2>&1 end=$(date +%s%N) echo $(( (end - start)/1000000 )) } mktemp_hako() { mktemp --suffix .hako; } mktemp_c() { mktemp --suffix .c; } case "$CASE" in loop) HAKO_FILE=$(mktemp_hako) cat >"$HAKO_FILE" <"$C_FILE" <<'C' #include int main(){ volatile int64_t n = N_PLACEHOLDER; volatile int64_t s=0; for (int64_t i=0;i"$HAKO_FILE" <"$C_FILE" <<'C' #include #include int main(){ volatile int64_t n = N_PLACEHOLDER; volatile int64_t s=0; const char* t = "abcdefghijklmnopqrstuvwxyz"; for (int64_t i=0;i"$HAKO_FILE" <"$C_FILE" <<'C' #include #include #include typedef struct { char* p; } Str; static inline Str* new_str(){ Str* s=(Str*)malloc(sizeof(Str)); s->p=strdup("x"); free(s->p); free(s); return s; } int main(){ volatile int64_t n=N_PLACEHOLDER; for(int64_t i=0;i&2 sum_c=0; sum_h=0 if [[ "$EXE_MODE" = "1" ]]; then # Build C exe once C_EXE=$(mktemp --suffix .out) cc -O3 -march=native -o "$C_EXE" "$C_FILE" # Build Nyash exe once (requires llvm harness) if [[ "$BACKEND" != "llvm" ]]; then echo "[FAIL] --exe requires --backend llvm" >&2; exit 2 fi if [[ ! -x "$ROOT/target/release/ny-llvmc" ]]; then (cargo build -q --release -p nyash-llvm-compiler >/dev/null 2>&1) || true fi HAKO_EXE=$(mktemp --suffix .out) TMP_JSON=$(mktemp --suffix .json) if ! HAKO_SELFHOST_BUILDER_FIRST=1 HAKO_MIR_BUILDER_LOOP_JSONFRAG=1 HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 \ NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ NYASH_JSON_ONLY=1 bash "$ROOT/tools/hakorune_emit_mir.sh" "$HAKO_FILE" "$TMP_JSON" >/dev/null 2>&1; then echo "[FAIL] failed to emit MIR JSON" >&2; exit 3 fi # Ensure runtime lib exists (nyash_kernel) (cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true # Build EXE via helper (selects crate backend ny-llvmc under the hood) if ! NYASH_LLVM_BACKEND=crate \ NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}" \ NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}" \ NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 NYASH_LLVM_FAST=1 \ bash "$ROOT/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$HAKO_EXE" --quiet >/dev/null 2>&1; then echo "[FAIL] failed to build Nyash EXE" >&2; exit 3 fi for i in $(seq 1 "$RUNS"); do t_c=$(time_exe_run "$C_EXE") t_h=$(time_exe_run "$HAKO_EXE") sum_c=$((sum_c + t_c)); sum_h=$((sum_h + t_h)) if command -v python3 >/dev/null 2>&1; then ratio=$(python3 -c "print(round(${t_h}/max(${t_c},1)*100,2))" 2>/dev/null || echo NA) else ratio=NA fi echo "run#$i c=${t_c}ms hak=${t_h}ms ratio=${ratio}%" >&2 done avg_c=$((sum_c / RUNS)); avg_h=$((sum_h / RUNS)) echo "avg c=${avg_c}ms hak=${avg_h}ms" >&2 if command -v python3 >/dev/null 2>&1; then python3 - </dev/null || true else for i in $(seq 1 "$RUNS"); do t_c=$(bench_c "$C_FILE" "${C_FILE%.c}") t_h=$(bench_hako "$HAKO_FILE" "$BACKEND") sum_c=$((sum_c + t_c)); sum_h=$((sum_h + t_h)) if command -v python3 >/dev/null 2>&1; then ratio=$(python3 -c "print(round(${t_h}/max(${t_c},1)*100,2))" 2>/dev/null || echo NA) else ratio=NA fi echo "run#$i c=${t_c}ms hak=${t_h}ms ratio=${ratio}%" >&2 done avg_c=$((sum_c / RUNS)); avg_h=$((sum_h / RUNS)) echo "avg c=${avg_c}ms hak=${avg_h}ms" >&2 if command -v python3 >/dev/null 2>&1; then python3 - </dev/null || true