SpyGlass 结果不确定抖动:同一 RTL 两次跑违例数不一致速查
更新时间:2026-10-22。FAQ 速查页,属于 EDA 工具排错系列,总入口见 开源 EDA 报错排错中心。SpyGlass(Synopsys 的 SpyGlass Lint/CDC/RDC)是 goal-based 的增量流程:读哪些文件、waiver 命中多少、license 是否够用,任何一环在两次运行之间发生变化,最终违例数就会抖。和「改了 RTL 结果却不变」的缓存陈旧互为镜像——那一篇讲结果该变不变,本篇讲输入没变结果却在变;缓存侧的机理见 SpyGlass 缓存陈旧速查,规则体系与 waiver 治理见 RTL 静态检查(Lint):SpyGlass 规则体系与基线门禁。
本文要回答的问题
- 同一份 RTL、同一条 filelist,连跑两次违例数却不同,是工具算错了吗?
- 本地 waiver 全部生效、CI 上同一批违例又冒出来,问题出在路径还是环境?
- filelist 用
*.v通配符,为什么换台机器读入顺序就变了? - 两个回归任务同时跑一个工程目录,会互相污染结果吗?
- 怎么用一次「全清重跑 + 读入清单对拍」把抖动根因收敛到一类?
一、现象与日志
结果不确定抖动的典型特征是:命令都退出 0,报告都正常产出,只有数字对不上。以下三组占位日志覆盖最高频的形态(工程名、机器名均为占位,各版本日志措辞以本单位安装版本为准):
1. 同一输入两次运行,违例总数与通过结论翻转:
# run A(昨天夜里回归)
Analyzed 87 files. Waivers applied: 214.
Goal lint/lint_rtl completed: 12 errors, 40 warnings -> FAIL
# run B(今天早上手动重跑,未改任何源码)
Analyzed 87 files. Waivers applied: 119.
Goal lint/lint_rtl completed: 8 errors, 35 warnings -> PASS注意第二行:文件数相同,waiver 命中数却少了 95 条——违例减少不是代码变好,而是该被 waive 的没被 waive。pass/fail 翻转的根源在 waiver,不在规则。
2. 读入文件清单随机器变化(通配符/软链作祟):
# run on node-a # run on node-b
Analyzing file rtl/alu.v ... Analyzing file rtl/axi_arb.v ...
Analyzing file rtl/fifo.v ... Analyzing file rtl/alu.v ...
Analyzing file rtl/uart.v ... Analyzing file rtl/fifo.v ...
Analyzed 87 files. Analyzing file rtl/uart.v ...
Analyzed 88 files. # 多出一个软链残留文件3. 并发任务互踩同一 work 目录,日志里夹杂交叉记录:
Warning: work directory './spyglass_work' is locked by another process (pid 20481)
Warning: proceeding without incremental database for goal lint/lint_rtl
Analyzing file rtl/fifo.v ... # 两个 pid 的 Analyzing 行交错出现
Analyzing file rtl/fifo.v ...二、原因速查表
| 现象 | 可能原因 | 处置 |
|---|---|---|
| 全清后稳定、不清就抖 | 增量缓存陈旧或混入旧分支产物 | 按缓存陈旧篇处置,切分支即清 work |
| 两次 waiver 命中数不同 | waiver 按绝对/相对路径匹配,启动目录不同导致失效 | waiver 统一用工程相对路径并规范化 |
| 文件数两次不同 | filelist 用通配符,目录内容随机器/分支变 | 显式列出每个文件,禁裸通配 |
| 文件数同、顺序不同 | 软链或通配展开顺序依赖文件系统 | 对读入清单排序后对拍 |
| 日志有 work locked 警告 | 多任务共用同一 work 目录并发互踩 | 每任务独立输出目录,串行化 |
| 本地好、CI 挂(或反之) | 版本/policy/环境变量 module 不一致 | 固定工具版本,CI 与本地同镜像 |
| CI 偶发缺违例/缺文件 | 浅克隆漏 submodule、稀疏检出漏文件 | CI 完整检出,清单行数与 filelist 对拍 |
| 跑到一半规则变少 | license 被抢占,部分 goal 静默降级/跳过 | 核对 checkout 记录,license 不足直接判失败 |
| 换行/大小写相关抖动 | 跨平台 CRLF、macOS/Windows 大小写不敏感 | 统一 LF、文件名全小写入库 |
| 临时目录每次不同 | $tmpdir 随机路径被 waiver/脚本硬编码引用 | 路径全部相对化,不引用随机目录 |
三、逐条排查展开
第一步判定性实验:全清 work 目录,串行重跑两次。 这是整条排查链的分水岭,一次实验把原因切成两大类。做法:删除 spyglass_work/、work/、<top>/<goal>/ 等可再生工作目录(只删产物、不删源码与 .prj,机理与目录清单见 SpyGlass 缓存陈旧速查),确认没有第二个任务在跑,用同一条命令连续执行两次,比对违例总数、各规则计数与 pass/fail 结论。两次全清结果一致、而带缓存时抖动——根因在缓存/并发侧;全清之后仍然不一致——根因在输入或环境,继续往下走。
颜色按语义分角色:红色是问题入口与仍未排除的输入侧分支,蓝色是排查动作,绿色是被干净重跑收敛掉的缓存/并发分支,橙色是修复手段,紫色是防复发纪律。读这张图抓住分水岭:全清串行重跑两次是唯一的判定节点,结果稳定走缓存侧处置,仍抖动才进入输入/环境的清单对拍,不要跳过这步直接怀疑工具。
第二步:对拍两次运行的「读入清单」与 waiver 命中数。 不要比违例总数——那是末端结果,要比就比工具实际看到的输入。从两次日志中分别抽出 Analyzing 文件列表(或报告目录里的 read_file 清单文件,部分版本会落盘),排序后做 diff:
grep -oE 'Analyzing file [^ ]+' run_a.log | awk '{print $3}' | sort > list_a.txt
grep -oE 'Analyzing file [^ ]+' run_b.log | awk '{print $3}' | sort > list_b.txt
diff list_a.txt list_b.txt清单行数不同,先查 filelist 里的通配符与软链:rtl/*.v 在不同机器、不同分支残留文件下展开结果不同,软链还会让同一文件以两个路径被读入两次。纪律是 filelist 显式列出每个文件、禁用裸通配,文件顺序也在 filelist 里写定。清单一致但 waiver 命中数不同,则是路径匹配问题:.awl 里的 waive 项常带文件路径,绝对路径在别人的工作区、CI 的随机检出目录下必然失配;启动目录不同时,相对路径也可能解析到别处。修法是 waiver 路径全部相对工程根(或使用版本提供的规范化路径选项),并在脚本里先 cd 到固定工程根再启动,签收纪律见 Lint waiver 签收与基线门禁。
第三步:排除并发互踩与随机目录。 两个回归任务共用一个 work 目录时,增量数据库可能被交替读写,日志出现 work locked 警告即判本次结果无效。修法是输出目录按任务分配(如 work/<job_id>/)或对同工程任务串行排队。同理,脚本里不要硬编码 /tmp/run_xxx 这类随机或复用路径再让 waiver 去引用它——临时目录每次解析到不同位置,waive 就时灵时不灵。
第四步:固定版本、policy 与环境,CI 与本地同镜像。 清单与 waiver 都对得上、结果仍随机器变,就到环境层对拍:工具小版本与补丁、规则 policy 文件、SPYGLASS_HOME 等环境变量、module 加载顺序,逐项记录成环境指纹随报告落盘。最彻底的做法是 CI 与本地用同一容器镜像、同一 module 版本。CI 侧还要专门核对检出完整性:浅克隆搭配 submodule 或稀疏检出时,filelist 列了但仓库里没有的文件可能被静默跳过;license 被抢占时部分版本会让 goal 降级或跳过——报告中规则数异常减少时,去 license 日志核对 checkout 记录,宁可直接判失败也不要接受降级结果。跨平台协作的团队另加两条:换行统一 LF、文件名全部小写入库,消除 CRLF 与大小写敏感性带来的随机性。
四、预防与纪律
- 不信结果先全清:任何「结果不对劲」的申诉,第一步都是全清 work、串行重跑两次,把缓存/并发与输入/环境切开。
- filelist 显式列文件:禁裸通配符、慎用软链;读入清单行数必须与 filelist 一致,清单随报告归档。
- waiver 路径相对化:统一相对工程根并规范化,启动目录在脚本里固定;命中数异常即查路径。
- 输出目录按任务隔离:同工程任务串行或各用独立 work 目录,work locked 警告直接判结果无效。
- 环境指纹随报告落盘:版本、policy、module、镜像 ID 可对拍;CI 全新完整检出,license 不足与降级一律 fail。
这一篇在知识体系里的位置
本篇是 EDA 排错速查簇中「确定性与复现」节点的 FAQ 页,总入口见 开源 EDA 报错排错中心;镜像问题「改了输入结果不变」走 SpyGlass 缓存陈旧速查,waiver 路径治理与签收流程见 Lint waiver 签收与基线门禁,规则体系与基线门禁的整体定位见 RTL 静态检查(Lint):SpyGlass 规则体系与基线门禁。
一句话总结
SpyGlass 结果不确定抖动先做判定性实验:全清 work、串行重跑两次——稳定即缓存陈旧或并发互踩,仍抖则对拍两次运行的读入文件清单与 waiver 命中数,依次收编通配符读入顺序、绝对路径 waiver 失配、版本环境漂移、CI 浅克隆与 license 降级;长期靠「显式 filelist、相对路径 waiver、独立输出目录、同镜像环境指纹、完整检出降级即 fail」五条纪律,让同输入必然同结果。