Skip to content

Code coverage support for Rust `no_std` and embedded programs

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

Amanieu/minicov

Repository files navigation

minicov

Crates.io Documentation

This crate provides code coverage and profile-guided optimization (PGO) support for no_std and embedded programs.

This is done through a modified version of the LLVM profiling runtime (normally part of compiler-rt) from which all dependencies on libc have been removed.

All types of instrumentation using the LLVM profiling runtime are supported:

  • Rust code coverage with -Cinstrument-coverage.
  • Rust profile-guided optimization with -Cprofile-generate.
  • Clang code coverage with -fprofile-instr-generate -fcoverage-mapping.
  • Clang profile-guided optimization with -fprofile-instr-generate.
  • Clang LLVM IR profile-guided optimization with -fprofile-generate.

Note that to profile both C and Rust code at the same time you must use Clang with the same LLVM version as the LLVM used by rustc. You can pass these flags to C code compiled with the cc crates using environment variables.

Usage

Note: This crate requires a recent nightly compiler.

  1. Ensure that the following environment variables are set up:
export RUSTFLAGS="-Cinstrument-coverage -Zno-profiler-runtime"

Note that these flags also apply to build-dependencies and proc macros by default. This can be worked around by explicitly specifying a target when invoking cargo:

# Applies RUSTFLAGS to everything
cargo build

# Doesn't apply RUSTFLAGS to build dependencies and proc macros
cargo build --target x86_64-unknown-linux-gnu
  1. Add the minicov crate as a dependency to your program:
[dependencies]
minicov = "0.3"
  1. Before your program exits, call minicov::capture_coverage with a sink (such as Vec<u8>) and then dump its contents to a file with the .profraw extension:
fn main() {
    // ...

    let mut coverage = vec![];
    unsafe {
        // Note that this function is not thread-safe! Use a lock if needed.
        minicov::capture_coverage(&mut coverage).unwrap();
    }
    std::fs::write("output.profraw", coverage).unwrap();
}

If your program is running on a different system than your build system then you will need to transfer this file back to your build system.

Sinks must implement the CoverageWriter trait. If the default alloc feature is enabled then an implementation is provided for Vec<u8>.

  1. Use a tool such as grcov or llvm-cov to generate a human-readable coverage report:
grcov output.profraw -b ./target/debug/my_program -s . -t html -o cov_report

Profile-guided optimization

The steps for profile-guided optimization are similar. The only difference is the flags passed in RUSTFLAGS:

# First run to generate profiling information.
export RUSTFLAGS="-Cprofile-generate -Zno-profiler-runtime"
cargo run --target x86_64-unknown-linux-gnu --release

# Post-process the profiling information.
# The rust-profdata tool comes from cargo-binutils.
rust-profdata merge -o output.profdata output.profraw

# Optimized build using PGO. minicov is not needed in this step.
export RUSTFLAGS="-Cprofile-use=output.profdata"
cargo build --target x86_64-unknown-linux-gnu --release

License

Licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

Code coverage support for Rust `no_std` and embedded programs

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published