2025-11-10 19:42:42 +09:00
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
|
|
# Record baseline timings for C and Python (and Hakorune VM/AOT) into benchmarks/baselines/.
|
|
|
|
|
|
# Usage: record_baselines.sh <bench_key|all> [warmup=2] [repeat=7]
|
|
|
|
|
|
# Env:
|
|
|
|
|
|
# PERF_SUBTRACT_STARTUP=1 subtract minimal startup baseline (ret0) for VM/AOT
|
|
|
|
|
|
# NYASH_LLVM_BACKEND=crate|native select LLVM builder backend for AOT (default auto)
|
|
|
|
|
|
# bench_key: box_create_destroy_small | method_call_only_small | all
|
|
|
|
|
|
|
|
|
|
|
|
ROOT_DIR=$(cd "$(dirname "$0")/../.." && pwd)
|
|
|
|
|
|
TARGET_DIR="${ROOT_DIR}/target"
|
|
|
|
|
|
OUT_DIR="${ROOT_DIR}/benchmarks/baselines"
|
|
|
|
|
|
PY_DIR="${ROOT_DIR}/benchmarks/python"
|
|
|
|
|
|
C_DIR="${ROOT_DIR}/benchmarks/c"
|
|
|
|
|
|
|
|
|
|
|
|
KEY=${1:-all}
|
|
|
|
|
|
WARMUP=${2:-2}
|
|
|
|
|
|
REPEAT=${3:-7}
|
|
|
|
|
|
|
|
|
|
|
|
mkdir -p "${OUT_DIR}"
|
|
|
|
|
|
|
|
|
|
|
|
time_ms() { date +%s%3N; }
|
|
|
|
|
|
measure_cmd_ms() { local t1 t2; t1=$(time_ms); "$@" >/dev/null 2>&1 || true; t2=$(time_ms); echo $((t2-t1)); }
|
|
|
|
|
|
median_ms() { awk 'NF{print $1}' | sort -n | awk '{a[NR]=$1} END{ if(NR==0){print 0; exit} n=int((NR+1)/2); print a[n] }'; }
|
|
|
|
|
|
|
|
|
|
|
|
collect_series() {
|
|
|
|
|
|
local warmup=$1; shift
|
|
|
|
|
|
local repeat=$1; shift
|
|
|
|
|
|
local -a cmd=("$@")
|
|
|
|
|
|
for _ in $(seq 1 "${warmup}"); do measure_cmd_ms "${cmd[@]}" >/dev/null || true; done
|
|
|
|
|
|
for _ in $(seq 1 "${repeat}"); do measure_cmd_ms "${cmd[@]}"; done
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ensure_c_built() {
|
|
|
|
|
|
local key=$1
|
|
|
|
|
|
local c_src="${C_DIR}/bench_${key}.c"
|
|
|
|
|
|
local c_bin="${TARGET_DIR}/perf_c_${key}"
|
|
|
|
|
|
if [[ ! -f "${c_src}" ]]; then echo "[error] missing ${c_src}" >&2; return 1; fi
|
|
|
|
|
|
mkdir -p "${TARGET_DIR}"
|
|
|
|
|
|
cc -O3 -march=native -mtune=native -o "${c_bin}" "${c_src}" 2>/dev/null || cc -O3 -o "${c_bin}" "${c_src}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
record_one() {
|
|
|
|
|
|
local key=$1
|
|
|
|
|
|
local ts host c_ms py_ms ny_vm_ms ny_aot_ms
|
|
|
|
|
|
|
|
|
|
|
|
# C
|
|
|
|
|
|
ensure_c_built "${key}"
|
|
|
|
|
|
local c_bin="${TARGET_DIR}/perf_c_${key}"
|
|
|
|
|
|
local c_series; c_series=$(collect_series "${WARMUP}" "${REPEAT}" "${c_bin}")
|
|
|
|
|
|
c_ms=$(printf "%s\n" "${c_series}" | median_ms)
|
|
|
|
|
|
|
|
|
|
|
|
# Python
|
|
|
|
|
|
local py_file="${PY_DIR}/bench_${key}.py"
|
|
|
|
|
|
if command -v python3 >/dev/null 2>&1 && [[ -f "${py_file}" ]]; then
|
|
|
|
|
|
local py_series; py_series=$(collect_series "${WARMUP}" "${REPEAT}" python3 "${py_file}")
|
|
|
|
|
|
py_ms=$(printf "%s\n" "${py_series}" | median_ms)
|
|
|
|
|
|
else
|
|
|
|
|
|
py_ms=0
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Hakorune VM (optional)
|
|
|
|
|
|
local hako_bin="${TARGET_DIR}/release/hakorune"
|
|
|
|
|
|
local hako_prog="${ROOT_DIR}/benchmarks/bench_${key}.hako"
|
|
|
|
|
|
if [[ -x "${hako_bin}" && -f "${hako_prog}" ]]; then
|
2025-12-02 12:38:01 +09:00
|
|
|
|
local -a HAKO_ENV=(NYASH_FEATURES=stage3 NYASH_FEATURES=stage3 NYASH_PARSER_ALLOW_SEMICOLON=1)
|
2025-11-10 19:42:42 +09:00
|
|
|
|
local hako_series; hako_series=$(collect_series "${WARMUP}" "${REPEAT}" env "${HAKO_ENV[@]}" timeout 20s "${hako_bin}" --backend vm "${hako_prog}")
|
|
|
|
|
|
ny_vm_ms=$(printf "%s\n" "${hako_series}" | median_ms)
|
|
|
|
|
|
# Optional subtract: measure minimal VM startup (ret0)
|
|
|
|
|
|
if [[ "${PERF_SUBTRACT_STARTUP:-0}" == "1" ]]; then
|
|
|
|
|
|
local tmp_ret0="$(mktemp --suffix .hako)"; cat >"${tmp_ret0}" <<'HAKO'
|
|
|
|
|
|
static box Main { main() { return 0 } }
|
|
|
|
|
|
HAKO
|
|
|
|
|
|
local base_series; base_series=$(collect_series 1 3 env "${HAKO_ENV[@]}" timeout 20s "${hako_bin}" --backend vm "${tmp_ret0}")
|
|
|
|
|
|
local base_ms; base_ms=$(printf "%s\n" "${base_series}" | median_ms)
|
|
|
|
|
|
rm -f "${tmp_ret0}" || true
|
|
|
|
|
|
if [[ "${base_ms}" =~ ^[0-9]+$ ]]; then
|
|
|
|
|
|
ny_vm_ms=$(( ny_vm_ms>base_ms ? ny_vm_ms-base_ms : 0 ))
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
else
|
|
|
|
|
|
ny_vm_ms=0
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# AOT (crate/native backend)
|
|
|
|
|
|
ny_aot_ms=0
|
|
|
|
|
|
if [[ -x "${hako_bin}" && -f "${hako_prog}" ]]; then
|
|
|
|
|
|
# 1) Emit MIR JSON (prefer robust Rust CLI; fallback to Stage‑B wrapper)
|
|
|
|
|
|
local tmp_json; tmp_json=$(mktemp --suffix .json)
|
|
|
|
|
|
if "${hako_bin}" --emit-mir-json "${tmp_json}" "${hako_prog}" >/dev/null 2>&1 || \
|
|
|
|
|
|
bash "${ROOT_DIR}/tools/hakorune_emit_mir.sh" "${hako_prog}" "${tmp_json}" >/dev/null 2>&1; then
|
|
|
|
|
|
# 2) Build EXE via ny_mir_builder (default backend auto/crate/native)
|
|
|
|
|
|
local exe_path="${TARGET_DIR}/perf_ny_${key}.exe"
|
|
|
|
|
|
if bash "${ROOT_DIR}/tools/ny_mir_builder.sh" --in "${tmp_json}" --emit exe -o "${exe_path}" --quiet >/dev/null 2>&1; then
|
|
|
|
|
|
# 3) Measure run time of EXE
|
|
|
|
|
|
local exe_series; exe_series=$(collect_series "${WARMUP}" "${REPEAT}" timeout 20s "${exe_path}")
|
|
|
|
|
|
ny_aot_ms=$(printf "%s\n" "${exe_series}" | median_ms)
|
|
|
|
|
|
# Optional subtract: minimal AOT startup (ret0)
|
|
|
|
|
|
if [[ "${PERF_SUBTRACT_STARTUP:-0}" == "1" ]]; then
|
|
|
|
|
|
# Build ret0 EXE
|
|
|
|
|
|
local tmp_ret0_hako tmp_ret0_json ret0_exe
|
|
|
|
|
|
tmp_ret0_hako=$(mktemp --suffix .hako); cat >"${tmp_ret0_hako}" <<'HAKO'
|
|
|
|
|
|
static box Main { main() { return 0 } }
|
|
|
|
|
|
HAKO
|
|
|
|
|
|
tmp_ret0_json=$(mktemp --suffix .json)
|
|
|
|
|
|
ret0_exe="${TARGET_DIR}/perf_ny_ret0.exe"
|
|
|
|
|
|
if bash "${ROOT_DIR}/tools/hakorune_emit_mir.sh" "${tmp_ret0_hako}" "${tmp_ret0_json}" >/dev/null 2>&1 \
|
|
|
|
|
|
&& bash "${ROOT_DIR}/tools/ny_mir_builder.sh" --in "${tmp_ret0_json}" --emit exe -o "${ret0_exe}" --quiet >/dev/null 2>&1; then
|
|
|
|
|
|
local base_series; base_series=$(collect_series 1 3 timeout 20s "${ret0_exe}")
|
|
|
|
|
|
local base_ms; base_ms=$(printf "%s\n" "${base_series}" | median_ms)
|
|
|
|
|
|
if [[ "${base_ms}" =~ ^[0-9]+$ ]]; then
|
|
|
|
|
|
ny_aot_ms=$(( ny_aot_ms>base_ms ? ny_aot_ms-base_ms : 0 ))
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
rm -f "${tmp_ret0_hako}" "${tmp_ret0_json}" || true
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
rm -f "${tmp_json}" || true
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
ts=$(date -Is)
|
|
|
|
|
|
host=$(hostname 2>/dev/null || echo unknown)
|
|
|
|
|
|
|
|
|
|
|
|
local obj; obj=$(cat <<JSON
|
|
|
|
|
|
{
|
|
|
|
|
|
"bench": "${key}",
|
|
|
|
|
|
"ts": "${ts}",
|
|
|
|
|
|
"host": "${host}",
|
|
|
|
|
|
"unit": "ms",
|
|
|
|
|
|
"warmup": ${WARMUP},
|
|
|
|
|
|
"repeat": ${REPEAT},
|
|
|
|
|
|
"c_ms": ${c_ms},
|
|
|
|
|
|
"py_ms": ${py_ms},
|
|
|
|
|
|
"ny_vm_ms": ${ny_vm_ms},
|
|
|
|
|
|
"ny_aot_ms": ${ny_aot_ms}
|
|
|
|
|
|
}
|
|
|
|
|
|
JSON
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
printf "%s\n" "${obj}" > "${OUT_DIR}/${key}.latest.json"
|
|
|
|
|
|
printf "%s\n" "${obj}" >> "${OUT_DIR}/${key}.ndjson"
|
|
|
|
|
|
echo "[saved] ${OUT_DIR}/${key}.latest.json"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
run_keys=("${KEY}")
|
|
|
|
|
|
if [[ "${KEY}" == "all" ]]; then
|
|
|
|
|
|
run_keys=(box_create_destroy_small method_call_only_small)
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
for k in "${run_keys[@]}"; do
|
|
|
|
|
|
record_one "${k}"
|
|
|
|
|
|
done
|