You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
5.9 KiB

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
BUILD_DIR="$ROOT_DIR/build"
ANTLR_DIR="$BUILD_DIR/generated/antlr4"
JAR_PATH="$ROOT_DIR/third_party/antlr-4.13.2-complete.jar"
GRAMMAR_PATH="$ROOT_DIR/src/antlr4/SysY.g4"
OUT_ROOT="$ROOT_DIR/test/test_result/lab3_asm_batch"
TIME_LOG_FILE=""
RUN_FUNCTIONAL=true
RUN_PERFORMANCE=true
RUN_EXEC=true
DO_BUILD=true
RUN_TIMEOUT=""
functional_total=0
functional_passed=0
functional_failed=0
performance_total=0
performance_passed=0
performance_failed=0
failed_cases=()
usage() {
cat <<'EOF'
Usage: ./solution/run_lab3_batch.sh [options]
Options:
--no-build Skip ANTLR generation and project rebuild
--functional-only Run only test/test_case/functional/*.sy
--performance-only Run only test/test_case/performance/*.sy
--no-run Generate/link asm only, skip qemu run and output check
--emit-only Generate/link asm only, skip qemu run and output check
--timeout <sec> Apply per-case timeout via the `timeout` command
--output-dir <dir> Set output directory for generated asm, executables, and logs
--help Show this help message
EOF
}
print_summary() {
local total passed failed
total=$((functional_total + performance_total))
passed=$((functional_passed + performance_passed))
failed=$((functional_failed + performance_failed))
echo
echo "Summary:"
echo " Mode: $([[ "$RUN_EXEC" == true ]] && echo "verify_asm --run" || echo "verify_asm")"
echo " Functional cases: total=$functional_total, passed=$functional_passed, failed=$functional_failed"
echo " Performance cases: total=$performance_total, passed=$performance_passed, failed=$performance_failed"
echo " Overall: total=$total, passed=$passed, failed=$failed"
if (( ${#failed_cases[@]} > 0 )); then
echo "Failed cases:"
printf ' - %s\n' "${failed_cases[@]}"
fi
echo " Per-case timing log: $TIME_LOG_FILE"
}
format_elapsed_seconds() {
local elapsed_ns=$1
awk -v ns="$elapsed_ns" 'BEGIN { printf "%.3f", ns / 1000000000 }'
}
run_case() {
local case_file=$1
local group=$2
local stem out_dir log_file
local start_ns end_ns elapsed_ns elapsed_s
local -a cmd
stem="$(basename "${case_file%.sy}")"
out_dir="$OUT_ROOT/$group"
log_file="$out_dir/$stem.verify.log"
mkdir -p "$out_dir"
if [[ "$group" == "functional" ]]; then
((functional_total += 1))
else
((performance_total += 1))
fi
cmd=(./scripts/verify_asm.sh "$case_file" "$out_dir")
if [[ "$RUN_EXEC" == true ]]; then
cmd+=(--run)
fi
if [[ -n "$RUN_TIMEOUT" ]]; then
cmd=(timeout "$RUN_TIMEOUT" "${cmd[@]}")
fi
start_ns=$(date +%s%N)
if "${cmd[@]}" >"$log_file" 2>&1; then
end_ns=$(date +%s%N)
elapsed_ns=$((end_ns - start_ns))
elapsed_s=$(format_elapsed_seconds "$elapsed_ns")
echo "PASS [asm] $case_file (${elapsed_s}s)"
if [[ "$group" == "functional" ]]; then
((functional_passed += 1))
else
((performance_passed += 1))
fi
printf '%s,%s,%s,%s,%s,%s\n' \
"$group" "$case_file" "PASS" "$elapsed_ns" "$elapsed_s" "$log_file" >> "$TIME_LOG_FILE"
else
end_ns=$(date +%s%N)
elapsed_ns=$((end_ns - start_ns))
elapsed_s=$(format_elapsed_seconds "$elapsed_ns")
echo "FAIL [asm] $case_file (${elapsed_s}s)"
cat "$log_file"
if [[ "$group" == "functional" ]]; then
((functional_failed += 1))
else
((performance_failed += 1))
fi
failed_cases+=("$case_file")
printf '%s,%s,%s,%s,%s,%s\n' \
"$group" "$case_file" "FAIL" "$elapsed_ns" "$elapsed_s" "$log_file" >> "$TIME_LOG_FILE"
fi
}
while [[ $# -gt 0 ]]; do
case "$1" in
--no-build)
DO_BUILD=false
;;
--functional-only)
RUN_FUNCTIONAL=true
RUN_PERFORMANCE=false
;;
--performance-only)
RUN_FUNCTIONAL=false
RUN_PERFORMANCE=true
;;
--emit-only)
RUN_EXEC=false
;;
--no-run)
RUN_EXEC=false
;;
--timeout)
shift
if [[ $# -eq 0 ]]; then
echo "Missing value for --timeout" >&2
usage
exit 1
fi
RUN_TIMEOUT="$1"
;;
--output-dir)
shift
if [[ $# -eq 0 ]]; then
echo "Missing value for --output-dir" >&2
usage
exit 1
fi
if [[ "$1" = /* ]]; then
OUT_ROOT="$1"
else
OUT_ROOT="$ROOT_DIR/$1"
fi
;;
--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage
exit 1
;;
esac
shift
done
if [[ "$RUN_FUNCTIONAL" == false && "$RUN_PERFORMANCE" == false ]]; then
echo "No test set selected." >&2
exit 1
fi
if [[ -n "$RUN_TIMEOUT" ]] && ! command -v timeout >/dev/null 2>&1; then
echo "未找到 timeout 命令,无法使用 --timeout。" >&2
exit 1
fi
mkdir -p "$OUT_ROOT"
TIME_LOG_FILE="$OUT_ROOT/case_timing.csv"
echo "group,case,status,elapsed_ns,elapsed_s,log_file" > "$TIME_LOG_FILE"
cd "$ROOT_DIR"
if [[ "$DO_BUILD" == true ]]; then
echo "[1/4] Generating ANTLR sources..."
mkdir -p "$ANTLR_DIR"
java -jar "$JAR_PATH" \
-Dlanguage=Cpp \
-visitor -no-listener \
-Xexact-output-dir \
-o "$ANTLR_DIR" \
"$GRAMMAR_PATH"
echo "[2/4] Configuring CMake..."
cmake -S "$ROOT_DIR" -B "$BUILD_DIR" -DCMAKE_BUILD_TYPE=Release -DCOMPILER_PARSE_ONLY=OFF
echo "[3/4] Building project..."
cmake --build "$BUILD_DIR" -j "$(nproc)"
fi
echo "[4/4] Running ASM batch tests..."
if [[ "$RUN_FUNCTIONAL" == true ]]; then
while IFS= read -r case_file; do
run_case "$case_file" "functional"
done < <(find "$ROOT_DIR/test/test_case/functional" -maxdepth 1 -name '*.sy' | sort)
fi
if [[ "$RUN_PERFORMANCE" == true ]]; then
while IFS= read -r case_file; do
run_case "$case_file" "performance"
done < <(find "$ROOT_DIR/test/test_case/performance" -maxdepth 1 -name '*.sy' | sort)
fi
print_summary
if (( functional_failed + performance_failed > 0 )); then
echo "Batch test finished with failures."
exit 1
fi
echo "Batch test passed."