From 407be0fca12124723547f693603b9933bc2cb209 Mon Sep 17 00:00:00 2001 From: the-little-apprentice <1343456449@qq.com> Date: Mon, 27 Apr 2026 10:17:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=84=9A=E6=9C=AC=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/analyze_case.sh | 55 ++++++++++++--------- scripts/usage.txt | 103 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 23 deletions(-) create mode 100644 scripts/usage.txt diff --git a/scripts/analyze_case.sh b/scripts/analyze_case.sh index 0af0ef5..c83e009 100755 --- a/scripts/analyze_case.sh +++ b/scripts/analyze_case.sh @@ -48,6 +48,11 @@ STEM="${BASE%.sy}" INPUT_DIR="$(dirname "$(realpath "$INPUT")")" TIMESTAMP="$(date +%Y%m%d_%H%M%S)" +# 与 run_baseline.sh 一致的路径键:去掉 test/ 前缀和 .sy 后缀 +REL="$(realpath --relative-to="$REPO_ROOT" "$INPUT" 2>/dev/null || echo "$INPUT")" +CASE_KEY="${REL#test/}" +CASE_KEY="${CASE_KEY%.sy}" + if [[ $# -ge 2 ]]; then OUT_DIR="$2" else @@ -162,26 +167,28 @@ GCC_ASM_LINES=0 GCC_ELAPSED_RAW="" # 秒,无 s 后缀 if [[ -f "$BASELINE_TSV_PATH" ]]; then - GCC_ELAPSED_RAW=$(awk -F'\t' -v s="$STEM" '$1==s{v=$2} END{if(v!="") print v}' \ + GCC_ELAPSED_RAW=$(awk -F'\t' -v s="$CASE_KEY" '$1==s{v=$2} END{if(v!="") print v}' \ "$BASELINE_TSV_PATH" 2>/dev/null || true) if [[ -n "$GCC_ELAPSED_RAW" ]]; then GCC_OK=true rpt_color "$GREEN" "baseline timing: ${GCC_ELAPSED_RAW}s" else - rpt_color "$YELLOW" "WARNING: no baseline entry for '$STEM'" + rpt_color "$YELLOW" "WARNING: no baseline entry for '$CASE_KEY'" rpt " Run: scripts/run_baseline.sh" fi - # 复制汇编文件 - if [[ -f "$BASELINE_DATA_DIR/$STEM.gcc.s" ]]; then - cp "$BASELINE_DATA_DIR/$STEM.gcc.s" "$GCC_ASM" + # 复制汇编文件(路径镜像结构) + local_gcc_asm="$BASELINE_DATA_DIR/${CASE_KEY}.gcc.s" + if [[ -f "$local_gcc_asm" ]]; then + cp "$local_gcc_asm" "$GCC_ASM" GCC_ASM_LINES=$(wc -l < "$GCC_ASM") rpt "GCC ASM: $GCC_ASM ($GCC_ASM_LINES lines)" else - rpt_color "$YELLOW" "GCC ASM not found in baseline dir" + rpt_color "$YELLOW" "GCC ASM not found in baseline dir: $local_gcc_asm" fi - # 复制输出文件(供步骥5 diff) - if [[ -f "$BASELINE_DATA_DIR/$STEM.gcc.out" ]]; then - cp "$BASELINE_DATA_DIR/$STEM.gcc.out" "$GCC_OUT" + # 复制输出文件(供步骤5 diff) + local_gcc_out="$BASELINE_DATA_DIR/${CASE_KEY}.gcc.out" + if [[ -f "$local_gcc_out" ]]; then + cp "$local_gcc_out" "$GCC_OUT" rpt "GCC output: $GCC_OUT" fi else @@ -199,24 +206,25 @@ run_and_time() { local label="$1" local exe="$2" local out_file="$3" - local time_file="$4" - local timeout_sec="${5:-60}" + local timeout_sec="${4:-60}" local stdout_file="$out_file.raw" local status=0 + local _t0 _t1 _ns + _t0=$(date +%s%N) set +e if [[ -f "$STDIN_FILE" ]]; then timeout "$timeout_sec" \ - /usr/bin/time -f "%e" -o "$time_file" \ qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" \ < "$STDIN_FILE" > "$stdout_file" 2>/dev/null else timeout "$timeout_sec" \ - /usr/bin/time -f "%e" -o "$time_file" \ qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" \ > "$stdout_file" 2>/dev/null fi status=$? + _t1=$(date +%s%N) + _ns=$((_t1 - _t0)) set -e # 将 stdout + exit_code 合并为 .out(与 verify_asm.sh 格式一致) @@ -229,26 +237,27 @@ run_and_time() { } > "$out_file" rm -f "$stdout_file" - local elapsed="timeout" - [[ $status -ne 124 ]] && elapsed="$(cat "$time_file" 2>/dev/null || echo "?")s" - + local elapsed if [[ $status -eq 124 ]]; then - rpt_color "$YELLOW" "$label: TIMEOUT (>${timeout_sec}s)" - elif [[ $status -ne 0 ]]; then - rpt_color "$YELLOW" "$label: exit $status elapsed=${elapsed}" + elapsed="timeout" + rpt_color "$YELLOW" "$label: TIMEOUT (>${timeout_sec}s)" >&2 else - rpt_color "$GREEN" "$label: OK elapsed=${elapsed}" + elapsed=$(awk "BEGIN{printf \"%.5f\", $_ns / 1000000000}") + if [[ $status -ne 0 ]]; then + rpt_color "$YELLOW" "$label: exit $status elapsed=${elapsed}s" >&2 + else + rpt_color "$GREEN" "$label: OK elapsed=${elapsed}s" >&2 + fi fi echo "$elapsed" } OUR_OUT="$OUT_DIR/$STEM.our.out" -OUR_TIME_FILE="$OUT_DIR/$STEM.our.time" TIMEOUT_SEC=60 [[ "$INPUT" == *"/performance/"* || "$INPUT" == *"/h_performance/"* ]] && TIMEOUT_SEC=300 -OUR_ELAPSED=$(run_and_time "our compiler" "$OUR_ELF" "$OUR_OUT" "$OUR_TIME_FILE" "$TIMEOUT_SEC") +OUR_ELAPSED=$(run_and_time "our compiler" "$OUR_ELF" "$OUR_OUT" "$TIMEOUT_SEC") # GCC 耗时直接读取基线数据,不重新运行 GCC_ELAPSED="N/A" @@ -305,7 +314,7 @@ rpt "$(printf '%-20s %s' 'GCC time:' "$GCC_ELAPSED")" if [[ "$GCC_ELAPSED" != "N/A" && "$GCC_ELAPSED" != "timeout" && "$OUR_ELAPSED" != "timeout" ]]; then OUR_S="${OUR_ELAPSED%s}" GCC_S="${GCC_ELAPSED%s}" - SPEEDUP=$(awk "BEGIN{if($OUR_S>0) printf \"%.3f\", $GCC_S/$OUR_S; else print \"inf\"}") + SPEEDUP=$(awk "BEGIN{if($OUR_S>0) printf \"%.5f\", $GCC_S/$OUR_S; else print \"inf\"}") rpt "$(printf '%-20s %sx' 'Speedup (gcc/ours):' "$SPEEDUP")" fi rpt "" diff --git a/scripts/usage.txt b/scripts/usage.txt new file mode 100644 index 0000000..7588d9d --- /dev/null +++ b/scripts/usage.txt @@ -0,0 +1,103 @@ +============================================================ + 脚本优化总结(2026-04) +============================================================ + +一、架构分离 +──────────────────────────────────────────────────────────── +· run_baseline.sh 成为唯一负责计算 GCC -O2 基线的脚本; + 其余所有脚本(lab3_build_test.sh、analyze_case.sh)只读 + TSV,不再重复运行 GCC,避免重复耗时。 + +· 基线输出目录镜像测试用例的相对路径结构,例如: + output/baseline/test_case/functional/65_color.gcc.s + output/baseline/class_test_case/h_functional/11_BST.gcc.s + TSV 键与目录结构对齐:class_test_case/h_functional/11_BST + +二、SysY → C 编译兼容性修复(run_baseline.sh) +──────────────────────────────────────────────────────────── +· const int 全局数组维度问题 + C 模式下 const int N=10; int a[N]; 属于 VLA(非法于文件域)。 + 用 Python3 预处理将 const int NAME=EXPR; 转换为: + #define NAME ((int)(EXPR)) + 同时支持多声明符写法:const int A=1, B=2; + +· sylib 链接方式 + 预编译 sylib.o(-x c),用 -include sylib.h 注入声明; + 链接命令用 -x none 在 .o 前重置语言标志,防止 ELF 被 + 当作 C 源文件解析(stray '\177' 错误)。 + +· C++ 关键字冲突 + 部分 SysY 测试用例用 delete/new/class 作函数名; + -x c 模式下这些不是关键字,编译正常通过。 + +· 枚举浮点值 + enum { MAX = 1e9 }; 枚举成员必须是整数常量,Python3 + 预处理同样将其转为 #define MAX ((int)(1e9))。 + +三、计时精度与准确性 +──────────────────────────────────────────────────────────── +· 全面弃用 /usr/bin/time:非零退出时会向输出文件写入 + "Command exited with non-zero status N",污染时间值。 + +· 改用 date +%s%N 纳秒手动计时: + _t0=$(date +%s%N) + ... 运行命令 ... + _t1=$(date +%s%N) + elapsed=$(awk "BEGIN{printf \"%.5f\", $((t1-t0)) / 1e9}") + +· 所有时间输出统一为 5 位小数(秒),加速比同样 5 位小数。 + +四、分段计时(verify_asm.sh + lab3_build_test.sh) +──────────────────────────────────────────────────────────── +· verify_asm.sh 新增 --timing-out 选项,运行结束后 + 向文件写入: + compile_ns=<纳秒> + run_ns=<纳秒> + +· lab3_build_test.sh 读取 timing 文件,将编译耗时与运行耗时 + 分开显示: + PASS test_case/functional/65_color [compile=0.31416s run=0.18804s] + +· 加速比只使用运行时间(run_ns),排除编译器启动开销。 + +五、性能排行榜(lab3_build_test.sh) +──────────────────────────────────────────────────────────── +· 测试结束后输出双排序表格: + Sort 1:加速比升序(最需优化的用例排最前) + Sort 2:我方用时降序(绝对耗时最高的排最前) + 每行格式: + <用例名> <我方时间> <加速比>x + +六、analyze_case.sh 修复 +──────────────────────────────────────────────────────────── +· 基线查找键从裸 stem(65_color)改为完整路径键 + (test_case/functional/65_color),与 TSV 格式对齐, + 消除 "WARNING: no baseline entry" 误报。 + +· run_and_time 函数的 rpt_color 输出重定向到 stderr, + 防止 ANSI 转义码被命令替换($())捕获后传入 awk, + 消除 "fatal: error: invalid character '\033'" 错误。 + +============================================================ + 脚本列表 +============================================================ + +run_baseline.sh 计算所有用例的 GCC -O2 基线,结果存入 + output/baseline/gcc_timing.tsv + 用法: ./scripts/run_baseline.sh [--update] + --update 清空重算全部条目 + +lab3_build_test.sh 构建编译器,跑全部用例,输出加速比排行榜 + 用法: ./scripts/lab3_build_test.sh + +verify_asm.sh 验证单个用例的汇编正确性 + 用法: ./scripts/verify_asm.sh [input.in] \ + [expected.out] [timeout] [--timing-out file] + +analyze_case.sh 单用例深度分析(IR/ASM/计时/与基线对比) + 用法: ./scripts/analyze_case.sh [output_dir] + +clean_outputs.sh 清理 output/ 目录下的分析结果 + 用法: ./scripts/clean_outputs.sh + +============================================================