If an inline function is observed but unused in a translation unit, a dummy coverage mapping data with a zero hash is stored for this function. If such a coverage mapping section came earlier than real one, the latter was ignored. As a result, llvm-cov was unable to show coverage information for those functions.
Details
Diff Detail
Event Timeline
The motivation sample for this patch is the following:
$ cat > sample.h << EOF inline int sample_func(int A) { if (A > 0) return A; return 0; } EOF $ cat > dummy.cpp << EOF #include "sample.h" EOF $ cat > sample.cpp << EOF #include "sample.h" int main() { return sample_func(5); } EOF $ clang++ -fprofile-instr-generate -fcoverage-mapping dummy.cpp sample.cpp $ ./a.out $ llvm-profdata merge -o default.profdata default.profraw $ llvm-cov show a.out -instr-profile default.profdata warning: 1 functions have mismatched data. sample.cpp: | 1|#include "sample.h" | 2| 1| 3|int main() { 1| 4| return sample_func(5); 1| 5|}
After applying the patch, the output is the following:
$ llvm-cov show a.out -instr-profile default.profdata sample.h: 1| 1|inline int sample_func(int A) { 1| 2| if (A > 0) 1| 3| return A; 0| 4| return 0; 1| 5|} sample.cpp: | 1|#include "sample.h" | 2| 1| 3|int main() { 1| 4| return sample_func(5); 1| 5|}
lib/ProfileData/Coverage/CoverageMappingReader.cpp | ||
---|---|---|
440 | It makes sense, but I think it would be better to make that change in another patch. |
This lgtm with the nit I had above, then. Please wait a bit in case there are other comments.
It is possible to handle this without requiring changing the hash value.
What is needed is a helper method to check if the coverageMapping record is 'dummy' -- i.e. has any execution count. It not, it can be skipped or replaced.
See CoverageMapping::load method:
ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(Region.Count); if (!ExecutionCount) break;
- Added the class to check if the coverage mapping data is dummy or real.
- New implementations also works for simple functions with zero hash, so D20287 is not needed anymore.
- The test case was extended to check simple inline functions in addition to regular ones.
lib/ProfileData/Coverage/CoverageMappingReader.cpp | ||
---|---|---|
445 | It is better to have another wrapper function to check dumminess which also takes FuncHash. The code can be simplified to If (NewIsDummy || !OldIsDummy) continue | |
474 | I think it is better to move duplicate resolution code above here (with a helper function) to improve readabiltity. The helper function can be something like: InsertFunctionRecordIfNeeded (...) { .. AlreadySeen = .. if (!AlreadySeen) { Records.push_back(..); return; } IsOldDummy = .. IsNewDummy = .. if (IsNewDummy || !IsOldDummy) return; // Now replace old entry Records[OldIndex] = NewRecord; } |
- Rebased to the top
- Extracted the code of filling the mapping records collection, including duplicate resolution logic, into a separate function.
lib/ProfileData/Coverage/CoverageMappingReader.cpp | ||
---|---|---|
347 | Should this be moved above the if(Hash) so that caller does not need to initialize it. | |
test/tools/llvm-cov/Inputs/prefer_used_to_unused.cpp | ||
6 | do you need another source file that includes prefer_used_to_unused.h but does not call sampleFunc nor simpleFunc in order to force creation of dummies? |
lib/ProfileData/Coverage/CoverageMappingReader.cpp | ||
---|---|---|
293 | Thanks! I'll update the patch tomorrow. | |
347 | The caller doesn't need to initialize it. If Hash is 0, RawCoverageMappingDummyChecker::isDummy() does its part of work. | |
394 | Thanks! | |
test/tools/llvm-cov/Inputs/prefer_used_to_unused.cpp | ||
6 | I use prefer_used_to_unused.h itself for this, see the comment at line 6 there. |
nit, could you use Expected<bool> here? That should let you simplify this a bit.