十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Slang 编译器覆盖率恢复实战:覆盖率棘轮与文档驱动变体展开的三步方法论

Slang 编译器覆盖率恢复实战:覆盖率棘轮与文档驱动变体展开的三步方法论 Slang 编译器覆盖率恢复实战覆盖率棘轮与文档驱动变体展开的三步方法论【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang导读本文复盘 Slang 仓库中一次针对自动生成测试套件docs/generated/tests/的隔夜覆盖率恢复行动在文档范围重新生成doc-scope regen导致 slangc 编译器行覆盖率静默跌落 3,351 行之后通过Step 1 覆盖率棘轮ratchet Step 2 变体矩阵广度展开 Step 3 深度发射展开三步方法论从低点恢复 1,257 行覆盖并把剩余缺口精确定位为文档受限doc-limited而非测试努力受限。读完本文你将掌握这套可复用的覆盖护栏工具的用法、文档驱动测试的硬性契约以及如何把一个覆盖率缺口转化为可执行的文档充实积压清单。一、背景一次被静默吞掉的覆盖率回退Slang 仓库的docs/generated/tests/是一套由文档驱动自动生成的测试套件详见 regenerate.md由_meta/regenerate.py驱动程序编排按 manifest 中的 44 个 bundle 组织分为conformance/锚定 docs/language-reference/ 语言规范、design/锚定 docs/generated/design/ 设计文档以及后补的coverage/白盒表征测试见 METHODOLOGY.md三棵树。2026 年 6 月的一次文档范围重新生成PR #11490 的后续暴露了一个严重问题recreate-to-doc-scope 步骤直接删除了 985 个单目标发射.slang文件566 个 spirv-asm、243 个 hlsl、68 个 metal、61 个 glsl、48 个 wgsl、12 个 cuda、1 个 torch及 ir-reference 测试导致覆盖 slangc 编译器的行覆盖率从53.10%134,016 行跌到 51.77%130,665 行净损失3,351 行——而整套 CI 没有任何一个环节失败。正如 coverage-history.md 记录的套件在 bootstrap、fork master 与 upstream masterPR #11421 之后之间的覆盖率对比表明上游 master 状态达到53.55% / 135,156 行是要超越的目标而本次回退正是由于删除的发射深度集中在slang-emit-spirv.cpp−671、slang-ir-glsl-legalize.cpp−640、slang-ir-spirv-legalize.cpp−144、slang-ir-legalize-varying−152等发射与合法化后端文件上。根因这一整轮事故之所以能不声不响地合入是因为缺失一件东西——对覆盖率的强制性护栏enforcement。这正是本次隔夜行动要补的缺口。二、三步方法论总览与覆盖率轨迹行动目标明确为do 1 then 2 then 3, commit each, coverage run after each, write an analysis on each step三步全部完成并各自提交、各自测量、各自产出一份分析报告即 analysis-step1.md、analysis-step2.md、analysis-step3.md。所有测量使用同一份带覆盖率插桩的libslang.sobuild/RelWithDebInfo/clang 基于源码的覆盖率仅切换测试套件git checkout commit -- docs/generated/tests/因此数字可直接比较。完整轨迹如下阶段行覆盖率已覆盖行数baseline重生成前53.10%134,016重生成后回退低点51.77%130,665 后端 fan-out更早52.00%131,242Step 2 —— 变体广度52.06%131,410Step 3 —— 深度发射52.27%131,922从低点累计恢复1,257 行约占丢失 3,351 行的 37%相对 baseline 仍差−2,094 行 / −0.83pp且该剩余缺口被证明是文档受限详见第五节。三、Step 1覆盖率棘轮——补上缺失的刹车Step 1 的交付物是 tools/coverage/coverage-floor.py 与 floors.json。这一步刻意不添加任何测试——它是后续 Step 2、3 的安全网guardrail而不是覆盖率本身。3.1 工具契约record/check两个子命令# 从某次 llvm-cov 报告的 TOTAL 行记录基准 python3 tools/coverage/coverage-floor.py record label-slangc-report.txt [--reason TEXT] # 检查某次报告是否低于已记录基准 python3 tools/coverage/coverage-floor.py check label-slangc-report.txt实现细节coverage-floor.pyparse_total读取 llvm-cov 文本报告的TOTAL行按列位置解析——Regions / MissedReg / Cov% / Func / MissedF / Exec% / Lines / MissedLines / Cov% / Branch / MissedBr / Cov%即列 1–2 为 regions列 7–8 为 lines列 10–11 为 branchescovered total − missed这与 llvm-cov 报告第二行数字是 missed 而非 covered 的陷阱一致。record将{lines_covered, lines_total, regions_covered, branches_covered}连同reason写入floors.jsoncheck解析当前报告后逐项比对任一指标低于基准即输出FAIL并exit 1达标 exit 0出错如找不到 TOTAL 行或未记录基准 exit 2。3.2 双向验证护栏确实生效分析文档记录了两种方向的验证结果用 Step 1 自身的报告 基准执行check→exit 0输出 coverage at or above floor用 fan-out 之前的低点报告130,665 行执行check→exit 1逐项报告lines_covered −577, regions −227, branches −249。也就是说如果当初重生成时就有这道闸门−3,351 行的跌落会在 CI 中被拦下而不是默默合入。3.3 设计取舍与注意事项套件级而非逐 bundle 级runner 已产出合并的套件总量逐 bundle 需要在各自 profile 中单独测量68 次独立运行。套件级足以捕获净回退且成本低逐 bundle 被留作未来可能的细化。基准可带理由重记录record --reason ...合法的编译器重构同样会移动覆盖率棘轮不能成为紧身衣。纪律是只有写下书面理由才能下调基准而不是永不下降。基准刻意低于 baselineStep 1 记录的是 131,242 行 当下状态先锁住不再继续下滑再由 Step 2、3 逐步上调基准。顺带一提仓库中当前提交的 floors.json 已进一步演进到lines_covered: 14172855.93% 行覆盖reason 为 master breadth depth white-box coverage suite——证明棘轮机制在隔夜行动之后仍被持续使用并随白盒表征套件coverage/树的加入继续抬高。四、Step 2变体矩阵规则与广度展开4.1 新方法论规则文档列举什么就测什么Step 2 在 _claims.md §2 Construct legalization variants (depth) 中固化了一条新规则当文档描述某个转换或发射、且其处理按输入的类型/形状/形式分叉时类型映射/布局表、opcode 或 decoration 列表、逐元素类型的数组步长、逐操作符的原子操作、逐地址空间的存储类别应当为文档枚举的每一行/每一个分支实例化一个测试而不是为整张表写一个测试。这条规则配套 _expand.md The hard rule展开代理不接收任何源行信息——看不到未覆盖行、文件 diff、百分比只能拿到 bundle 名、README、现有.slang文件与source_doc。原因是如果测试针对我们观察到未覆盖的源行来写就会把实现固化为规范侵蚀套件每条测试都映射到一个文档化断言的价值。这条限制关乎来源provenance而非广度——它禁止靠看未覆盖代码选测试但不禁止在权威表面language-reference 类型表、core-module 声明*.meta.slang确认某个变体族后系统性地实例化其成员。4.2 十个最薄 bundle 的广度展开Step 2 用regenerate.py expansion-candidates --from report.json按 bundle 的平均覆盖率打分、只输出 bundle key 分数、不泄漏源行细节排序出10 个最薄的设计 bundle包括pipeline/05-ir-passes、target-pipelines/{hlsl,cuda,spirv,metal}、cross-cutting/targets、pipeline/04-ast-to-ir、name-resolution/visibility、syntax-reference/keywords-and-builtins、pipeline/overview产出41 个测试168 行覆盖全部intentexpansion、CHECK 行钉在真实 slangc 输出上verify FAILED:0、lint 0/0。示例包括05-ir-passes的 3 个文档化 pass 行array-return-by-ref、reinterpret、defer、hlsl 的矩阵复合选择与只读 matrix 结构缓冲、cuda 的SV_*→threadIdx/blockIdx与 active-mask 合成、metal 12 个测试。4.3 关键发现文档天花板doc ceilingStep 2 最重要的结论不在测试数量而在那个数字本身41 个高质量测试只换来 168 行覆盖而且严格按文档工作的代理只找到2 处文档缺口。这不是代理不努力而是文档天花板——代理正确地展开了文档枚举的一切然后停下因为契约禁止发明文档不支持的断言。由此得出结论剩余约 2,600 行的缺口是 doc-limited文档受限不是 effort-limited测试努力受限。slang-emit-spirv−610、slang-ir-glsl-legalize−630、spirv-legalize−142等深分支由构造变体逐类型数组步长、完整原子操作矩阵、逐类型/逐形状的发射形式驱动而设计文档的简洁章节如spirv.md的 Phase D、GLSL 发射路径并未枚举这些变体——在文档描述它们之前无法写出契约合法的测试。这正是 Step 3 存在的原因。五、Step 3深度发射展开与文档充实积压5.1 深度优先胜过广度优先Step 3 在target-pipelines/{spirv,hlsl,metal,cuda,wgsl}五个 bundle 上做穷举式深度优先展开实例化每个文档可枚举的发射变体逐元素类型/形状/操作符并同时在共享 SPIR-V/GLSL 合法化路径上发射到 spirv-asm和glsl。产出79 个测试512 行覆盖是 Step 2 的 3 倍分布为 spirv 16完整原子操作族、bitcast、逐类型/形状的 ArrayStride、首批 GLSL 臂测试、hlsl 17、metal 10、cuda 16、wgsl 20。5.2 九项文档充实积压清单the actionable backlogStep 3 的代理把文档命名了通用规则但未枚举编译器实际分叉的变体族记录为## Doc gaps observed形成精确的9 项 doc-enrichment backlog#文档缺口编译器实际行为文档未覆盖的部分1SPIR-V 原子操作族文档只写了InterlockedAdd→OpAtomicIAdd代码实际处理 And/Or/Xor/Exchange/CompareExchange 及有符号/无符号 Min/Max 拆分OpAtomicSMin/UMin…2SPIR-V StructuredBuffer 的 std430 聚合布局文档只记录了 cbuffer 的*_std140StructuredBufferstruct实际发射带逐成员Offset的*_std430StorageBuffer 布局3HLSL 字节寻址 Load 依赖元素类型裸.Load原生 uint 字、模板化LoadT、逐分量向量分解三者行为不同4HLSL 复合选择composite-select文档只提 matrix/structarray 类型的条件表达式被同样改写但未列出5Metal 矩阵 device/structured 缓冲_MatrixStorage_包装只记录了 cbuffer但RWStructuredBufferfloat4x4也会被lowerBufferElementTypeToStorageType包装6Metal 原子操作数族比文档化的atomic_uint更宽atomic_int/ulong/long/floatdevice 与 threadgroup 两种地址空间half/double 在类型检查时被拒E361077CUDA Interlocked→atomic* 映射完整家族atomicAnd/Or/Xor/Min/Max/Exch/CAS 操作数类型 × 存储目标的正交组合远超文档化的atomicAdd8WGSL 数值宽度矩阵i64/u64 与 f16带enable f16;受支持且可观察double触发内部错误 abort而非干净诊断9WGSL 窄整型int16/uint16给出干净诊断 E56103int8/uint8触发内部错误 abort5.3 附带产出两个编译器 bug第 8、9 项不只是文档缺口而是编译器 bugWGSL 发射doubleunexpected: double type emitted与int8/uint8unexpected: 8 bit integer type emitted会命中内部错误 aborterror[E99997]: Slang compilation aborted due to an exception of N5Slang13InternalErrorEexit 255而不是像 16 位路径那样给出干净的不支持类型诊断。仓库的 findings 目录中已有对应的结构化记录可佐证types-double-member-metal-wgsl-emit-abort.yamldouble结构体成员发射到 Metal/WGSL 时 abortHLSL/GLSL/SPIR-V 均干净发射与 values-intcast-wgsl-8bit-internal-error.yaml同一 shader 在 spirv-asm/hlsl/glsl/metal 上干净发射仅 WGSL 后端 abort已归类为 wrong-diagnostic 而非 wrong-codegen。按 METHODOLOGY.md 的纪律——crash/abort/internal-error 是 finding永远不是测试——这两个 bug 没有转成测试abort 会导致失败而是留在 bundle 的 Untested/Doc-gaps 中等待通过_meta/findings/渠道提交。5.4 为什么剩余缺口要留给人工闭环剩余约 2,094 行是 doc-limited 的设计文档命名了通用规则但没有枚举编译器分叉的变体族。要闭合它必须先充实设计文档本身。但充实必须走 design-doc 重生成渠道docs/generated/design/是生成式源头不能在无人值守时手工编辑生成的 source-of-truth——那既是循环论证用同一输出同时写文档和测试又会破坏其 freshness/review provenance 契约。这一立场与 regenerate.md 的 hand-edit policy 完全一致.slang与 README 禁止手改正确动作是改进 prompt、改进源文档、或改进 manifest然后mark-fresh。六、结论与推荐后续动作方法论至此闭环且补上了此前缺失的关键一环深度 重读文档以枚举可枚举的变体Step 2 规则 对残余 bundle 深度优先展开Step 3 覆盖率棘轮守卫Step 1。文档扎根的深度在 52.27% 处已基本穷尽闭合最后 −0.83pp 需要先充实设计文档本身即 9 项积压清单这被刻意留给**人工在环human-in-the-loop**通过 design-doc 重生成渠道处理。分析文档给出的三条推荐后续动作执行 9 项积压的设计文档充实再做一轮最终展开——有望闭合大部分剩余的 −2,094 行把 2 个 WGSL 内部错误 abort 作为编译器 bug 提交通过_meta/findings/与regenerate.py findings file id流程把coverage-floor.py check接入 CI让棘轮真正被强制执行regenerate.py无第三方 Python 依赖接入只需一次python3调用。本次会话的提交位于2026-06-doc-update-1分支包括design 重生成 freshness、coverage runner、20 个后端 fan-out bundle、size-caps/INDEX、coverage-fanout 审计、Step 1棘轮、variant-matrix 规则、Step 210 个展开 bundle floor、Step 35 个深度展开 bundle floor。七、可继续深入的仓库资源覆盖率工具与数据tools/coverage/coverage-floor.py、floors.json、coverage-history.md三步分析报告analysis-step1.md、analysis-step2.md、analysis-step3.md方法论契约_claims.mdclaim 枚举 变体展开规则、_expand.mdhard rule 展开循环、CAMPAIGN.mdcampaign 编排、METHODOLOGY.md白盒表征树驱动与流程regenerate.mdregenerate.py全部子命令、Phase A–F 状态、hand-edit policy被深度展开的 bundle 示例target-pipelines/wgsl/README.md27 条 spelling claims、功能覆盖表、Untested claims 分类、Doc gaps observed 表编译器 bug findingstypes-double-member-metal-wgsl-emit-abort.yaml、values-intcast-wgsl-8bit-internal-error.yaml【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表