[llvm-cov] Improve error messaging for function mismatches
authorVedant Kumar <vsk@apple.com>
Thu, 21 Sep 2017 01:11:30 +0000 (01:11 +0000)
committerVedant Kumar <vsk@apple.com>
Thu, 21 Sep 2017 01:11:30 +0000 (01:11 +0000)
Passing "-dump" to llvm-cov will now print more detailed information
about function hash and counter mismatches. This should make it easier
to debug *.profdata files which contain incorrect records, and to debug
other scenarios where coverage goes missing due to mismatch issues.

llvm-svn: 313853

llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
llvm/test/tools/llvm-cov/cov-comdat.test
llvm/tools/llvm-cov/CodeCoverage.cpp

index 13a9093..22286f6 100644 (file)
@@ -508,7 +508,8 @@ public:
 class CoverageMapping {
   StringSet<> FunctionNames;
   std::vector<FunctionRecord> Functions;
-  unsigned MismatchedFunctionCount = 0;
+  std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
+  std::vector<std::pair<std::string, uint64_t>> FuncCounterMismatches;
 
   CoverageMapping() = default;
 
@@ -535,7 +536,25 @@ public:
   ///
   /// This is a count of functions whose profile is out of date or otherwise
   /// can't be associated with any coverage information.
-  unsigned getMismatchedCount() { return MismatchedFunctionCount; }
+  unsigned getMismatchedCount() const {
+    return FuncHashMismatches.size() + FuncCounterMismatches.size();
+  }
+
+  /// A hash mismatch occurs when a profile record for a symbol does not have
+  /// the same hash as a coverage mapping record for the same symbol. This
+  /// returns a list of hash mismatches, where each mismatch is a pair of the
+  /// symbol name and its coverage mapping hash.
+  ArrayRef<std::pair<std::string, uint64_t>> getHashMismatches() const {
+    return FuncHashMismatches;
+  }
+
+  /// A counter mismatch occurs when there is an error when evaluating the
+  /// counter expressions in a coverage mapping record. This returns a list of
+  /// counter mismatches, where each mismatch is a pair of the symbol name and
+  /// the number of valid evaluated counter expressions.
+  ArrayRef<std::pair<std::string, uint64_t>> getCounterMismatches() const {
+    return FuncCounterMismatches;
+  }
 
   /// Returns a lexicographically sorted, unique list of files that are
   /// covered.
index 4c257cf..52f9447 100644 (file)
@@ -217,7 +217,7 @@ Error CoverageMapping::loadFunctionRecord(
                                                 Record.FunctionHash, Counts)) {
     instrprof_error IPE = InstrProfError::take(std::move(E));
     if (IPE == instrprof_error::hash_mismatch) {
-      MismatchedFunctionCount++;
+      FuncHashMismatches.emplace_back(Record.FunctionName, Record.FunctionHash);
       return Error::success();
     } else if (IPE != instrprof_error::unknown_function)
       return make_error<InstrProfError>(IPE);
@@ -237,7 +237,8 @@ Error CoverageMapping::loadFunctionRecord(
     Function.pushRegion(Region, *ExecutionCount);
   }
   if (Function.CountedRegions.size() != Record.MappingRegions.size()) {
-    MismatchedFunctionCount++;
+    FuncCounterMismatches.emplace_back(Record.FunctionName,
+                                       Function.CountedRegions.size());
     return Error::success();
   }
 
index 1545f99..9d22716 100644 (file)
@@ -7,6 +7,9 @@ REQUIRES: shell
 # of the same template function are properly merged in show
 # output.
 
-// RUN: llvm-cov show %S/Inputs/binary-formats.v1.linux64l -instr-profile %S/Inputs/elf_binary_comdat.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/instrprof-comdat.h | FileCheck --check-prefix=HEADER %S/Inputs/instrprof-comdat.h
+// RUN: llvm-cov show %S/Inputs/binary-formats.v1.linux64l -instr-profile %S/Inputs/elf_binary_comdat.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/instrprof-comdat.h -dump 2> %t.err | FileCheck --check-prefix=HEADER %S/Inputs/instrprof-comdat.h
+// RUN: FileCheck --check-prefix=ERROR -input-file %t.err %s
+// ERROR: hash-mismatch: No profile record found for 'main' with hash = 0xA
+
 // RUN: llvm-cov show %S/Inputs/binary-formats.v2.linux64l -instr-profile %S/Inputs/elf_binary_comdat.profdata -path-equivalence=/root/llvm/test/tools,%S/.. %S/Inputs/instrprof-comdat.h | FileCheck --check-prefix=HEADER %S/Inputs/instrprof-comdat.h
 // RUN: llvm-cov show %S/Inputs/binary-formats.v2.linux32l -instr-profile %S/Inputs/elf_binary_comdat.profdata -path-equivalence=/root/llvm/R/../test/tools,%S/.. %S/Inputs/instrprof-comdat.h | FileCheck --check-prefix=HEADER %S/Inputs/instrprof-comdat.h
index 09ee82a..981c93a 100644 (file)
@@ -350,9 +350,23 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
   }
   auto Coverage = std::move(CoverageOrErr.get());
   unsigned Mismatched = Coverage->getMismatchedCount();
-  if (Mismatched)
+  if (Mismatched) {
     warning(utostr(Mismatched) + " functions have mismatched data");
 
+    if (ViewOpts.Debug) {
+      for (const auto &HashMismatch : Coverage->getHashMismatches())
+        errs() << "hash-mismatch: "
+               << "No profile record found for '" << HashMismatch.first << "'"
+               << " with hash = 0x" << utohexstr(HashMismatch.second) << "\n";
+
+      for (const auto &CounterMismatch : Coverage->getCounterMismatches())
+        errs() << "counter-mismatch: "
+               << "Coverage mapping for " << CounterMismatch.first
+               << " only has " << CounterMismatch.second
+               << " valid counter expressions\n";
+    }
+  }
+
   remapPathNames(*Coverage);
 
   if (!SourceFiles.empty())