-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rust function-level coverage now works on external crates #74959
Conversation
Fixed a known issue in the coverage map where some regions had nonsensical source code locations. External crate functions are already included in their own coverage maps, per library, and don't need to also be added to the importing crate's coverage map. (In fact, their source start and end byte positions are not relevant to the importing crate's SourceMap.) The fix was to simply skip trying to add imported coverage info to the coverage map if the instrumented function is not "local". The injected counters are still relevant, however, and the LLVM `instrprof.increment` intrinsic call parameters will map those counters to the external crates' coverage maps, when generating runtime coverage data.
r? @eddyb (rust_highfive has picked a reviewer for you, use r? to override) |
r? @tmandry |
@wesleywiser FYI, here's the fix. |
@wesleywiser @tmandry As you can see in the example below, the external crate coverage maps are working, even for generics and inlined functions. My explanation in the initial PR comment is, to some degree, my "theory" on how this is working, but to be honest, I'm not entirely sure how counters called from monomorphized generics with types in an importing crate would correctly map the counter data to the right generic function in the dependent crate's coverage map. It might not. And if not, then some coverage results are missing. So, as discussed, I need to put together some more targeted tests to confirm what is or is not working with regard to cross-crate inline function instantiations. Then, if anything is missing, I'll work on implementing a resolution.
|
@bors r+ rollup |
📌 Commit 34b26d6 has been approved by |
🌲 The tree is currently closed for pull requests below priority 5, this pull request will be tested once the tree is reopened |
FYI, I scanned my results for specific examples of external crate generic functions showing results with different type parameters, and I wasn't able to find any good, clear examples. The results are too big, using my example off-the-shell crate, so it's hard to be sure of anything, but I will prioritize putting some more targeted tests together for this situation. In any case, the fix in this PR is still a win, since it allows running coverage instrumentation on an entire crate with dependencies, and produces clean results, for what we're able to instrument and map today. |
@tmandry @wesleywiser - Building on what I've learned here, I think I have a more complete solution. I currently take only the I can change the Rust intrinsic parameter arguments, from just the start and end byte (relative to the current |
☀️ Test successful - checks-actions, checks-azure |
…, r=wesleywiser Completes support for coverage in external crates Follow-up to rust-lang#74959 : The prior PR corrected for errors encountered when trying to generate the coverage map on source code inlined from external crates (including macros and generics) by avoiding adding external DefIds to the coverage map. This made it possible to generate a coverage report including external crates, but the external crate coverage was incomplete (did not include coverage for the DefIds that were eliminated. The root issue was that the coverage map was converting Span locations to source file and locations, using the SourceMap for the current crate, and this would not work for spans from external crates (compliled with a different SourceMap). The solution was to convert the Spans to filename and location during MIR generation instead, so precompiled external crates would already have the correct source code locations embedded in their MIR, when imported into another crate. @wesleywiser FYI r? @tmandry
…, r=wesleywiser Completes support for coverage in external crates Follow-up to rust-lang#74959 : The prior PR corrected for errors encountered when trying to generate the coverage map on source code inlined from external crates (including macros and generics) by avoiding adding external DefIds to the coverage map. This made it possible to generate a coverage report including external crates, but the external crate coverage was incomplete (did not include coverage for the DefIds that were eliminated. The root issue was that the coverage map was converting Span locations to source file and locations, using the SourceMap for the current crate, and this would not work for spans from external crates (compliled with a different SourceMap). The solution was to convert the Spans to filename and location during MIR generation instead, so precompiled external crates would already have the correct source code locations embedded in their MIR, when imported into another crate. @wesleywiser FYI r? @tmandry
…r=wesleywiser Completes support for coverage in external crates Follow-up to rust-lang#74959 : The prior PR corrected for errors encountered when trying to generate the coverage map on source code inlined from external crates (including macros and generics) by avoiding adding external DefIds to the coverage map. This made it possible to generate a coverage report including external crates, but the external crate coverage was incomplete (did not include coverage for the DefIds that were eliminated. The root issue was that the coverage map was converting Span locations to source file and locations, using the SourceMap for the current crate, and this would not work for spans from external crates (compliled with a different SourceMap). The solution was to convert the Spans to filename and location during MIR generation instead, so precompiled external crates would already have the correct source code locations embedded in their MIR, when imported into another crate. @wesleywiser FYI r? @tmandry
Follow-up to a known issue discussed (post-merge) in #74733:
Resolves a known issue in the coverage map where some regions had nonsensical source code locations.
External crate functions are already included in their own coverage maps, per library, and don't need to also
be added to the importing crate's coverage map. (In fact, their source start and end byte positions are not relevant to the importing crate's SourceMap.)
The fix was to simply skip trying to add imported coverage info to the coverage map if the instrumented function is not "local".
The injected counters are still relevant, however, and the LLVM
instrprof.increment
intrinsic call parameters will map those counters to the external crates' coverage maps, when generating runtime coverage data.Now Rust Coverage can cleanly instrument and analyze coverage on an entire crate and its dependencies.
Example (instrumenting https://github.com/google/json5format):
(Scan forward for some of the non-zero coverage results, with
/^....[0-9]\| *[^ |0]
.)