#!/bin/bash # larson.sh - Unified Larson benchmark runner # Purpose: "1コマンドで正しい環境・同条件比較・結果保存"を保証 # # Usage: # scripts/larson.sh [options] [duration] [threads] # # Commands: # build - Build all targets (hakmem/mi/sys) # hakmem - Run HAKMEM only # mi - Run mimalloc only # sys - Run system malloc only # battle - Compare all 3 (hakmem vs mimalloc vs system) # asan - Run with AddressSanitizer # ubsan - Run with UBSan # tsan - Run with ThreadSanitizer # guard - Run with full safety checks (guard profile) # debug - Run with debug ring (debug profile) # # Options: # --profile - Load profile from scripts/profiles/.env # # Examples: # scripts/larson.sh hakmem --profile tinyhot_tput 2 4 # scripts/larson.sh battle 2 4 # scripts/larson.sh guard 2 4 set -e # ============================================================================ # Configuration # ============================================================================ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" PROFILES_DIR="$SCRIPT_DIR/profiles" RESULTS_DIR="$PROJECT_ROOT/benchmarks/results" # Default Larson parameters (fixed for consistency) DEFAULT_PARAMS="8 128 1024 1 12345" # ============================================================================ # Helper Functions # ============================================================================ usage() { cat < [options] [duration] [threads] Commands: build Build all targets (hakmem/mi/sys) hakmem Run HAKMEM only mi Run mimalloc only sys Run system malloc only battle Compare all 3 (hakmem vs mimalloc vs system) asan Run with AddressSanitizer ubsan Run with UBSan tsan Run with ThreadSanitizer guard Run with full safety checks debug Run with debug ring Options: --profile Load profile from scripts/profiles/.env Examples: $0 hakmem --profile tinyhot_tput 2 4 $0 battle 2 4 $0 guard 2 4 EOF exit 1 } log() { echo "[larson.sh] $*" >&2 } error() { echo "[larson.sh ERROR] $*" >&2 exit 1 } # Load profile from scripts/profiles/*.env load_profile() { local profile_name="$1" local profile_path="$PROFILES_DIR/${profile_name}.env" if [[ ! -f "$profile_path" ]]; then error "Profile not found: $profile_path" fi log "Loading profile: $profile_name" # shellcheck disable=SC1090 source "$profile_path" } # Display current environment configuration show_env() { log "==========================================" log "Environment Configuration:" log "==========================================" log "Tiny Fast Path: ${HAKMEM_TINY_FAST_PATH:-}" # Program reads HAKMEM_TINY_USE_SUPERSLAB. Keep legacy var for backward compatibility. log "SuperSlab: ${HAKMEM_TINY_USE_SUPERSLAB:-${HAKMEM_USE_SUPERSLAB:-}}" log "SS Adopt: ${HAKMEM_TINY_SS_ADOPT:-}" log "Box Refactor: ${HAKMEM_TINY_PHASE6_BOX_REFACTOR:-}" log "Fast Cap 0: ${HAKMEM_TINY_FAST_CAP_0:-}" log "Fast Cap 1: ${HAKMEM_TINY_FAST_CAP_1:-}" log "Refill Count Hot: ${HAKMEM_TINY_REFILL_COUNT_HOT:-}" log "SLL Only: ${HAKMEM_TINY_SLL_ONLY:-}" log "TLS List Cap: ${HAKMEM_TINY_TLS_LIST_CAP:-}" log "TLS Hot Mag Cap: ${HAKMEM_TINY_TLS_HOT_MAG_CAP:-}" log "Trace Ring: ${HAKMEM_TINY_TRACE_RING:-}" log "Safe Free: ${HAKMEM_TINY_SAFE_FREE:-}" log "Remote Guard: ${HAKMEM_TINY_REMOTE_GUARD:-}" log "Debug Counters: ${HAKMEM_DEBUG_COUNTERS:-}" log "==========================================" } # Build target build_target() { local target="$1" log "Building $target..." cd "$PROJECT_ROOT" make "$target" || error "Build failed: $target" } # Run Larson benchmark run_larson() { local binary="$1" local duration="$2" local threads="$3" log "Running: $binary $duration $DEFAULT_PARAMS $threads" cd "$PROJECT_ROOT" "./$binary" "$duration" $DEFAULT_PARAMS "$threads" } # ============================================================================ # Command Handlers # ============================================================================ cmd_build() { log "Building all targets..." build_target "larson_hakmem" build_target "larson_system" # Try to build mimalloc (may not exist) if [[ -f "larson_mi.c" ]] || [[ -f "mimalloc-bench/bench/larson/larson.c" ]]; then build_target "larson_mi" || log "Warning: mimalloc build failed (skipping)" else log "Warning: mimalloc source not found (skipping)" fi } cmd_hakmem() { local duration="$1" local threads="$2" build_target "larson_hakmem" show_env run_larson "larson_hakmem" "$duration" "$threads" } cmd_mi() { local duration="$1" local threads="$2" build_target "larson_mi" run_larson "larson_mi" "$duration" "$threads" } cmd_sys() { local duration="$1" local threads="$2" build_target "larson_system" run_larson "larson_system" "$duration" "$threads" } cmd_battle() { local duration="$1" local threads="$2" local snapshot_dir="$RESULTS_DIR/snapshot_$(date +%Y%m%d_%H%M%S)" log "===========================" log "BATTLE MODE: 3-way comparison" log "===========================" mkdir -p "$snapshot_dir" # Save environment env | grep HAKMEM > "$snapshot_dir/env.txt" || true # Build all cmd_build log "Running HAKMEM..." run_larson "larson_hakmem" "$duration" "$threads" | tee "$snapshot_dir/hakmem.txt" log "Running mimalloc..." run_larson "larson_mi" "$duration" "$threads" | tee "$snapshot_dir/mimalloc.txt" || log "mimalloc skipped" log "Running system malloc..." run_larson "larson_system" "$duration" "$threads" | tee "$snapshot_dir/system.txt" log "Results saved to: $snapshot_dir" log "Summary:" grep "Throughput" "$snapshot_dir"/*.txt || true } cmd_guard() { local duration="$1" local threads="$2" load_profile "larson_guard" cmd_hakmem "$duration" "$threads" } cmd_debug() { local duration="$1" local threads="$2" load_profile "larson_debug" cmd_hakmem "$duration" "$threads" } cmd_asan() { local duration="$1" local threads="$2" build_target "larson_hakmem_asan" show_env run_larson "larson_hakmem_asan" "$duration" "$threads" } cmd_ubsan() { local duration="$1" local threads="$2" build_target "larson_hakmem_ubsan" show_env run_larson "larson_hakmem_ubsan" "$duration" "$threads" } cmd_tsan() { local duration="$1" local threads="$2" build_target "larson_hakmem_tsan" show_env run_larson "larson_hakmem_tsan" "$duration" "$threads" } # ============================================================================ # Main # ============================================================================ main() { if [[ $# -lt 1 ]]; then usage fi local command="$1" shift # Parse options local profile="" while [[ $# -gt 0 ]]; do case "$1" in --profile) profile="$2" shift 2 ;; *) break ;; esac done # Load profile if specified if [[ -n "$profile" ]]; then load_profile "$profile" fi # Get duration and threads (optional, defaults to 2 and 4) local duration="${1:-2}" local threads="${2:-4}" # Route to command handler case "$command" in build) cmd_build ;; hakmem) cmd_hakmem "$duration" "$threads" ;; mi|mimalloc) cmd_mi "$duration" "$threads" ;; sys|system) cmd_sys "$duration" "$threads" ;; battle) cmd_battle "$duration" "$threads" ;; guard) cmd_guard "$duration" "$threads" ;; debug) cmd_debug "$duration" "$threads" ;; asan) cmd_asan "$duration" "$threads" ;; ubsan) cmd_ubsan "$duration" "$threads" ;; tsan) cmd_tsan "$duration" "$threads" ;; *) error "Unknown command: $command" ;; esac } main "$@"