|  | # LLVM source-based code coverage | 
|  |  | 
|  | <!-- toc --> | 
|  |  | 
|  | `rustc` supports detailed source-based code and test coverage analysis | 
|  | with a command line option (`-C instrument-coverage`) that instruments Rust | 
|  | libraries and binaries with additional instructions and data, at compile time. | 
|  |  | 
|  | The coverage instrumentation injects calls to the LLVM intrinsic instruction | 
|  | [`llvm.instrprof.increment`][llvm-instrprof-increment] at code branches | 
|  | (based on a MIR-based control flow analysis), and LLVM converts these to | 
|  | instructions that increment static counters, when executed. The LLVM coverage | 
|  | instrumentation also requires a [Coverage Map] that encodes source metadata, | 
|  | mapping counter IDs--directly and indirectly--to the file locations (with | 
|  | start and end line and column). | 
|  |  | 
|  | Rust libraries, with or without coverage instrumentation, can be linked into | 
|  | instrumented binaries. When the program is executed and cleanly terminates, | 
|  | LLVM libraries write the final counter values to a file (`default.profraw` or | 
|  | a custom file set through environment variable `LLVM_PROFILE_FILE`). | 
|  |  | 
|  | Developers use existing LLVM coverage analysis tools to decode `.profraw` | 
|  | files, with corresponding Coverage Maps (from matching binaries that produced | 
|  | them), and generate various reports for analysis, for example: | 
|  |  | 
|  | <img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" | 
|  | src="img/llvm-cov-show-01.png" class="center"/> | 
|  | <br/> | 
|  |  | 
|  | Detailed instructions and examples are documented in the | 
|  | [rustc book][rustc-book-instrument-coverage]. | 
|  |  | 
|  | [llvm-instrprof-increment]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic | 
|  | [coverage map]: https://llvm.org/docs/CoverageMappingFormat.html | 
|  | [rustc-book-instrument-coverage]: https://doc.rust-lang.org/nightly/rustc/instrument-coverage.html | 
|  |  | 
|  | ## Recommended `bootstrap.toml` settings | 
|  |  | 
|  | When working on the coverage instrumentation code, it is usually necessary to | 
|  | **enable the profiler runtime** by setting `profiler = true` in `[build]`. | 
|  | This allows the compiler to produce instrumented binaries, and makes it possible | 
|  | to run the full coverage test suite. | 
|  |  | 
|  | Enabling debug assertions in the compiler and in LLVM is recommended, but not | 
|  | mandatory. | 
|  |  | 
|  | ```toml | 
|  | # Similar to the "compiler" profile, but also enables debug assertions in LLVM. | 
|  | # These assertions can detect malformed coverage mappings in some cases. | 
|  | profile = "codegen" | 
|  |  | 
|  | [build] | 
|  | # IMPORTANT: This tells the build system to build the LLVM profiler runtime. | 
|  | # Without it, the compiler can't produce coverage-instrumented binaries, | 
|  | # and many of the coverage tests will be skipped. | 
|  | profiler = true | 
|  |  | 
|  | [rust] | 
|  | # Enable debug assertions in the compiler. | 
|  | debug-assertions = true | 
|  | ``` | 
|  |  | 
|  | ## Rust symbol mangling | 
|  |  | 
|  | `-C instrument-coverage` automatically enables Rust symbol mangling `v0` (as | 
|  | if the user specified `-C symbol-mangling-version=v0` option when invoking | 
|  | `rustc`) to ensure consistent and reversible name mangling. This has two | 
|  | important benefits: | 
|  |  | 
|  | 1. LLVM coverage tools can analyze coverage over multiple runs, including some | 
|  | changes to source code; so mangled names must be consistent across compilations. | 
|  | 2. LLVM coverage reports can report coverage by function, and even separates | 
|  | out the coverage counts of each unique instantiation of a generic function, | 
|  | if invoked with multiple type substitution variations. | 
|  |  | 
|  | ## The LLVM profiler runtime | 
|  |  | 
|  | Coverage data is only generated by running the executable Rust program. `rustc` | 
|  | statically links coverage-instrumented binaries with LLVM runtime code | 
|  | ([compiler-rt][compiler-rt-profile]) that implements program hooks | 
|  | (such as an `exit` hook) to write the counter values to the `.profraw` file. | 
|  |  | 
|  | In the `rustc` source tree, | 
|  | `library/profiler_builtins` bundles the LLVM `compiler-rt` code into a Rust library crate. | 
|  | Note that when building `rustc`, | 
|  | `profiler_builtins` is only included when `build.profiler = true` is set in `bootstrap.toml`. | 
|  |  | 
|  | When compiling with `-C instrument-coverage`, | 
|  | [`CrateLoader::postprocess()`][crate-loader-postprocess] dynamically loads | 
|  | `profiler_builtins` by calling `inject_profiler_runtime()`. | 
|  |  | 
|  | [compiler-rt-profile]: https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/profile | 
|  | [crate-loader-postprocess]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/creader/struct.CrateLoader.html#method.postprocess | 
|  |  | 
|  | ## Testing coverage instrumentation | 
|  |  | 
|  | [(See also the compiletest documentation for the `tests/coverage` | 
|  | test suite.)](./tests/compiletest.md#coverage-tests) | 
|  |  | 
|  | Coverage instrumentation in the MIR is validated by a `mir-opt` test: | 
|  | [`tests/mir-opt/coverage/instrument_coverage.rs`]. | 
|  |  | 
|  | Coverage instrumentation in LLVM IR is validated by the [`tests/coverage`] | 
|  | test suite in `coverage-map` mode. | 
|  | These tests compile a test program to LLVM IR assembly, and then | 
|  | use the [`src/tools/coverage-dump`] tool to extract and pretty-print the | 
|  | coverage mappings that would be embedded in the final binary. | 
|  |  | 
|  | End-to-end testing of coverage instrumentation and coverage reporting is | 
|  | performed by the [`tests/coverage`] test suite in `coverage-run` mode, | 
|  | and by the [`tests/coverage-run-rustdoc`] test suite. | 
|  | These tests compile and run a test program with coverage | 
|  | instrumentation, then use LLVM tools to convert the coverage data into a | 
|  | human-readable coverage report. | 
|  |  | 
|  | > Tests in `coverage-run` mode have an implicit `//@ needs-profiler-runtime` | 
|  | > directive, so they will be skipped if the profiler runtime has not been | 
|  | > [enabled in `bootstrap.toml`](#recommended-configtoml-settings). | 
|  |  | 
|  | Finally, the [`tests/codegen/instrument-coverage/testprog.rs`] test compiles a simple Rust program | 
|  | with `-C instrument-coverage` and compares the compiled program's LLVM IR to | 
|  | expected LLVM IR instructions and structured data for a coverage-enabled | 
|  | program, including various checks for Coverage Map-related metadata and the LLVM | 
|  | intrinsic calls to increment the runtime counters. | 
|  |  | 
|  | Expected results for the `coverage`, `coverage-run-rustdoc`, | 
|  | and `mir-opt` tests can be refreshed by running: | 
|  |  | 
|  | ```shell | 
|  | ./x test coverage --bless | 
|  | ./x test coverage-run-rustdoc --bless | 
|  | ./x test tests/mir-opt --bless | 
|  | ``` | 
|  |  | 
|  | [`tests/mir-opt/coverage/instrument_coverage.rs`]: https://github.com/rust-lang/rust/blob/master/tests/mir-opt/coverage/instrument_coverage.rs | 
|  | [`tests/coverage`]: https://github.com/rust-lang/rust/tree/master/tests/coverage | 
|  | [`src/tools/coverage-dump`]: https://github.com/rust-lang/rust/tree/master/src/tools/coverage-dump | 
|  | [`tests/coverage-run-rustdoc`]: https://github.com/rust-lang/rust/tree/master/tests/coverage-run-rustdoc | 
|  | [`tests/codegen/instrument-coverage/testprog.rs`]: https://github.com/rust-lang/rust/blob/master/tests/mir-opt/coverage/instrument_coverage.rs |