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/test5.sh

425 lines
12 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.

#!/bin/bash
set -e
set -o pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
TEST_ROOT="./2026test/performance"
# TEST_ROOT="./test_merged"
# TEST_ROOT="./test_merged/functional"
# TEST_ROOT="./test_merged/hidden_functional"
# TEST_ROOT="./test_merged/h_performance"
# TEST_ROOT="./test_merged/performance"
# TEST_ROOT="./test_merged/final_performance"
OUTPUT_DIR="./lab5_results"
COMPILER="./build/bin/compiler"
VERIFY_SCRIPT="./scripts/verify_asm.sh"
BASELINE_DIR="./lab4_results"
MAX_CASES=0
STOP_ON_FIRST_FAILURE=false
START_FROM=1
KEEP_OLD=true
PERFORMANCE_ONLY=false
show_help() {
cat << 'EOF'
用法: ./test5.sh [选项]
说明:
批量执行 Lab5(寄存器分配与后端优化)测试。
默认会递归扫描测试目录下所有 .sy 文件,
使用 -O 优化选项编译生成汇编,汇编链接后运行,
验证输出正确性。
选项:
-h, --help 显示此帮助信息
-n, --max-cases N 最多运行 N 个测试用例 (0=不限制)
-x, --stop-on-failure 遇到第一个失败即停止
-s, --start-from N 从第 N 个测试开始
-k, --keep 保留旧输出目录,不删除
-t, --test-root DIR 指定测试目录
-o, --output-dir DIR 指定输出目录
-p, --performance-only 仅测试文件夹名中含"performance"的测试
示例:
./test5.sh # 运行所有测试
./test5.sh -n 10 # 只运行前10个
./test5.sh -x # 失败即停止
./test5.sh --start-from 5 # 从第5个开始
./test5.sh -p # 仅测试performance相关文件夹
EOF
}
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-n|--max-cases)
MAX_CASES="$2"
shift 2
;;
-x|--stop-on-failure)
STOP_ON_FIRST_FAILURE=true
shift
;;
-s|--start-from)
START_FROM="$2"
shift 2
;;
-k|--keep)
KEEP_OLD=true
shift
;;
-t|--test-root)
TEST_ROOT="$2"
shift 2
;;
-o|--output-dir)
OUTPUT_DIR="$2"
shift 2
;;
-p|--performance-only)
PERFORMANCE_ONLY=true
shift
;;
*)
echo -e "${RED}未知参数: $1${NC}"
show_help
exit 1
;;
esac
done
}
parse_args "$@"
if [[ ! -x "$COMPILER" ]]; then
echo -e "${RED}错误: 编译器不存在或不可执行: $COMPILER${NC}"
echo "请先编译项目: cd build && cmake .. && make -j4"
exit 1
fi
if [[ ! -d "$TEST_ROOT" ]]; then
echo -e "${RED}错误: 测试目录不存在: $TEST_ROOT${NC}"
exit 1
fi
if [[ ! -x "$VERIFY_SCRIPT" ]]; then
echo -e "${RED}错误: verify脚本不可执行: $VERIFY_SCRIPT${NC}"
exit 1
fi
if [[ "$KEEP_OLD" != "true" ]]; then
rm -rf "$OUTPUT_DIR"
fi
mkdir -p "$OUTPUT_DIR"
OUTPUT_DIR="$OUTPUT_DIR/asm"
mkdir -p "$OUTPUT_DIR"
LOG_FILE="$OUTPUT_DIR/lab5_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"
OPT_REPORT_FILE="$OUTPUT_DIR/optimization_report.txt"
if [[ "$KEEP_OLD" != "true" ]]; then
: > "$LOG_FILE"
: > "$FAIL_FILE"
: > "$ERROR_LOG_FILE"
: > "$TIME_SUMMARY_FILE"
fi
{
echo "================================================"
echo "Lab5 寄存器分配与后端优化测试报告"
echo "================================================"
echo "基线目录: $BASELINE_DIR"
echo "生成时间: $(date)"
echo "================================================"
echo ""
echo "格式: 测试用例 | 基线时间(ms) | 优化后时间(ms) | 提升幅度"
echo "------------------------------------------------"
} > "$OPT_REPORT_FILE"
echo "Lab5 批量测试日志 - $(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"
collect_sy_files() {
if [[ "$PERFORMANCE_ONLY" == "true" ]]; then
find "$TEST_ROOT" -type d -name "*performance*" | while read dir; do
find "$dir" -type f -name '*.sy'
done | sort
else
find "$TEST_ROOT" -type f -name '*.sy' | sort
fi
}
calc_improvement() {
local old_time="$1"
local new_time="$2"
if [[ -z "$old_time" || -z "$new_time" ]]; then
echo ""
return
fi
if [[ "$old_time" -eq 0 ]]; then
echo ""
return
fi
local improvement=$(awk -v old="$old_time" -v new="$new_time" 'BEGIN { printf "%.2f", ((old - new) / old) * 100 }')
echo "$improvement"
}
run_single_test() {
local sy_file="$1"
local case_num="$2"
local filename=$(basename "$sy_file")
local base_name="${filename%.sy}"
local rel_path="${sy_file#$TEST_ROOT/}"
local rel_dir=$(dirname "$rel_path")
if [[ "$rel_dir" == "." ]]; then
rel_dir=""
fi
local case_out_dir="$OUTPUT_DIR"
if [[ -n "$rel_dir" ]]; then
case_out_dir="$OUTPUT_DIR/$rel_dir"
fi
mkdir -p "$case_out_dir"
rm -f "$case_out_dir/${base_name}_time.txt"
echo -ne "${YELLOW}[$case_num] $filename ... ${NC}"
set +e
"$VERIFY_SCRIPT" "$sy_file" "$case_out_dir" -O --run > /dev/null 2>&1
code=$?
set -e
local opt_time_file="$case_out_dir/${base_name}_time.txt"
local opt_time=""
if [[ -f "$opt_time_file" ]]; then
opt_time=$(cat "$opt_time_file")
fi
local baseline_time=""
local baseline_time_file=""
local baseline_search_paths=(
"$BASELINE_DIR/$rel_path/${base_name}_time.txt"
"$BASELINE_DIR/$rel_dir/${base_name}_time.txt"
)
if [[ ! -f "${baseline_search_paths[0]}" ]] && [[ ! -f "${baseline_search_paths[1]}" ]]; then
baseline_time_file=$(find "$BASELINE_DIR" -name "${base_name}_time.txt" 2>/dev/null | head -n 1)
fi
for path in "${baseline_search_paths[@]}"; do
if [[ -f "$path" ]]; then
baseline_time_file="$path"
break
fi
done
if [[ -f "$baseline_time_file" ]]; then
baseline_time=$(cat "$baseline_time_file")
fi
if [[ $code -eq 0 ]]; then
SUCCESS=$((SUCCESS + 1))
if [[ -n "$opt_time" && "$opt_time" =~ ^[0-9]+$ ]]; then
total_time_sum=$((total_time_sum + opt_time))
time_cases_count=$((time_cases_count + 1))
echo "$rel_path: ${opt_time}ms" >> "$TIME_SUMMARY_FILE"
echo -ne "${GREEN}成功${NC} "
if [[ -n "$baseline_time" && "$baseline_time" =~ ^[0-9]+$ ]]; then
improvement=$(calc_improvement "$baseline_time" "$opt_time")
if [[ -n "$improvement" ]]; then
if (( $(echo "$improvement > 0" | bc -l 2>/dev/null || echo "0") )); then
echo -ne "${GREEN}(${baseline_time}ms->${opt_time}ms+${improvement}%)${NC}"
total_improvement_sum=$(echo "$total_improvement_sum + $improvement" | bc -l 2>/dev/null || echo "0")
improvement_count=$((improvement_count + 1))
elif (( $(echo "$improvement < 0" | bc -l 2>/dev/null || echo "0") )); then
echo -ne "${RED}(${baseline_time}ms->${opt_time}ms${improvement}%)${NC}"
total_degradation_sum=$(echo "$total_degradation_sum + (0 - $improvement)" | bc -l 2>/dev/null || echo "0")
degradation_count=$((degradation_count + 1))
else
echo -ne "(${baseline_time}ms->${opt_time}ms+0.00%)"
fi
echo "$rel_path | $baseline_time | $opt_time | ${improvement}%" >> "$OPT_REPORT_FILE"
else
echo -ne "(${baseline_time}ms->${opt_time}ms)"
fi
else
echo -ne "(${opt_time}ms无基线数据)"
fi
echo ""
else
echo -e "${GREEN}成功${NC} (运行时间: N/A)"
fi
echo "[SUCCESS] $sy_file" >> "$LOG_FILE"
else
FAILED=$((FAILED + 1))
echo "$sy_file" >> "$FAIL_FILE"
if [[ -n "$opt_time" && "$opt_time" =~ ^[0-9]+$ ]]; then
echo -e "${RED}失败${NC} (${opt_time}ms)"
else
echo -e "${RED}失败${NC}"
fi
echo "[FAILED] $sy_file (exit=$code)" >> "$LOG_FILE"
echo "========================================" >> "$ERROR_LOG_FILE"
echo "测试失败: $sy_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}失败文件: $sy_file${NC}"
echo -e "${RED}日志: $LOG_FILE${NC}"
echo -e "${RED}错误日志: $ERROR_LOG_FILE${NC}"
echo -e "${RED}========================================${NC}"
return 1
fi
fi
return 0
}
main() {
local sy_files=($(collect_sy_files))
local total=${#sy_files[@]}
if [[ $total -eq 0 ]]; then
echo -e "${YELLOW}警告: 未找到任何测试文件${NC}"
exit 0
fi
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab5 寄存器分配与后端优化测试 (ASM模式)${NC}"
echo -e "${BLUE}========================================${NC}"
echo "测试目录: $TEST_ROOT"
echo "输出目录: $OUTPUT_DIR"
echo "基线目录: $BASELINE_DIR"
echo "测试用例总数: $total"
echo ""
SUCCESS=0
FAILED=0
case_num=0
total_time_sum=0
time_cases_count=0
total_improvement_sum=0
improvement_count=0
total_degradation_sum=0
degradation_count=0
for sy_file in "${sy_files[@]}"; do
case_num=$((case_num + 1))
if [[ $case_num -lt $START_FROM ]]; then
continue
fi
local executed=$((case_num - START_FROM + 1))
if [[ $MAX_CASES -gt 0 && $executed -gt $MAX_CASES ]]; then
break
fi
set +e
run_single_test "$sy_file" "$case_num"
test_result=$?
set -e
if [[ $test_result -eq 1 ]] && [[ "$STOP_ON_FIRST_FAILURE" = true ]]; then
break
fi
done
{
echo ""
echo "================================================"
echo "优化对比摘要"
echo "================================================"
if [[ $improvement_count -gt 0 ]]; then
avg_improvement=$(echo "scale=2; $total_improvement_sum / $improvement_count" | bc 2>/dev/null || echo "0")
echo "平均性能提升: ${avg_improvement}% (基于 $improvement_count 个测试)"
fi
if [[ $degradation_count -gt 0 ]]; then
avg_degradation=$(echo "scale=2; $total_degradation_sum / $degradation_count" | bc 2>/dev/null || echo "0")
echo "平均性能退化: ${avg_degradation}% (基于 $degradation_count 个测试)"
fi
echo ""
echo "================================================"
} >> "$OPT_REPORT_FILE"
RATE="0.00"
if [[ $case_num -gt 0 ]]; then
RATE=$(awk -v s="$SUCCESS" -v t="$case_num" 'BEGIN { printf "%.2f", (s*100.0)/t }')
fi
echo ""
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab5 批量测试完成${NC}"
echo -e "${BLUE}执行用例: $case_num${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}"
fi
if [[ $improvement_count -gt 0 ]]; then
avg_improvement=$(echo "scale=2; $total_improvement_sum / $improvement_count" | bc 2>/dev/null || echo "0")
echo -e "${GREEN}平均性能提升: ${avg_improvement}% (基于 $improvement_count 个测试)${NC}"
fi
if [[ $degradation_count -gt 0 ]]; then
avg_degradation=$(echo "scale=2; $total_degradation_sum / $degradation_count" | bc 2>/dev/null || echo "0")
echo -e "${RED}平均性能退化: ${avg_degradation}% (基于 $degradation_count 个测试)${NC}"
fi
echo -e "${BLUE}时间汇总: $TIME_SUMMARY_FILE${NC}"
echo -e "${BLUE}优化报告: $OPT_REPORT_FILE${NC}"
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}"
if [[ $FAILED -gt 0 ]]; then
exit 1
fi
exit 0
}
main