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.
nudt-compiler-cpp/test2.sh

273 lines
7.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env bash
# test2.sh - Lab2(IR生成)批量测试脚本
set -u
set -o pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
TEST_ROOT="./test_merged"
OUTPUT_DIR="./lab2_results"
COMPILER="./build/bin/compiler"
VERIFY_SCRIPT="./scripts/verify_ir.sh"
MAX_CASES=0
STOP_ON_FIRST_FAILURE=false
START_FROM=1
KEEP_OLD=true
# 时间统计相关变量
total_time_sum=0
time_cases_count=0
show_help() {
cat << 'EOF'
用法: ./test2.sh [选项]
说明:
批量执行 Lab2(IR 生成)测试。
默认会递归扫描 test/test_case 下所有 .sy 文件,
调用 scripts/verify_ir.sh 生成 IR 并运行校验。
选项:
-m, --max N 最多执行 N 个用例0 表示不限制,默认: 0
-x, --stop-on-fail 遇到第一个失败时停止
-s, --start-from N 从第 N 个测试用例开始(默认: 1
-k, --keep 保留旧的输出目录,不删除
-h, --help 显示帮助
示例:
./test2.sh
./test2.sh --max 20
./test2.sh --stop-on-fail
./test2.sh --start-from 50
./test2.sh --keep
./test2.sh --start-from 50 --keep
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
-m|--max)
MAX_CASES="$2"
shift 2
;;
-x|--stop-on-fail)
STOP_ON_FIRST_FAILURE=true
shift
;;
-s|--start-from)
START_FROM="$2"
shift 2
;;
-k|--keep)
KEEP_OLD=true
shift
;;
-h|--help)
show_help
exit 0
;;
*)
echo -e "${RED}错误: 未知选项 $1${NC}"
show_help
exit 1
;;
esac
done
if ! [[ "$START_FROM" =~ ^[0-9]+$ ]] || [[ "$START_FROM" -lt 1 ]]; then
echo -e "${RED}错误: --start-from 需要正整数${NC}"
exit 1
fi
if [[ ! -d "$TEST_ROOT" ]]; then
echo -e "${RED}错误: 测试目录不存在: $TEST_ROOT${NC}"
exit 1
fi
if [[ ! -x "$COMPILER" ]]; then
echo -e "${RED}错误: 编译器不可执行: $COMPILER${NC}"
echo -e "${YELLOW}提示: 请先构建: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j \"\$(nproc)\"${NC}"
exit 1
fi
if [[ ! -x "$VERIFY_SCRIPT" ]]; then
echo -e "${RED}错误: verify脚本不可执行: $VERIFY_SCRIPT${NC}"
exit 1
fi
if ! [[ "$MAX_CASES" =~ ^[0-9]+$ ]]; then
echo -e "${RED}错误: --max 需要非负整数${NC}"
exit 1
fi
mkdir -p "$OUTPUT_DIR"
# 删除旧的输出目录(除非指定了 --keep
if [[ "$KEEP_OLD" != "true" ]]; then
if [[ -d "$OUTPUT_DIR" ]]; then
echo "正在删除旧的输出目录..."
rm -rf "$OUTPUT_DIR"/*
echo "已删除旧的输出目录"
fi
fi
mkdir -p "$OUTPUT_DIR"
LOG_FILE="$OUTPUT_DIR/lab2_batch.log"
FAIL_FILE="$OUTPUT_DIR/failed_cases.txt"
ERROR_LOG_FILE="$OUTPUT_DIR/error_log.txt"
TIME_SUMMARY_FILE="$OUTPUT_DIR/time_summary.txt"
: > "$LOG_FILE"
: > "$FAIL_FILE"
: > "$ERROR_LOG_FILE"
: > "$TIME_SUMMARY_FILE"
echo "Lab2 批量测试日志 - $(date)" >> "$LOG_FILE"
echo "TEST_ROOT=$TEST_ROOT" >> "$LOG_FILE"
echo "OUTPUT_DIR=$OUTPUT_DIR" >> "$LOG_FILE"
echo "MAX_CASES=$MAX_CASES" >> "$LOG_FILE"
echo "================================================" >> "$LOG_FILE"
mapfile -d '' -t CASES < <(find "$TEST_ROOT" -type f -name '*.sy' -print0 | sort -z)
TOTAL_FOUND=${#CASES[@]}
if [[ $TOTAL_FOUND -eq 0 ]]; then
echo -e "${YELLOW}未找到任何 .sy 用例,请检查目录: $TEST_ROOT${NC}"
exit 0
fi
TOTAL=0
SUCCESS=0
FAILED=0
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab2 批量测试开始${NC}"
echo -e "${BLUE}测试根目录: $TEST_ROOT${NC}"
echo -e "${BLUE}找到用例数: $TOTAL_FOUND${NC}"
echo -e "${BLUE}输出目录: $OUTPUT_DIR${NC}"
if [[ "$KEEP_OLD" == "true" ]]; then
echo -e "${BLUE}模式: 保留旧输出${NC}"
else
echo -e "${BLUE}模式: 全新输出${NC}"
fi
if [[ "$START_FROM" -gt 1 ]]; then
echo -e "${BLUE}起始用例: $START_FROM${NC}"
fi
echo -e "${BLUE}========================================${NC}"
for file in "${CASES[@]}"; do
rel_path="${file#$TEST_ROOT/}"
filename="$(basename "$file")"
base_name="${filename%.sy}"
rel_dir="$(dirname "$rel_path")"
case_out_dir="$OUTPUT_DIR/$rel_dir"
TOTAL=$((TOTAL + 1))
# 跳过起始用例之前的测试
if [[ $TOTAL -lt $START_FROM ]]; then
continue
fi
# 检查是否已达到最大用例数限制(基于实际执行的用例数)
if [[ $MAX_CASES -gt 0 && $((TOTAL - START_FROM + 1)) -gt $MAX_CASES ]]; then
break
fi
mkdir -p "$case_out_dir"
# 删除已有的输出文件,确保重新生成
rm -f "$case_out_dir/$base_name.ll"
rm -f "$case_out_dir/$base_name.o"
rm -f "$case_out_dir/$base_name"
rm -f "$case_out_dir/$base_name.stdout"
rm -f "$case_out_dir/$base_name.actual.out"
rm -f "$case_out_dir/${base_name}_time.txt"
echo -ne "${YELLOW}[$TOTAL] $filename ... ${NC}"
# 调用 verify 脚本,指定输出目录为 case_out_dir
"$VERIFY_SCRIPT" "$file" "$case_out_dir" --run > /dev/null 2>&1
code=$?
# 从 case_out_dir 读取运行时间文件
time_file="$case_out_dir/${base_name}_time.txt"
run_time=""
if [[ -f "$time_file" ]]; then
run_time=$(cat "$time_file")
fi
if [[ $code -eq 0 ]]; then
SUCCESS=$((SUCCESS + 1))
# 显示运行时间
if [[ -n "$run_time" && "$run_time" =~ ^[0-9]+$ ]]; then
echo -e "${GREEN}成功${NC} (${run_time}ms)"
# 累加统计
total_time_sum=$((total_time_sum + run_time))
time_cases_count=$((time_cases_count + 1))
# 写入汇总文件
echo "$rel_path: ${run_time}ms" >> "$TIME_SUMMARY_FILE"
else
echo -e "${GREEN}成功${NC} (运行时间: N/A)"
fi
echo "[SUCCESS] $file" >> "$LOG_FILE"
else
FAILED=$((FAILED + 1))
echo "$file" >> "$FAIL_FILE"
echo -e "${RED}失败${NC}"
echo "[FAILED] $file (exit=$code)" >> "$LOG_FILE"
# 写入详细错误信息到错误日志
echo "========================================" >> "$ERROR_LOG_FILE"
echo "测试失败: $file" >> "$ERROR_LOG_FILE"
echo "退出码: $code" >> "$ERROR_LOG_FILE"
echo "时间: $(date)" >> "$ERROR_LOG_FILE"
echo "========================================" >> "$ERROR_LOG_FILE"
if [[ "$STOP_ON_FIRST_FAILURE" = true ]]; then
echo -e "${RED}========================================${NC}"
echo -e "${RED}在第一个失败处停止测试${NC}"
echo -e "${RED}失败文件: $file${NC}"
echo -e "${RED}日志: $LOG_FILE${NC}"
echo -e "${RED}错误日志: $ERROR_LOG_FILE${NC}"
echo -e "${RED}========================================${NC}"
break
fi
fi
done
RATE="0.00"
if [[ $TOTAL -gt 0 ]]; then
RATE=$(awk -v s="$SUCCESS" -v t="$TOTAL" 'BEGIN { printf "%.2f", (s*100.0)/t }')
fi
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab2 批量测试完成${NC}"
echo -e "${BLUE}执行用例: $TOTAL${NC}"
echo -e "${GREEN}成功: $SUCCESS${NC}"
echo -e "${RED}失败: $FAILED${NC}"
echo -e "${BLUE}成功率: ${RATE}%${NC}"
# 显示平均运行时间
if [[ $time_cases_count -gt 0 ]]; then
avg_time=$((total_time_sum / time_cases_count))
echo -e "${BLUE}平均运行时间: ${avg_time}ms (基于 ${time_cases_count} 个成功用例)${NC}"
echo -e "${BLUE}时间汇总: $TIME_SUMMARY_FILE${NC}"
fi
echo -e "${BLUE}日志: $LOG_FILE${NC}"
if [[ $FAILED -gt 0 ]]; then
echo -e "${RED}失败清单: $FAIL_FILE${NC}"
echo -e "${RED}错误日志: $ERROR_LOG_FILE${NC}"
fi
echo -e "${BLUE}========================================${NC}"
exit 0