llvm-cov: Print coverage summary to STDOUT.
authorYuchen Wu <yuchenericwu@hotmail.com>
Wed, 18 Dec 2013 21:12:51 +0000 (21:12 +0000)
committerYuchen Wu <yuchenericwu@hotmail.com>
Wed, 18 Dec 2013 21:12:51 +0000 (21:12 +0000)
File summaries will now be optionally outputted which will give line,
branching and call coverage info. Unfortunately, clang's current
instrumentation does not give enough information to deduce function
calls, something that gcc is able to do. Thus, no calls are always
outputted to be consistent with gcov output.

Also updated tests.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197606 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/GCOV.h
lib/IR/GCOV.cpp
test/tools/llvm-cov/Inputs/test_-b.output [new file with mode: 0644]
test/tools/llvm-cov/Inputs/test_no_options.output [new file with mode: 0644]
test/tools/llvm-cov/llvm-cov.test

index a0468bd81527ad4607e88761ee242168bb395daf..eb536f50dc3cd67ad264adffdf312001b6fc8673 100644 (file)
@@ -350,6 +350,19 @@ class FileInfo {
     BlockLines Blocks;
     FunctionLines Functions;
   };
+
+  struct GCOVCoverage {
+    GCOVCoverage() :
+      LogicalLines(0), LinesExec(0), Branches(0), BranchesExec(0),
+      BranchesTaken(0) {}
+
+    uint32_t LogicalLines;
+    uint32_t LinesExec;
+
+    uint32_t Branches;
+    uint32_t BranchesExec;
+    uint32_t BranchesTaken;
+  };
 public:
   FileInfo(const GCOVOptions &Options) :
     Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {}
@@ -370,9 +383,10 @@ private:
   void printBlockInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
                       uint32_t LineIndex, uint32_t &BlockNo) const;
   void printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
-                       uint32_t &EdgeNo) const;
+                       GCOVCoverage &Coverage, uint32_t &EdgeNo) const;
   void printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo,
                              uint64_t Count) const;
+  void printFileCoverage(StringRef Filename, GCOVCoverage &Coverage) const;
 
   const GCOVOptions &Options;
   StringMap<LineData> LineInfo;
index 62cbc5ef03e47df4d89e332dff2d6100b2fe9203..b33eee6692b80aa9f1ab4dc7b6ab7c1114b1ffde 100644 (file)
@@ -454,6 +454,7 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
     OS << "        -:    0:Programs:" << ProgramCount << "\n";
 
     const LineData &Line = I->second;
+    GCOVCoverage Coverage;
     for (uint32_t LineIndex = 0; !AllLines.empty(); ++LineIndex) {
       if (Options.BranchInfo) {
         FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex);
@@ -485,10 +486,14 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
             LineCount += Block->getCount();
           }
         }
+
         if (LineCount == 0)
           OS << "    #####:";
-        else
+        else {
           OS << format("%9" PRIu64 ":", LineCount);
+          ++Coverage.LinesExec;
+        }
+        ++Coverage.LogicalLines;
 
         std::pair<StringRef, StringRef> P = AllLines.split('\n');
         OS << format("%5u:", LineIndex+1) << P.first << "\n";
@@ -508,13 +513,16 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
           if (Options.BranchInfo) {
             size_t NumEdges = Block->getNumDstEdges();
             if (NumEdges > 1)
-              printBranchInfo(OS, *Block, EdgeNo);
+              printBranchInfo(OS, *Block, Coverage, EdgeNo);
             else if (Options.UncondBranch && NumEdges == 1)
               printUncondBranchInfo(OS, EdgeNo, (*Block->dst_begin())->Count);
           }
         }
       }
     }
+
+    // FIXME: There is no way to detect calls given current instrumentation.
+    printFileCoverage(Filename, Coverage);
   }
 }
 
@@ -552,7 +560,7 @@ void FileInfo::printBlockInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
 
 /// printBranchInfo - Print conditional branch probabilities.
 void FileInfo::printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
-                               uint32_t &EdgeNo) const {
+                               GCOVCoverage &Coverage, uint32_t &EdgeNo) const {
   SmallVector<uint64_t, 16> BranchCounts;
   uint64_t TotalCounts = 0;
   for (GCOVBlock::EdgeIterator I = Block.dst_begin(), E = Block.dst_end();
@@ -560,6 +568,9 @@ void FileInfo::printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
     const GCOVEdge *Edge = *I;
     BranchCounts.push_back(Edge->Count);
     TotalCounts += Edge->Count;
+    if (Block.getCount()) ++Coverage.BranchesExec;
+    if (Edge->Count) ++Coverage.BranchesTaken;
+    ++Coverage.Branches;
   }
 
   for (SmallVectorImpl<uint64_t>::const_iterator I = BranchCounts.begin(),
@@ -575,3 +586,27 @@ void FileInfo::printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo,
   OS << format("unconditional %2u ", EdgeNo++)
      << formatBranchInfo(Options, Count, Count) << "\n";
 }
+
+/// printFileCoverage - Print per-file coverage info.
+void FileInfo::printFileCoverage(StringRef Filename,
+                                 GCOVCoverage &Coverage) const {
+  outs() << "File '" << Filename << "'\n";
+  outs() << format("Lines executed:%.2lf%% of %u\n",
+                   double(Coverage.LinesExec)*100/Coverage.LogicalLines,
+                   Coverage.LogicalLines);
+  if (Options.BranchInfo) {
+    if (Coverage.Branches) {
+      outs() << format("Branches executed:%.2lf%% of %u\n",
+                       double(Coverage.BranchesExec)*100/Coverage.Branches,
+                       Coverage.Branches);
+      outs() << format("Taken at least once:%.2lf%% of %u\n",
+                       double(Coverage.BranchesTaken)*100/Coverage.Branches,
+                       Coverage.Branches);
+    } else {
+      outs() << "No branches\n";
+    }
+    outs() << "No calls\n"; // to be consistent with gcov
+  }
+  outs() << Filename << ":creating '" << Filename << ".gcov'\n";
+  outs() << "\n";
+}
diff --git a/test/tools/llvm-cov/Inputs/test_-b.output b/test/tools/llvm-cov/Inputs/test_-b.output
new file mode 100644 (file)
index 0000000..4003ce8
--- /dev/null
@@ -0,0 +1,13 @@
+File 'test.cpp'
+Lines executed:84.21% of 38
+Branches executed:100.00% of 15
+Taken at least once:86.67% of 15
+No calls
+test.cpp:creating 'test.cpp.gcov'
+
+File './test.h'
+Lines executed:100.00% of 1
+No branches
+No calls
+./test.h:creating './test.h.gcov'
+
diff --git a/test/tools/llvm-cov/Inputs/test_no_options.output b/test/tools/llvm-cov/Inputs/test_no_options.output
new file mode 100644 (file)
index 0000000..93ea726
--- /dev/null
@@ -0,0 +1,8 @@
+File 'test.cpp'
+Lines executed:84.21% of 38
+test.cpp:creating 'test.cpp.gcov'
+
+File './test.h'
+Lines executed:100.00% of 1
+./test.h:creating './test.h.gcov'
+
index 02b8a3db9a5105a3f563731fef99730ded5ab685..da39307168963c37604d49998eb1bae7bb90b57c 100644 (file)
@@ -5,7 +5,7 @@ RUN: mkdir %t
 RUN: cd %t
 RUN: cp %p/Inputs/test* .
 
-RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda
+RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda | diff test_no_options.output -
 RUN: diff -aub test_no_options.cpp.gcov test.cpp.gcov
 RUN: diff -aub test_no_options.h.gcov test.h.gcov
 
@@ -13,7 +13,7 @@ RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda -a
 RUN: diff -aub test_-a.cpp.gcov test.cpp.gcov
 RUN: diff -aub test_-a.h.gcov test.h.gcov
 
-RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda -a -b
+RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda -a -b | diff test_-b.output -
 RUN: diff -aub test_-a_-b.cpp.gcov test.cpp.gcov
 RUN: diff -aub test_-a_-b.h.gcov test.h.gcov