feat(backend): 完善课题 18 安全指令调度与 A/B Benchmark 报告 - #59
Mastttttter wants to merge 6 commits into
Conversation
🤖 AI Code Review
📁
|
| 指令类别 | 示例 | 延迟(拍) |
|---|---|---|
| 整数加法/逻辑 | add, and |
1 |
| 乘法 | mul |
3 |
| 内存访问 | lw, sw |
2 |
| 除法 | div |
16 |
| 分支/跳转 | beq, jal |
1 |
| ... | ... | ... |
同时 ret 在表格中占 1 拍但未单独列出,建议补上或归入 "分支/跳转" 类并加注。
🟡 Section 8 — 验证检查缺少分支目标完整性
检查列表中有 "越过标签、调用、跳转等边界",但没有检查 分支目标本身是否被破坏。例如 beq a1, a2, done 中的 done 标签如果在排序中被移动或删除,分支会跳转到错误位置。Section 2 说标签留在原处,但 Section 8 的检查项应该显式覆盖这一点。
🟡 Section 9 — 新文件归属不明
schedule_semantics.py、schedule_model.py、schedule_verify.py 三个新文件未说明放在哪个包下。从上下文推测应在 scratchv/backend/,建议明确写出完整路径,避免实现时放错位置。
💭 Section 6 — 建议补充公式
优先级计算的文字描述准确,但增加一行公式会更清晰:
priority[i] = latency[i] + max(priority[j] for j in successors(i), default=0)
并注明确认:ret / nop 这类无后继的指令,priority = latency 本身。
💭 Section 7 — 同速排序时的平局策略
"只有新顺序更快才使用;一样快或更慢就保留原序" — 如果多条合法排序耗时相同但移动数量不同,是否偏好移动更少的?这在 debug 时会有用。建议补充一条平局策略。
💭 LLVM 行号引用
多处引用本地 LLVM 源码的精确行号(如 ScheduleDAGInstrs.cpp:303)。如果 LLVM 版本更新,行号会漂移。建议改为引用函数名 + 文件路径,行号作为辅助信息。
总体评价
文档技术准确性高,bug 分析有据可查,LLVM 对比恰当。上述问题都是文档完备性层面的改进,不涉及方案方向性错误。
📁 scratchv/backend/__init__.py
This change looks clean — straightforward re-export addition, no issues found.
🟡 Minor: consider grouping related exports — Lines 41-44: ScheduleConfig, ScheduleResult, schedule_assembly are appended after machine_instrs_from_scheduled but before ExtendedInstructionSelector. Since they're from the same .inst_scheduler module, consider whether the __all__ order should mirror the import order for consistency (currently it does, which is good). No action needed — just noting the pattern is consistent.
📁 scratchv/backend/schedule_verify.py
🔴 KeyError: DAG check can crash on missing instructions — Lines 44–45:
positions[pred.inst.id] raises a raw KeyError if a DAG-referenced ID isn't in the candidate. Wrap with a ScheduleError or validate that all DAG instruction IDs are a subset of positions.keys() beforehand.
try:
pred_pos, node_pos = positions[pred.inst.id], positions[node.inst.id]
except KeyError as e:
raise ScheduleError(f"DAG references missing instruction: {e}") from None🟡 Silent no-op when dag is empty — Line 21:
Dependency-order verification is skipped entirely when dag=(). If a caller forgets to pass it, ordering bugs go undetected. Consider making dag required, or at minimum asserting dag is non-empty when the schedule is non-empty.
🟡 Unannotated local variable — Line 11:
reads = {} bypasses the type checker. Use:
reads: dict[tuple[str, str], int | None] = {}This also makes the "None means incoming value" contract explicit in the type.
🟡 Imprecise return annotation — Line 8:
tuple[dict, dict] hides the actual structure. Prefer:
tuple[dict[tuple[str, str], int | None], dict[str, int]]💭 Docstring could name the invariants checked — Line 18:
"Reject changes to identity, boundaries, register values or effects" is good but skims over the DAG-order and pinned-instruction checks. A bullet list of the 6–7 invariant categories would make it a better API contract.
⚠️ 未审查的文件
- scratchv/compiler.py
- scratchv/main.py
- tests/test_inst_scheduler.py
- tests/test_inst_scheduler_integration.py
- tests/test_inst_scheduler_report.py
- tests/test_inst_scheduler_safety.py
概述
完善课题 18 的局部指令调度器,修复汇编信息丢失、依赖遗漏和周期估算无法反映调度收益的问题。补充调度校验、编译器集成、实际执行验证及 CI Benchmark 报告。
主要改动
Benchmark 报告
参照 PR #35 的同输入 A/B 报告方式,将固定功能用例、实际编译输出和合成规模测试分别展示。
固定用例与真实执行
同一份汇编分别通过 CompilerDriver 的调度关闭和开启配置,再将前后汇编编码并使用真实 TinyFive 执行。
指标 调度前 调度后
━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━ ━━━━━━━━
源汇编指令数 4 4
───────────────────────── ──────── ────────
局部模型周期(估算) 5 4
───────────────────────── ──────── ────────
局部模型停顿(估算) 1 0
───────────────────────── ──────── ────────
编码机器指令数 4 4
───────────────────────── ──────── ────────
代码大小(字节) 16 16
───────────────────────── ──────── ────────
TinyFive 实际执行指令数 4 4
模型周期下降表示调度填补了 load-use 等待,不代表硬件实测加速。
CNN 汇编静态 A/B
对现有 CNN 编译步骤产生的同一份汇编切换调度开关,保留零收益及跳过结果。
当前 CNN 列表包含数字分支偏移,触发调度器的整份输入保留规则:
该结果用于展示当前支持范围,不声称已经完成 CNN 端到端执行验证或取得性能提升。
合成规模测试与 CI
本地验证
当前范围
调度在寄存器分配后的汇编阶段进行,仅在合法局部区域内移动指令。候选顺序必须通过校验,且在同一模型下严格减少周期才会被采用。
周期统计是局部静态估算;优化器耗时是主机执行调度 pass 的时间,两者均不作为目标程序硬件运行时间。