-
Notifications
You must be signed in to change notification settings - Fork 92
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
RFC: Line Coverage #2612
RFC: Line Coverage #2612
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the proposal and think that implementing coverage in Kani is the way to go. However, I think we should rely on existing compiler APIs (e.g. CodeRegion) to compute coverage that is consistent with compiler-instrumented coverage.
In particular, can we implement a MIR pass similar to rustc's |
We both agree on this, and the RFC should discuss these references in more detail. That said, my main concern as of now with the compiler APIs for coverage is that they heavily rely on LLVM intrinsics and tools to do most of the profiling work. We can definitely plug in the InstrumentCoverage MIR pass to our compiler, but our backend is not LLVM-based so it's not clear to me what to do then (note that LLVM intrinsics are used to increment the region-based counters, but then you also need the LLVM runtime to extract their values). So I don't think the compiler APIs are directly usable for us unless some work happens in our backend first. In summary, I don't think we're capable of adopting these APIs at the moment, but I'm looking forward to learning more about them and eventually replace the proposed mechanism. But that's out of scope for this version, which aims at line-level coverage information. |
True: the |
Yes, that makes sense. Thank you! Do you have any feedback on the UX side? |
One question is: how does this work with multiple harnesses? Ideally, one would want a single coverage report where a line is considered covered if it is reachable from one or more harnesses. That way, one can focus on writing new harnesses that cover lines that are currently uncovered by any of the existing harnesses. |
Another question: how would we report coverage for functions in user code that are not reachable from a harness? As a user, I would expect the lines in those functions to be reported as uncovered, but the pruning done by the MIR linker may remove those functions altogether, and thus no checks would be generated for them at all. |
Today I tried implementing a MIR pass similar to But I learned something important along the way: This instrumentation is quite similar to the one proposed in the RFC, but with many steps dedicated to optimizing runtime. In particular, I'd like to point you to these comments in
Because of that, I'm confident that our proposed implementation, which injects coverage statements for each statement and terminator, is essentially a naive version of the Another thing that I've tried is passing
I was able to work around this by also adding the
Debug logs showed a single counter being injected for the whole block:
At that point, Kani APIs may not have been taken into account in the computation for coverage basic blocks, resulting in a single In summary, some of these APIs aren't public which makes it difficult to use them, and it isn't clear to me what code we'd need to trim even if we do. The basic idea seems to be the same, but many steps seem focused on optimizing runtime. Another attempt to use the coverage instrumentation has failed. Do you still think it's worth exploring this for the first version? |
I see. Thanks for exploring this option @adpaco-aws. If we have no reason to believe that the proposed approach is different from the way rustc instruments coverage, then I'm OK with proceeding with the current plan. Once we implement it, we can conduct experiments that check for discrepancies between rustc's coverage and ours (e.g. by checking that lines that are reported as covered through rustc's instrumentation are reported as covered by Kani). |
How do we report if a line is partially covered? That is, there are multiple instructions in the same line and only some of them are reachable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the goal of this RFC is not quite clear to me (neither, the path to stabilization).
BTW, I think it's OK for us to have a lot of open questions, it's just not clear to me what is an open question and what is a design decision at this point. For example, what is the coverage granularity that we are planning to provide? The design talks about statements, but the output is line based.
Good point! Yes, we should merge coverage results from all harnesses to produce a combined report. I've discussed it with @jaisnan and I think we're going to go with the following approach:
Let me add that to the RFC. |
Update: I've tried to address most comments in the latest changes, but tomorrow I'll post individual replies to each of them. Thank you all for the feedback! |
This is now considered in the future possibilities section. Some coverage frameworks have a dedicated tool to combine coverage results from individual harnesses and I'd like Kani to do the same. However, I'm not sure how to distribute and in any case it's a nice-to-have which is why I'm adding it to that section (actually, @jaisnan has a prototype if I'm not mistaken). |
We don't provide coverage results for unreachable code. In other words, we only report coverage for lines which contain at least one coverage check. The rest are essentially considered not covered. |
This is now addressed in the design section (postprocessing of coverage checks). We'll report three different types of coverage: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good! Thanks for all the changes. My main request is to make it clear that we still need to define a final UX as part of this RFC. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we report if a line is partially covered? That is, there are multiple instructions in the same line and only some of them are reachable.
This is now addressed in the design section (postprocessing of coverage checks). We'll report three different types of coverage:
FULL
,PARTIAL
andNONE
.
LGTM. Thanks.
Description of changes:
An RFC to discuss an option in Kani to generate verification-based line coverage reports.
Rendered version is available here.
Proof-of-concept is available in #2609
Resolved issues:
Resolves (partially) #2610
Call-outs:
Testing:
How is this change tested? N/A
Is this a refactor change? N/A
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.