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/scripts/diff_test.sh

690 lines
21 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
# 差分测试:编译器 vs gcc支持正确性对比和性能对比
# 用法:
# ./scripts/diff_test.sh --baseline 生成 gcc 正确性基线
# ./scripts/diff_test.sh --diff 正确性差分对比(输出是否一致)
# ./scripts/diff_test.sh --perf 性能对比(指令数)
# ./scripts/diff_test.sh --perf --gcc-opt 2 性能对比 vs gcc -O2
# ./scripts/diff_test.sh --perf --save-asm 性能对比并保存 gcc 汇编
# ./scripts/diff_test.sh --perf --gcc-opt 0 对比 gcc -O0最低基线
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
BLUE='\033[0;34m'
NC='\033[0m'
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
TEST_ROOT="$PROJECT_ROOT/2026test"
RESULTS_ROOT="$PROJECT_ROOT/2026test_results"
GCC_BASELINE_DIR="$RESULTS_ROOT/gcc_baseline"
GCC_ASM_DIR="$RESULTS_ROOT/gcc_asm"
RUNTIME_SRC="$PROJECT_ROOT/sylib/sylib.c"
RUNTIME_OBJ="$PROJECT_ROOT/build/test_runtime/sylib_gcc.o"
COMPILER="$PROJECT_ROOT/build/bin/compiler"
GCC="aarch64-linux-gnu-gcc"
QEMU="qemu-aarch64"
CORRECTNESS_CATS=("functional" "h_functional")
PERF_CATS=("performance")
DO_BASELINE=false
DO_DIFF=false
DO_PERF=false
SAVE_ASM=false
GCC_OPT_LEVEL=3
MAX_CASES=0
REPORT_FILE=""
JSON_FILE=""
JOBS=$(nproc 2>/dev/null || echo 4)
usage() {
cat <<'EOF'
用法: ./scripts/diff_test.sh [选项]
差分测试:对每个 .sy 用例,用编译器生成汇编和 gcc 编译后,
比较输出(正确性)或指令数(性能)。
模式(至少选一个):
--baseline 生成 gcc 正确性基线(保存输出到 gcc_baseline/
--diff 正确性差分对比(编译器输出 vs gcc 基线)
--perf 性能对比(编译器 vs gcc 指令数及比值)
性能对比选项(与 --perf 配合):
--gcc-opt <N> gcc 优化级别 0/1/2/3默认: 3最高标准优化
--save-asm 保存 gcc 汇编到 gcc_asm/ 供人工分析
--perf-cats <cats> 性能对比覆盖的类别,逗号分隔
(默认: performance也可加 functional,h_functional
--report <file> 导出性能对比结果到 CSV 文件
--json <file> 导出性能对比结果到 JSON 文件
通用选项:
-n, --max N 最多运行 N 个用例 (0=不限制,默认: 0)
-j, --jobs N 并行任务数 (默认: nproc设为1恢复串行)
-h, --help 显示此帮助信息
输出目录:
2026test_results/gcc_baseline/ gcc 正确性基线(输出 + 退出码)
2026test_results/gcc_asm/ gcc 汇编(--save-asm 时保存)
EOF
}
# ============================================================
# 参数解析
# ============================================================
while [[ $# -gt 0 ]]; do
case "$1" in
--baseline) DO_BASELINE=true ;;
--diff) DO_DIFF=true ;;
--perf) DO_PERF=true ;;
--save-asm) SAVE_ASM=true ;;
--gcc-opt) GCC_OPT_LEVEL="$2"; shift ;;
--perf-cats) IFS=',' read -ra PERF_CATS <<< "$2"; shift ;;
--report) REPORT_FILE="$2"; shift ;;
--json) JSON_FILE="$2"; shift ;;
-n|--max) MAX_CASES="$2"; shift ;;
-j|--jobs) JOBS="$2"
if ! [[ "$JOBS" =~ ^[0-9]+$ ]] || [[ "$JOBS" -lt 1 ]]; then
echo "错误: --jobs 需要正整数"; exit 1
fi ;;
-h|--help) usage; exit 0 ;;
*) echo "未知选项: $1"; usage; exit 1 ;;
esac
shift
done
if [[ "$DO_BASELINE" == false && "$DO_DIFF" == false && "$DO_PERF" == false ]]; then
echo "错误: 至少需要 --baseline、--diff 或 --perf 之一"
usage
exit 1
fi
if ! [[ "$GCC_OPT_LEVEL" =~ ^[0-3]$ ]]; then
echo "错误: --gcc-opt 必须是 0/1/2/3"
exit 1
fi
# ============================================================
# 预检
# ============================================================
command -v "$GCC" >/dev/null 2>&1 || { echo "未找到 $GCC"; exit 1; }
command -v "$QEMU" >/dev/null 2>&1 || { echo "未找到 $QEMU"; exit 1; }
[[ -f "$RUNTIME_SRC" ]] || { echo "未找到 $RUNTIME_SRC"; exit 1; }
[[ -f "$COMPILER" ]] || { echo "未找到编译器 $COMPILER,请先构建"; exit 1; }
# 编译运行时库
mkdir -p "$(dirname "$RUNTIME_OBJ")"
if [[ ! -f "$RUNTIME_OBJ" || "$RUNTIME_SRC" -nt "$RUNTIME_OBJ" ]]; then
echo "编译运行时库 $RUNTIME_SRC$RUNTIME_OBJ ..."
$GCC -O2 -c "$RUNTIME_SRC" -o "$RUNTIME_OBJ"
fi
# ============================================================
# SysY → C 预处理(让 gcc 能编译 SysY 特有问题)
# ============================================================
preprocess_for_gcc() {
local src="$1"
local dst="$2"
python3 -c "
import re, sys
with open('$src') as f:
content = f.read()
content = re.sub(r'const int (\w+) = ([^;]+);', r'#define \1 \2', content)
with open('$dst', 'w') as f:
f.write(content)
"
}
# ============================================================
# 规范化比较(替代 python3减少进程启动开销
# ============================================================
canon_compare() {
local expected="$1" actual="$2"
diff -q \
<(sed 's/\r$//; s/[[:space:]]*$//' "$expected" \
| awk '{lines[NR]=$0} END{last=NR; while(last>0&&lines[last]=="")last--; for(i=1;i<=last;i++)print lines[i]}') \
<(sed 's/\r$//; s/[[:space:]]*$//' "$actual" \
| awk '{lines[NR]=$0} END{last=NR; while(last>0&&lines[last]=="")last--; for(i=1;i<=last;i++)print lines[i]}') \
> /dev/null 2>&1
}
# ============================================================
# 收集用例
# ============================================================
collect_cases() {
local cats=("$@")
local cases=()
for cat in "${cats[@]}"; do
local dir="$TEST_ROOT/$cat"
[[ -d "$dir" ]] || continue
for sy in "$dir"/*.sy; do
[[ -f "$sy" ]] || continue
cases+=("$sy")
done
done
printf '%s\n' "${cases[@]}" | sort
}
load_cases() {
local cats=("$@")
CASES=()
while IFS= read -r line; do
CASES+=("$line")
done < <(collect_cases "${cats[@]}")
if [[ "$MAX_CASES" -gt 0 && "$MAX_CASES" -lt "${#CASES[@]}" ]]; then
CASES=("${CASES[@]:0:$MAX_CASES}")
fi
}
# ============================================================
# 生成 gcc 正确性基线(并行化)
# ============================================================
run_baseline_worker() {
local idx="$1" sy="$2"
local result_file="$3"
local dir=$(dirname "$sy")
local cat=$(basename "$dir")
local base=$(basename "$sy")
local stem=${base%.sy}
local out_dir="$GCC_BASELINE_DIR/$cat"
local exe="$out_dir/$stem"
local actual_file="$out_dir/$stem.actual.out"
local stdin_file="$dir/$stem.in"
mkdir -p "$out_dir"
local gcc_src=$(mktemp /tmp/gcc_baseline_XXXX.sy)
preprocess_for_gcc "$sy" "$gcc_src"
local status="FAIL"
if $GCC -x c "$gcc_src" -x none "$RUNTIME_OBJ" -static -o "$exe" -lm 2>/dev/null; then
rm -f "$gcc_src"
local exit_code=0
set +e
if [[ -f "$stdin_file" ]]; then
timeout --signal=KILL 60 "$QEMU" "$exe" < "$stdin_file" > "$out_dir/$stem.stdout" 2>/dev/null || exit_code=$?
else
timeout --signal=KILL 60 "$QEMU" "$exe" < /dev/null > "$out_dir/$stem.stdout" 2>/dev/null || exit_code=$?
fi
set -e
{
cat "$out_dir/$stem.stdout"
if [[ -s "$out_dir/$stem.stdout" ]] && (( $(tail -c 1 "$out_dir/$stem.stdout" | wc -l) == 0 )); then
printf '\n'
fi
printf '%s\n' "$exit_code"
} > "$actual_file"
status="OK"
else
rm -f "$gcc_src"
fi
printf 'STATUS=%s\nNAME=%s\n' "$status" "$stem" > "$result_file"
}
run_baseline() {
load_cases "${CORRECTNESS_CATS[@]}"
echo ""
echo "========== 生成 gcc 正确性基线(${#CASES[@]} 用例)=========="
local res_dir="$GCC_BASELINE_DIR/.results"
mkdir -p "$res_dir"
if [[ $JOBS -gt 1 && ${#CASES[@]} -gt 1 ]]; then
export GCC_BASELINE_DIR RUNTIME_OBJ GCC QEMU
export -f run_baseline_worker preprocess_for_gcc
declare -a QUEUE=()
for i in "${!CASES[@]}"; do
QUEUE+=("$i|${CASES[$i]}")
done
printf '%s\n' "${QUEUE[@]}" | xargs -P "$JOBS" -L 1 bash -c '
IFS="|" read -r idx sy <<< "$1"
run_baseline_worker "$idx" "$sy" "'"$res_dir"'/$idx"
' _
else
for i in "${!CASES[@]}"; do
run_baseline_worker "$i" "${CASES[$i]}" "$res_dir/$i"
done
fi
# 汇总
local total=0 pass=0 fail=0
for i in "${!CASES[@]}"; do
total=$((total + 1))
if [[ -f "$res_dir/$i" ]]; then
local status name
status=$(grep '^STATUS=' "$res_dir/$i" | cut -d= -f2)
name=$(grep '^NAME=' "$res_dir/$i" | cut -d= -f2)
if [[ "$status" == "OK" ]]; then
pass=$((pass + 1))
printf " [${GREEN}OK${NC}] %-35s (%d/%d)\r" "$name" "$total" "${#CASES[@]}"
else
fail=$((fail + 1))
echo -e " [${RED}FAIL${NC}] $name (gcc 编译失败)"
fi
else
fail=$((fail + 1))
fi
done
rm -rf "$res_dir"
printf '\n'
echo "基线完成: $pass/$total 成功"
if [[ $fail -gt 0 ]]; then
echo -e " ${YELLOW}$fail 个 gcc 编译失败(可能使用了 gcc 不支持的 SysY 语法)${NC}"
fi
}
# ============================================================
# 正确性差分对比
# ============================================================
run_diff() {
load_cases "${CORRECTNESS_CATS[@]}"
echo ""
echo "========== 正确性差分对比(${#CASES[@]} 用例)=========="
local total=0 match=0 mismatch=0 skip=0
for sy in "${CASES[@]}"; do
total=$((total + 1))
local dir=$(dirname "$sy")
local cat=$(basename "$dir")
local base=$(basename "$sy")
local stem=${base%.sy}
local compiler_out="$RESULTS_ROOT/$cat/$stem.actual.out"
local gcc_out="$GCC_BASELINE_DIR/$cat/$stem.actual.out"
if [[ ! -f "$compiler_out" ]]; then
echo -e " [${YELLOW}SKIP${NC}] $stem (无编译器输出,先跑 2026test.sh)"
skip=$((skip + 1))
continue
fi
if [[ ! -f "$gcc_out" ]]; then
echo -e " [${YELLOW}SKIP${NC}] $stem (无 gcc 基线,先跑 --baseline)"
skip=$((skip + 1))
continue
fi
if canon_compare "$compiler_out" "$gcc_out"; then
match=$((match + 1))
printf " [${GREEN}MATCH${NC}] %-35s (%d/%d)\r" "$stem" "$total" "${#CASES[@]}"
else
mismatch=$((mismatch + 1))
printf '\n'
echo -e " [${RED}MISMATCH${NC}] $stem"
echo " --- 编译器输出 ---"
cat "$compiler_out" | head -20 | sed 's/^/ | /'
echo " --- gcc 输出 ---"
cat "$gcc_out" | head -20 | sed 's/^/ | /'
echo " --- diff ---"
diff -u <(cat "$compiler_out") <(cat "$gcc_out") | head -20 | sed 's/^/ | /' || true
echo ""
fi
done
printf '\n'
echo "========== 正确性差分结果 =========="
echo -e " 匹配: ${GREEN}$match${NC}"
echo -e " 不匹配: ${RED}$mismatch${NC}"
if [[ $skip -gt 0 ]]; then
echo -e " 跳过: ${YELLOW}$skip${NC}"
fi
if [[ $mismatch -eq 0 ]]; then
echo -e "\n${GREEN}全部匹配,编译器输出与 gcc -O0 一致${NC}"
fi
}
# ============================================================
# 性能对比(并行化)
# ============================================================
run_perf_worker() {
local idx="$1" sy="$2" result_file="$3"
local dir=$(dirname "$sy")
local cat=$(basename "$dir")
local base=$(basename "$sy")
local stem=${base%.sy}
local compiler_asm=$(mktemp /tmp/compiler_XXXX.s)
local gcc_asm=$(mktemp /tmp/gcc_XXXX.s)
# 编译器生成汇编
local comp_ok=true compiler_lines=0
if ! timeout --signal=KILL 60 "$COMPILER" -S -O -o "$compiler_asm" "$sy" 2>/dev/null; then
comp_ok=false
else
compiler_lines=$(wc -l < "$compiler_asm")
compiler_lines=${compiler_lines:-0}
fi
# gcc 生成汇编
local gcc_ok=true gcc_lines=0
local gcc_src=$(mktemp /tmp/gcc_perf_XXXX.sy)
preprocess_for_gcc "$sy" "$gcc_src"
if ! $GCC -x c -S "-O${GCC_OPT_LEVEL}" -o "$gcc_asm" "$gcc_src" 2>/dev/null; then
gcc_ok=false
else
gcc_lines=$(wc -l < "$gcc_asm")
gcc_lines=${gcc_lines:-0}
fi
rm -f "$gcc_src"
# 保存 gcc 汇编
if [[ "$SAVE_ASM" == true && "$gcc_ok" == true ]]; then
local save_dir="$GCC_ASM_DIR/${cat}/${GCC_OPT_LEVEL}"
mkdir -p "$save_dir"
cp "$gcc_asm" "$save_dir/${stem}.s"
fi
rm -f "$compiler_asm" "$gcc_asm"
printf 'STATUS=%s\nSTEM=%s\nCAT=%s\nCOMPILER_LINES=%s\nGCC_LINES=%s\n' \
"$(if $comp_ok && $gcc_ok; then echo "OK"; elif ! $comp_ok; then echo "COMP_FAIL"; else echo "GCC_FAIL"; fi)" \
"$stem" "$cat" "$compiler_lines" "$gcc_lines" \
> "$result_file"
}
run_perf() {
load_cases "${PERF_CATS[@]}"
local gcc_opt="-O${GCC_OPT_LEVEL}"
local gcc_label="gcc ${gcc_opt}"
echo ""
echo "========== 性能对比:编译器 -O vs ${gcc_label}${#CASES[@]} 用例)=========="
echo ""
local res_dir="$RESULTS_ROOT/.perf_results"
rm -rf "$res_dir"
mkdir -p "$res_dir"
# 并行或串行执行
if [[ $JOBS -gt 1 && ${#CASES[@]} -gt 1 ]]; then
export COMPILER GCC GCC_OPT_LEVEL SAVE_ASM GCC_ASM_DIR
export -f run_perf_worker preprocess_for_gcc
declare -a QUEUE=()
for i in "${!CASES[@]}"; do
QUEUE+=("$i|${CASES[$i]}")
done
printf '%s\n' "${QUEUE[@]}" | xargs -P "$JOBS" -L 1 bash -c '
IFS="|" read -r idx sy <<< "$1"
run_perf_worker "$idx" "$sy" "'"$res_dir"'/$idx"
' _
else
for i in "${!CASES[@]}"; do
run_perf_worker "$i" "${CASES[$i]}" "$res_dir/$i"
done
fi
# 汇总
local total=${#CASES[@]}
local compiler_fail=0 gcc_fail=0
local -a results=() # "stem|compiler_lines|gcc_lines|ratio"
for i in "${!CASES[@]}"; do
local rf="$res_dir/$i"
if [[ ! -f "$rf" ]]; then
compiler_fail=$((compiler_fail + 1))
echo -e " [${RED}FAIL${NC}] $(basename "${CASES[$i]}" .sy) 超时/崩溃"
continue
fi
local status stem cat cl gl
status=$(grep '^STATUS=' "$rf" | cut -d= -f2)
stem=$(grep '^STEM=' "$rf" | cut -d= -f2)
cl=$(grep '^COMPILER_LINES=' "$rf" | cut -d= -f2)
gl=$(grep '^GCC_LINES=' "$rf" | cut -d= -f2)
case "$status" in
COMP_FAIL)
compiler_fail=$((compiler_fail + 1))
echo -e " [${RED}FAIL${NC}] $stem 编译器编译失败"
;;
GCC_FAIL)
gcc_fail=$((gcc_fail + 1))
echo -e " [${YELLOW}SKIP${NC}] $stem gcc 编译失败"
;;
OK)
local ratio flag=""
if [[ "$gl" -eq 0 ]]; then
ratio="N/A"
else
ratio=$(awk -v c="$cl" -v g="$gl" 'BEGIN { printf "%.2f", c/g }')
fi
if [[ "$ratio" != "N/A" ]]; then
if awk -v r="$ratio" 'BEGIN { exit(r <= 1.5 ? 0 : 1) }'; then
flag="${GREEN}"
elif awk -v r="$ratio" 'BEGIN { exit(r <= 3.0 ? 0 : 1) }'; then
flag="${YELLOW}"
else
flag="${RED}"
fi
fi
printf " %-35s 编译器:%5d gcc:%5d ${flag}${BOLD}%sx${NC}\n" \
"$stem" "$cl" "$gl" "$ratio"
results+=("$stem|$cl|$gl|$ratio")
;;
esac
done
rm -rf "$res_dir"
# 汇总统计
printf '\n'
echo "========== 性能对比汇总 =========="
echo ""
local valid=${#results[@]}
if [[ $valid -eq 0 ]]; then
echo "无有效用例"
return
fi
# TOP 5 差距最大
echo "--- 差距最大 TOP 5优先优化---"
printf '%s\n' "${results[@]}" | sort -t'|' -k4 -rn | head -5 | while IFS='|' read -r stem cl gl ratio; do
local flag="${RED}"
if awk -v r="$ratio" 'BEGIN { exit(r <= 1.5 ? 0 : 1) }'; then flag="${GREEN}"
elif awk -v r="$ratio" 'BEGIN { exit(r <= 3.0 ? 0 : 1) }'; then flag="${YELLOW}"; fi
printf " %-35s 编译器:%5d gcc:%5d ${flag}${BOLD}%sx${NC}\n" "$stem" "$cl" "$gl" "$ratio"
done
echo ""
echo "--- 差距最小 TOP 5最接近 1.0x---"
printf '%s\n' "${results[@]}" | awk -F'|' '
{
ratio = $4 + 0
dist = (ratio > 1.0) ? (ratio - 1.0) : (1.0 - ratio)
printf "%s|%s|%s|%s|%f\n", $1, $2, $3, $4, dist
}' | sort -t'|' -k5 -n | head -5 | while IFS='|' read -r stem cl gl ratio dist; do
printf " %-35s 编译器:%5d gcc:%5d ${GREEN}${BOLD}%sx${NC}\n" "$stem" "$cl" "$gl" "$ratio"
done
echo ""
# 编译器指令数总计
local total_compiler=0 total_gcc=0
for r in "${results[@]}"; do
local cl=$(echo "$r" | cut -d'|' -f2)
local gl=$(echo "$r" | cut -d'|' -f3)
total_compiler=$((total_compiler + cl))
total_gcc=$((total_gcc + gl))
done
# 几何平均
local geo_mean
geo_mean=$(printf '%s\n' "${results[@]}" | awk -F'|' '
BEGIN { sum = 0; n = 0 }
{
ratio = $4 + 0
if (ratio > 0) { sum += log(ratio); n++ }
}
END {
if (n > 0) printf "%.2f", exp(sum / n)
else print "N/A"
}')
echo "--- 整体指标 ---"
printf " 编译器总指令数: %d\n" "$total_compiler"
printf " %s 总指令数: %d\n" "$gcc_label" "$total_gcc"
printf " 总指令数比: ${BOLD}%.2fx${NC}\n" "$(awk -v c="$total_compiler" -v g="$total_gcc" 'BEGIN { printf "%.2f", c/g }')"
printf " 几何平均比: ${BOLD}%sx${NC} (越接近 1.0 越接近 %s)\n" "$geo_mean" "$gcc_label"
printf " 有效用例: %d\n" "$valid"
if [[ $compiler_fail -gt 0 ]]; then
printf " 编译器失败: %d\n" "$compiler_fail"
fi
if [[ $gcc_fail -gt 0 ]]; then
printf " gcc 失败: %d\n" "$gcc_fail"
fi
echo ""
# 性能分估算
local target_ratio="1.11"
if awk -v gm="$geo_mean" -v tr="$target_ratio" 'BEGIN { exit(gm <= tr ? 0 : 1) }'; then
echo -e "${GREEN}几何平均比 ${geo_mean}x ≤ ${target_ratio}x性能分预估 ≥90一级水平${NC}"
else
local perf_est
perf_est=$(awk -v gm="$geo_mean" 'BEGIN { printf "%.0f", 100 / gm }')
echo -e "${YELLOW}几何平均比 ${geo_mean}x > ${target_ratio}x性能分预估 ≈${perf_est}(一级需 ≥90${NC}"
fi
if [[ "$SAVE_ASM" == true ]]; then
echo ""
echo -e "${CYAN}gcc 汇编已保存到 $GCC_ASM_DIR/${GCC_OPT_LEVEL}/${NC}"
echo " 可对比分析 gcc 的优化策略(循环展开、向量化、指令调度等)"
fi
# 导出报告
if [[ -n "$REPORT_FILE" ]]; then
_export_csv "$gcc_label" "$GCC_OPT_LEVEL" "$total_compiler" "$total_gcc" "$geo_mean" "$valid" "$compiler_fail" "$gcc_fail"
echo ""
echo -e "${CYAN}CSV 报告已导出到 $REPORT_FILE${NC}"
fi
if [[ -n "$JSON_FILE" ]]; then
_export_json "$gcc_label" "$GCC_OPT_LEVEL" "$total_compiler" "$total_gcc" "$geo_mean" "$valid" "$compiler_fail" "$gcc_fail"
echo ""
echo -e "${CYAN}JSON 报告已导出到 $JSON_FILE${NC}"
fi
}
# ============================================================
# 导出函数
# ============================================================
_export_csv() {
local gcc_label="$1" gcc_opt="$2"
local total_compiler="$3" total_gcc="$4" geo_mean="$5"
local valid="$6" compiler_fail="$7" gcc_fail="$8"
local now=$(date '+%Y-%m-%d %H:%M:%S')
local perf_est=$(awk -v gm="$geo_mean" 'BEGIN { printf "%.0f", 100 / gm }')
{
echo "test_case,category,compiler_insn,gcc_insn,ratio,winner"
printf '%s\n' "${results[@]}" | sort -t'|' -k4 -rn | while IFS='|' read -r stem cl gl ratio; do
local cat=""
for c in "${PERF_CATS[@]}"; do
[[ -f "$TEST_ROOT/$c/${stem}.sy" ]] && { cat="$c"; break; }
done
local winner="gcc"
if awk -v r="$ratio" 'BEGIN { exit(r < 1.0 ? 0 : 1) }'; then winner="compiler"; fi
if [[ "$ratio" == "1.00" ]]; then winner="tie"; fi
echo "${stem},${cat},${cl},${gl},${ratio},${winner}"
done
echo ""
echo "# 汇总,,,"
echo "生成时间,,${now}"
echo "gcc优化级别,,${gcc_opt}"
echo "有效用例,,${valid}"
echo "编译器总指令数,,${total_compiler}"
echo "gcc总指令数,,${total_gcc}"
echo "总指令数比,,${total_compiler}/${total_gcc}"
echo "几何平均比,,${geo_mean}"
echo "性能分预估,,${perf_est}"
} > "$REPORT_FILE"
}
_export_json() {
local gcc_label="$1" gcc_opt="$2"
local total_compiler="$3" total_gcc="$4" geo_mean="$5"
local valid="$6" compiler_fail="$7" gcc_fail="$8"
local now=$(date -Iseconds)
local perf_est=$(awk -v gm="$geo_mean" 'BEGIN { printf "%.0f", 100 / gm }')
python3 - "$JSON_FILE" "$now" "$gcc_opt" "$valid" \
"$total_compiler" "$total_gcc" "$geo_mean" "$perf_est" \
"$compiler_fail" "$gcc_fail" \
"${results[@]}" <<'PY'
import sys, json
outfile = sys.argv[1]
report = {
"generated_at": sys.argv[2],
"gcc_opt_level": int(sys.argv[3]),
"summary": {
"valid_cases": int(sys.argv[4]),
"total_compiler_insn": int(sys.argv[5]),
"total_gcc_insn": int(sys.argv[6]),
"geometric_mean_ratio": float(sys.argv[7]),
"estimated_performance_score": float(sys.argv[8]),
"compiler_fail": int(sys.argv[9]),
"gcc_fail": int(sys.argv[10]),
},
"cases": []
}
for r in sys.argv[11:]:
stem, cl, gl, ratio = r.split('|')
rv = float(ratio)
winner = "compiler" if rv < 1.0 else ("tie" if rv == 1.0 else "gcc")
report["cases"].append({
"test_case": stem,
"compiler_insn": int(cl),
"gcc_insn": int(gl),
"ratio": rv,
"winner": winner
})
with open(outfile, 'w') as f:
json.dump(report, f, ensure_ascii=False, indent=2)
PY
}
# ============================================================
# 执行
# ============================================================
if [[ "$DO_BASELINE" == true ]]; then
run_baseline
fi
if [[ "$DO_DIFF" == true ]]; then
run_diff
fi
if [[ "$DO_PERF" == true ]]; then
run_perf
fi