Skip to content

Impl/topic09

Impl/topic09 #262

Workflow file for this run

name: CI
on:
push:
branches: [main, wjy_dev, jzj_dev]
pull_request:
branches: [main]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: read
jobs:
# ═════════════════════════════════════════════════════════════════════════
# 课题功能测试:所有14个模块的单元测试 + 集成测试
# ═════════════════════════════════════════════════════════════════════════
test:
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'self-hosted' }}
timeout-minutes: 20
steps:
- name: Checkout pull request on isolated runner
if: github.event_name == 'pull_request'
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false
- name: Set up Python for pull request
if: github.event_name == 'pull_request'
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Sync from local mirror (skip unstable GitHub checkout)
if: github.event_name != 'pull_request'
run: |
echo "=== CI Sync ==="
retry() {
local desc="$1" rc=0; shift
for i in 1 2 3; do
if "$@" --depth=1; then rc=0; break; fi
rc=$?
if [ "$i" -lt 3 ]; then
echo "::warning::$desc failed, retry #$i in $((i*3))s"
sleep $((i * 3))
else
echo "::error::$desc failed after 3 attempts"
fi
done
return $rc
}
MIRROR=/opt/ScratchV
WORKSPACE=/opt/actions-runner/_work/ScratchV/ScratchV
rm -rf "$WORKSPACE"
cp -a "$MIRROR" "$WORKSPACE"
cd "$WORKSPACE"
echo "Fetching origin main..."
retry "git fetch origin main" git fetch origin main || exit 1
echo "Checking out $GITHUB_SHA..."
if ! git -c advice.detachedHead=false checkout -f "$GITHUB_SHA"; then
echo "::warning::Checkout failed, fetching SHA directly from origin..."
git fetch origin "$GITHUB_SHA" || true
if git -c advice.detachedHead=false checkout -f "$GITHUB_SHA"; then
echo "::notice::Checkout successful after direct fetch: $(git log -1 --format='%h %ai %s')"
else
echo "::error::GITHUB_SHA ($GITHUB_SHA) not found — checkout failed"
exit 1
fi
else
echo "::notice::Checkout successful: $(git log -1 --format='%h %ai %s')"
fi
- name: Install dependencies
run: |
python3.12 -m pip install --upgrade pip
python3.12 -m pip install -e ".[all]"
python3.12 -m pip install "pytest>=7,<10"
# Includes Topic 9 parser, diagnostic, CLI and benchmark regression tests.
- name: Run all topic tests
run: |
mkdir -p benchmark_reports
python3.12 -m pytest tests/ -v --tb=short \
--junit-xml=benchmark_reports/test_results.xml \
--ignore=tests/test_simulator.py
- name: Run assembly-beautifier regressions
run: |
python3.12 -m pytest \
tests/test_parser_for_beautifier.py \
tests/test_asm_beautifier_comments.py \
tests/test_asm_beautifier_formatting.py \
tests/test_asm_beautifier_integration.py \
tests/test_asm_beautifier_blackbox.py \
-v --tb=short
- name: Run constant-merge regressions
run: |
python3.12 -m pytest \
tests/test_const_merge.py \
tests/test_backend.py::TestConstMergeIntegration \
tests/test_simulator.py::TestStubProfiledMachine \
-v --tb=short
- name: Run PR #37 register-allocation regressions
run: |
python3.12 -m pytest tests/test_pr37_regression.py -v --tb=short
- name: Generate test visualization page
if: github.ref == 'refs/heads/main'
run: |
python3.12 scratchv/ci/test_page.py \
--junit benchmark_reports/test_results.xml \
-o benchmark_reports/tests.html
- name: Upload test reports
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: test-reports
path: |
benchmark_reports/test_results.xml
benchmark_reports/tests.html
retention-days: 30
# ═════════════════════════════════════════════════════════════════════════
# 模型性能测试:ONNX模型管线 + DSL用例 + CNN RISC-V编译
# ═════════════════════════════════════════════════════════════════════════
benchmark:
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'self-hosted' }}
timeout-minutes: 30
steps:
- name: Checkout pull request on isolated runner
if: github.event_name == 'pull_request'
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false
- name: Set up Python for pull request
if: github.event_name == 'pull_request'
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Sync from local mirror (skip unstable GitHub checkout)
if: github.event_name != 'pull_request'
run: |
echo "=== CI Sync ==="
retry() {
local desc="$1" rc=0; shift
for i in 1 2 3; do
if "$@" --depth=1; then rc=0; break; fi
rc=$?
if [ "$i" -lt 3 ]; then
echo "::warning::$desc failed, retry #$i in $((i*3))s"
sleep $((i * 3))
else
echo "::error::$desc failed after 3 attempts"
fi
done
return $rc
}
MIRROR=/opt/ScratchV
WORKSPACE=/opt/actions-runner/_work/ScratchV/ScratchV
rm -rf "$WORKSPACE"
cp -a "$MIRROR" "$WORKSPACE"
cd "$WORKSPACE"
echo "Fetching origin main..."
retry "git fetch origin main" git fetch origin main || exit 1
echo "Checking out $GITHUB_SHA..."
if ! git -c advice.detachedHead=false checkout -f "$GITHUB_SHA"; then
echo "::warning::Checkout failed, fetching SHA directly from origin..."
git fetch origin "$GITHUB_SHA" || true
if git -c advice.detachedHead=false checkout -f "$GITHUB_SHA"; then
echo "::notice::Checkout successful after direct fetch: $(git log -1 --format='%h %ai %s')"
else
echo "::error::GITHUB_SHA ($GITHUB_SHA) not found — checkout failed"
exit 1
fi
else
echo "::notice::Checkout successful: $(git log -1 --format='%h %ai %s')"
fi
- name: Install dependencies
run: |
python3.12 -m pip install --upgrade pip
python3.12 -m pip install -e ".[all]"
python3.12 -m pip install markdown "pytest>=7,<10"
- name: Topic 9 DSL diagnostics benchmark
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
run: |
if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
echo "::error::No baseline commit available for DSL comparison."
exit 1
fi
git fetch origin "$BASE_SHA" --depth=1
BASELINE=$(mktemp -d "$RUNNER_TEMP/dsl-baseline.XXXXXX")
git worktree add --detach "$BASELINE" "$BASE_SHA"
trap 'git worktree remove --force "$BASELINE"' EXIT
python3.12 -m benchmarks.bench_dsl_diagnostics \
--baseline-root "$BASELINE" \
--json-output benchmark_reports/dsl_diagnostics.json \
--markdown benchmark_reports/dsl_diagnostics.md \
--html benchmark_reports/dsl_diagnostics.html
# ── 3.1 ONNX 模型管线基准测试 ──────────────────────────────────────
- name: ONNX model pipeline benchmarks
run: python3.12 -m pytest benchmarks/test_benchmark.py -v --tb=short
# ── 3.1.1 课题14:固定 case + 真实 TinyFive A/B 报告 ─────────────
- name: Topic 14 constant-merge case report
run: |
python3.12 benchmarks/run_const_merge_case.py \
benchmarks/cases/const_merge_feature.asm \
--json benchmark_reports/const_merge_report.json \
--markdown benchmark_reports/const_merge_report.md
# ── 3.2 DSL 用例编译 + 模拟基准 ────────────────────────────────────
- name: DSL case compilation benchmarks
run: |
mkdir -p benchmark_reports
python3.12 benchmarks/bench_runner.py benchmarks/cases \
--output-json benchmark_reports/dsl_bench.json \
--output-html benchmark_reports/dsl_bench.html \
--output-md benchmark_reports/dsl_bench.md
# ── 3.3 CNN RISC-V 编译 + 性能估算 ────────────────────────────────
- name: CNN RISC-V compilation & estimation
run: |
mkdir -p benchmark_reports models/graph
MODEL=models/graph/cnn.onnx
if [ ! -f "$MODEL" ]; then
echo "::warning::cnn.onnx not found, generating minimal CNN test model"
python3.12 scripts/gen_minimal_cnn.py 2>&1
fi
python3.12 scratchv/standalone/onnx_to_riscv_standalone.py \
"$MODEL" -o /tmp/cnn_riscv.bin \
--asm benchmark_reports/cnn_scratchv.s \
--estimate --report --const-merge
# ── 3.3.1 汇编美化器:真实 CNN 输出 + Actions Summary ───────────
- name: CNN assembly beautifier benchmark
run: |
python3.12 -m benchmarks.bench_asm_beautifier \
--input benchmark_reports/cnn_scratchv.s \
--output-asm benchmark_reports/cnn_pretty.s \
--markdown benchmark_reports/asm_beautifier_summary.md \
--json benchmark_reports/asm_beautifier_summary.json \
--repeats 20
# ── 3.4 LLVM vs ScratchV + TinyFive + Dashboard ──────────────────
- name: LLVM vs ScratchV comparison
run: |
mkdir -p benchmark_reports
# Generate ScratchV assembly if not already present
if [ ! -f benchmark_reports/cnn_scratchv.s ] && [ -f models/graph/cnn.onnx ]; then
python3.12 scratchv/standalone/onnx_to_riscv_standalone.py \
models/graph/cnn.onnx -o /tmp/cnn_riscv.bin \
--asm benchmark_reports/cnn_scratchv.s --estimate \
--const-merge 2>&1 | tail -3
fi
python3.12 scratchv/standalone/llvm_cache_compare.py \
--json-output benchmark_reports/llvm_vs_scratchv.json \
--markdown benchmark_reports/llvm_vs_scratchv.md \
|| echo "WARNING: llvm_cache_compare failed"
python3.12 scratchv/standalone/tinyfive_compare.py \
--json benchmark_reports/tinyfive_compare.json \
--markdown benchmark_reports/tinyfive_compare.md \
--scratchv-asm benchmark_reports/cnn_scratchv.s \
|| echo "WARNING: tinyfive_compare failed"
# ── 3.5 ONNX 模型拆分为单算子 ────────────────────────────────────
- name: Split CNN model into single operators
run: |
python3.12 scripts/split_cnn_to_single_ops.py \
|| echo "WARNING: split_cnn_to_single_ops failed"
# ── 3.6 单算子 benchmark ────────────────────────────────────────
- name: Single-operator benchmarks
run: |
python3.12 scripts/bench_single_ops.py \
|| echo "WARNING: bench_single_ops failed"
# ── 3.7 生成仪表盘 HTML (版本vsLLVM + 指令分类 + 算子对比) ─────
- name: Generate dashboard
run: |
python3.12 scratchv/ci/dashboard.py \
--llvm-json benchmark_reports/llvm_vs_scratchv.json \
--history-json benchmark_reports/optimization_history.json \
-o benchmark_reports/dashboard.html \
|| echo "WARNING: dashboard generation failed"
# ── 3.8 寄存器分配 benchmark(线性扫描:simple/dense/cnn + LLVM对比) ──
- name: Register allocation benchmarks
run: |
python3.12 -m benchmarks.test_regalloc.bench_regalloc_linear \
--repeats 30 \
--output-json benchmark_reports/regalloc_bench.json \
--output-html benchmark_reports/regalloc_bench.html \
--output-md benchmark_reports/regalloc_bench.md
# ── 上报 ──────────────────────────────────────────────────────────
- name: Upload benchmark reports
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: benchmark-reports
path: benchmark_reports/
retention-days: 30
# ── 保留推广主页(docs/ScratchV.html 不会被顶替) ────────────────
- name: Copy promotional page into Pages artifact
if: github.ref == 'refs/heads/main'
run: cp docs/ScratchV.html benchmark_reports/ScratchV.html
# ── 文档课程 HTML 站点 ──────────────────────────────────────────────
- name: Build docs HTML course site
if: github.ref == 'refs/heads/main'
run: |
python3.12 -m pip install markdown
python3.12 scripts/build_docs_html.py --output-dir benchmark_reports/docs
echo "Docs site built: benchmark_reports/docs/index.html"
# ── 优化历史页面 ──────────────────────────────────────────────────
- name: Generate optimization history page
if: github.ref == 'refs/heads/main'
run: python3.12 scratchv/ci/history_page.py -o benchmark_reports/history.html
# ── 测试可视化页面 ────────────────────────────────────────────────
- name: Generate test visualization page
if: github.ref == 'refs/heads/main'
run: |
python3.12 scratchv/ci/test_page.py \
--junit benchmark_reports/test_results.xml \
-o benchmark_reports/tests.html
# ── 精简 Pages 产物(移除大型编译产物) ──────────────────────────
- name: Clean large binaries before Pages deploy
if: github.ref == 'refs/heads/main'
run: |
rm -f benchmark_reports/*.bin benchmark_reports/*.elf
rm -f benchmark_reports/*.ll
rm -f benchmark_reports/cnn.onnx_*
rm -f benchmark_reports/_ll_* benchmark_reports/_sv.*
echo "Cleaned large binaries from Pages artifact"
# ── 上传 Pages 产物 ──────────────────────────────────────────────
- name: Upload Pages artifact
if: github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
with:
path: benchmark_reports/
- name: Write job summary
if: always()
run: |
if [ -f benchmark_reports/dsl_diagnostics.md ]; then
cat benchmark_reports/dsl_diagnostics.md >> "$GITHUB_STEP_SUMMARY"
fi
if [ -f benchmark_reports/const_merge_report.md ]; then
cat benchmark_reports/const_merge_report.md >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f benchmark_reports/github_summary.md ]; then
cat benchmark_reports/github_summary.md >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f benchmark_reports/asm_beautifier_summary.md ]; then
cat benchmark_reports/asm_beautifier_summary.md >> "$GITHUB_STEP_SUMMARY"
fi
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "### LLVM vs ScratchV" >> $GITHUB_STEP_SUMMARY
if [ -f benchmark_reports/llvm_vs_scratchv.md ]; then
tail -20 benchmark_reports/llvm_vs_scratchv.md >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Register Allocation Benchmarks" >> $GITHUB_STEP_SUMMARY
if [ -f benchmark_reports/regalloc_bench.md ]; then
cat benchmark_reports/regalloc_bench.md >> $GITHUB_STEP_SUMMARY
fi
# ═════════════════════════════════════════════════════════════════════════
# GitHub Pages 部署 (仅 main 分支)
# ═════════════════════════════════════════════════════════════════════════
deploy-pages:
needs: benchmark
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4