ARTICLE DETAIL

资讯详情

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

如何用 rustc -C instrument-coverage 生成 Rust 源代码覆盖率报告?

如何用 rustc -C instrument-coverage 生成 Rust 源代码覆盖率报告? 如何用 rustc -C instrument-coverage 生成 Rust 源代码覆盖率报告【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust这篇文章解决一个具体任务用 Rust 编译器标志-C instrument-coverage编译你的 Rust 程序运行它产生原始覆盖率数据再用 LLVM 覆盖率工具把这些数据转成可读的源代码覆盖率报告汇总百分比 逐行/逐区域的命中情况。该功能基于 LLVM 的 instrumentation-based coverage 实现编译器在代码中的函数与分支处注入llvm.instrprof.increment内建函数调用来递增计数器并把覆盖映射标记源码中被统计区域的起止位置嵌入二进制的数据段。程序正常退出时计数器值会写入profraw文件之后由llvm-profdata和llvm-cov两个 LLVM 工具完成合并与报告生成。文档正文见 rustc 手册 instrument-coverage 章节。前提条件profiler runtime 与 LLVM 工具编译器必须带 profiler runtime-C instrument-coverage依赖 Rust 的 profiler runtime。没有它用该标志编译会直接报 profiler runtime 缺失的错误。如果你用的是nightly发行通道profiler runtime 默认已包含。如果你是从源码构建 Rust 编译器本仓库即是默认的bootstrap.example.toml中并未启用 profiler runtime需要在bootstrap.toml中显式打开放在[build]段或某个[target.triple]配置下# Build the profiler runtime (required when compiling with options that depend # on this runtime, such as -C profile-generate or -C instrument-coverage). profiler true从源码构建场景下的更完整配置含编译器与 LLVM 的调试断言用于在部分情况下检测格式错误的覆盖映射可参考 rustc-dev-guide 的 LLVM coverage 文档# Similar to the compiler profile, but also enables debug assertions in LLVM. # These assertions can detect malformed coverage mappings in some cases. profile codegen # IMPORTANT: This tells the build system to build the LLVM profiler runtime. # Without it, the compiler cant produce coverage-instrumented binaries, # and many of the coverage tests will be skipped. build.profiler true # Enable debug assertions in the compiler. rust.debug-assertions true安装 llvm-profdata 和 llvm-cov处理覆盖率数据需要 LLVM 提供的两个工具llvm-profdata合并原始 profile和llvm-cov生成报告。文档给出的约束是Rust 编译器生成的覆盖映射数据要求 LLVM 12 或更高版本处理profraw原始数据可能需要与编译器所用 LLVM 完全一致的版本。可以先用llvm-cov --version查看工具侧的 LLVM 版本用rustc --verbose --version查看编译器所用的 LLVM 版本两边对照。获取工具的途径文档列出的选项通过rustup组件llvm-tools-preview安装配套版本——文档推荐的路径该组件的具体工具接口目前不受 Rust 常规稳定性保证约束从操作系统发行版或 LLVM 官方发行版安装兼容版本如果你从源码构建了 Rust 编译器可直接使用随构建一起编译出的 LLVM 工具二进制通常位于构建平台目录例如rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*。可选安装符号去修饰器 rustfiltLLVM 覆盖率工具报告中的函数名使用的是编译器的 mangled 形式难以阅读。LLVM 工具支持用户指定一个去修饰器demangler文档给出的 Rust 选项是rustfiltcargo install --locked rustfilt用覆盖率插桩编译项目在项目目录下设置-C instrument-coverage编译器标志即可启用。用cargo编译时RUSTFLAGS-C instrument-coverage会同时给程序二进制和它的依赖做插桩$ cd your-project $ cargo clean $ RUSTFLAGS-C instrument-coverage cargo build如果 cargo 当前使用的rustc不是带 profiler runtime 的版本例如你从源码构建的 stage1用RUSTC环境变量显式指定路径。文档以json5formatcrate 为例$ RUSTC$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \ RUSTFLAGS-C instrument-coverage \ cargo build --example formatjson5两点说明该标志支持可选取值-C instrument-coverageyes或不带值默认行为插桩所有函数包括未调用过的函数和泛型、-C instrument-coverageno等同于不使用该标志、-C instrument-coverageall目前是yes的别名文档建议暂不使用。-C instrument-coverage会自动启用-C symbol-mangling-versionv0v0 mangler 被强烈建议以保证多次编译间符号一致支撑跨运行分析和按实例化统计泛型函数。如确需回退可用-Z unstable-options -C symbol-mangling-versionlegacy覆盖。文档提醒某些编译器选项与-C instrument-coverage组合会产出不兼容的 LLVM IR 或链接产物。覆盖分析要求 LLVM IR 中存在对真实函数的引用——如果某个被覆盖的函数被优化掉覆盖率工具可能无法处理结果。需要额外传选项时应尽早测试确认能得到预期的覆盖率结果。运行插桩二进制生成 .profraw 原始数据运行插桩后的程序程序结束时计数器会写入当前工作目录下的一个profraw文件文件名形如default_签名_进程号.profraw每次运行生成唯一文件名以避免覆盖旧数据。文档示例json5formatcrate 的 example 二进制$ echo {some: thing} | target/debug/examples/formatjson5 -运行后确认 profraw 已生成$ ls default_*.profraw default_11699812450447639123_0_20944.profraw上面文件名来自文档示例11699812450447639123_0是插桩二进制的签名20944是进程号。你的实际文件名会不同。如果想控制输出文件用环境变量LLVM_PROFILE_FILE指定文件名或路径。路径中不存在的目录会被自动创建。支持的特殊模式串%p— 进程 ID%h— 运行程序的主机名%t—TMPDIR环境变量的值%Nm— 插桩二进制的签名运行时创建 N 个 raw profile 的池用于在线合并N取值 1–9省略 N写成%m时默认为 1%c— 不改变文件名但在部分平台含 Darwin启用持续同步计数器到文件的模式程序崩溃或被信号杀死时仍可恢复覆盖率信息。示例$ echo {some: thing} \ | LLVM_PROFILE_FILEformatjson5.profraw target/debug/examples/formatjson5 - $ ls formatjson5.profraw formatjson5.profraw默认值是LLVM_PROFILE_FILEdefault_%m_%p.profraw。文档特别提醒1.65 之前的版本默认是default.profraw如果用那些版本建议显式设置LLVM_PROFILE_FILEdefault_%m_%p.profraw避免多个测试二进制互相覆盖 profraw 文件。合并原始数据并生成覆盖率报告用 llvm-profdata merge 建索引profraw必须先索引才能用于生成报告由llvm-profdata merge完成它可以同时合并多个原始 profile$ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata用 llvm-cov 生成报告llvm-cov report生成覆盖率汇总llvm-cov show把行与区域字符区间的命中情况叠加在原源代码上展示并与二进制内嵌的覆盖映射配合使用。文档示例-name指定只看某个精确函数名也可改用--name-regexpattern过滤$ llvm-cov show -Xdemanglerrustfilt target/debug/examples/formatjson5 \ -instr-profileformatjson5.profdata \ -show-line-counts-or-regions \ -show-instantiations \ -nameadd_quoted_string这条命令中各参数的作用--Xdemanglerrustfilt— 用于去修饰 Rust 符号的命令名或路径示例为rustfilttarget/debug/examples/formatjson5— 插桩后的二进制从中提取覆盖映射按你的实际构建产物替换--instr-profilepath.profdata— 上一步llvm-profdata merge生成的.profdata文件--show-line-counts-or-regions/--show-instantiations/--nameexact-function-name— 展示与过滤选项。读懂报告中的四种覆盖率统计覆盖率汇总里有四项统计Function coverage函数覆盖至少被执行过一次的函数占比。只要某个函数的任一实例化被执行过该函数就算被执行。Instantiation coverage实例化覆盖至少被执行过一次的函数实例化占比。泛型函数和宏生成的函数可能有多个实例化。Line coverage行覆盖至少被执行过一次的代码行占比。只有函数体内可执行的行才算代码行。Region coverage区域覆盖至少被执行过一次的代码区域占比。一个区域可跨多行例如没有控制流的大函数体反过来一行也可能包含多个区域——例如return x || (y z)中x、|| (y z)、return各是可统计的区域。四项中函数覆盖粒度最粗区域覆盖最细每个统计的全项目总量列在汇总里。可选分支用测试套件测量覆盖率文档指出覆盖分析最典型的用途就是测试覆盖既测出测试代码覆盖率百分比也能定位没被测试覆盖到的函数和分支。与上一节运行单个二进制的路径不同这里由cargo test同时构建并运行测试。$ RUSTFLAGS-C instrument-coverage \ cargo test --tests在测试输出里记下 Running 之后显示的行——那是各测试二进制的路径文档示例实际路径不同Running target/debug/deps/json5format-fececd4653271682 running 25 tests ... test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Running target/debug/deps/lib-30768f9c53506dc5 running 31 tests ... test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out此时每个测试二进制各产生一个.profraw合并它们$ llvm-profdata merge -sparse default_*.profraw -o json5format.profdata然后对每个测试二进制各传一个--object参数给llvm-cov。--ignore-filename-regex/.cargo/registry用于把依赖源码从覆盖率结果中排除$ llvm-cov report \ --use-color --ignore-filename-regex/.cargo/registry \ --instr-profilejson5format.profdata \ --object target/debug/deps/lib-30768f9c53506dc5 \ --object target/debug/deps/json5format-fececd4653271682 $ llvm-cov show \ --use-color --ignore-filename-regex/.cargo/registry \ --instr-profilejson5format.profdata \ --object target/debug/deps/lib-30768f9c53506dc5 \ --object target/debug/deps/json5format-fececd4653271682 \ --show-instantiations --show-line-counts-or-regions \ --Xdemanglerrustfilt | less -R如果多个测试二进制的手写--object参数容易出错文档给出了面向bash用户的自动化做法用同样的环境变量和标志给cargo test追加--no-run --message-formatjson用jq过滤出.profile.test true的条目、取出.filenames[]再拼出每个二进制的-object参数依赖jq。包含 doc tests上面用cargo test --tests会排除 doc tests。要把 doc tests 计入覆盖率去掉--tests并通过RUSTDOCFLAGS传入插桩与 doc-test 专用选项llvm-profdata命令不变$ RUSTFLAGS-C instrument-coverage \ RUSTDOCFLAGS-C instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins \ cargo test $ llvm-profdata merge -sparse default_*.profraw -o json5format.profdata其中-Z unstable-options --persist-doctests是必需的用来把带覆盖映射的 doc-test 二进制保存下来供llvm-cov使用。随后llvm-cov report需要把target/debug/doctestbins/*/rust_out中的可执行文件也作为-object传入注意部分rust_out可能不是可执行二进制文档用[[ -x $file ]]过滤。文档同时注明doc test 覆盖目前在llvm-cov show中会生成不正确的源码行号是仍在处理中的已知问题。其他限制与进阶选项单函数关闭插桩给函数标注coverage(off)attribute 可以对其单独禁用覆盖率插桩该 attribute 需要#![feature(coverage)]特性门。插桩级别不稳定选项-Z coverage-optionsoptions可控制插桩细节多个选项以逗号分隔。级别选项block默认插桩控制流图中的块、branch在块覆盖之上启用分支覆盖、condition在分支覆盖之上把部分布尔表达式也作为分支插桩即使它们没有直接用作分支条件后设的级别会覆盖先前指定的级别。详见 unstable-book 的 coverage-options 文档。验证插桩本身本仓库内还有用于验证插桩行为的测试与工具可用于理解与调试mir-opt测试 tests/mir-opt/coverage/instrument_coverage.rs 验证 MIR 中的插桩tests/codegen-llvm/instrument-coverage/testprog.rs将简单程序编译成 LLVM IR 并与预期的覆盖映射元数据、计数器内建调用指令比对tests/coverage与tests/coverage-run-rustdoc测试套件分别验证 LLVM IR 层的覆盖映射和端到端报告流程配套的提取工具见 src/tools/coverage-dump。完成以上步骤后你的验收依据是运行插桩二进制或测试套件后工作目录中出现default_*.profrawllvm-profdata merge产出一个.profdatallvm-cov report输出含四类统计的汇总llvm-cov show在源代码上叠加出行/区域命中数。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表