Skip to content

Commit

Permalink
llvm-cov: Added -f option for function summaries.
Browse files Browse the repository at this point in the history
Similar to the file summaries, the function summaries output line,
branching and call statistics. The file summaries have been moved
outside the initial loop so that all of the function summaries can be
outputted before file summaries.

Also updated test cases.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197633 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
yuchenericwu committed Dec 19, 2013
1 parent deb8e33 commit d218959
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 23 deletions.
25 changes: 18 additions & 7 deletions include/llvm/Support/GCOV.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define LLVM_SUPPORT_GCOV_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/MemoryBuffer.h"
Expand All @@ -36,12 +37,14 @@ namespace GCOV {

/// GCOVOptions - A struct for passing gcov options between functions.
struct GCOVOptions {
GCOVOptions(bool A, bool B, bool C, bool U) :
AllBlocks(A), BranchInfo(B), BranchCount(C), UncondBranch(U) {}
GCOVOptions(bool A, bool B, bool C, bool F, bool U) :
AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F), UncondBranch(U)
{}

bool AllBlocks;
bool BranchInfo;
bool BranchCount;
bool FuncCoverage;
bool UncondBranch;
};

Expand Down Expand Up @@ -300,6 +303,7 @@ class GCOVBlock {
GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N), Counter(0),
DstEdgesAreSorted(true), SrcEdges(), DstEdges(), Lines() {}
~GCOVBlock();
const GCOVFunction &getParent() const { return Parent; }
void addLine(uint32_t N) { Lines.push_back(N); }
uint32_t getLastLine() const { return Lines.back(); }
void addCount(size_t DstEdgeNo, uint64_t N);
Expand Down Expand Up @@ -352,10 +356,12 @@ class FileInfo {
};

struct GCOVCoverage {
GCOVCoverage() :
LogicalLines(0), LinesExec(0), Branches(0), BranchesExec(0),
GCOVCoverage(StringRef Name) :
Name(Name), LogicalLines(0), LinesExec(0), Branches(0), BranchesExec(0),
BranchesTaken(0) {}

StringRef Name;

uint32_t LogicalLines;
uint32_t LinesExec;

Expand All @@ -376,22 +382,27 @@ class FileInfo {
}
void setRunCount(uint32_t Runs) { RunCount = Runs; }
void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
void print(StringRef GCNOFile, StringRef GCDAFile) const;
void print(StringRef GCNOFile, StringRef GCDAFile);
private:
void printFunctionSummary(raw_fd_ostream &OS,
const FunctionVector &Funcs) const;
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,
GCOVCoverage &Coverage, uint32_t &EdgeNo) const;
GCOVCoverage &Coverage, uint32_t &EdgeNo);
void printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo,
uint64_t Count) const;
void printFileCoverage(StringRef Filename, GCOVCoverage &Coverage) const;

void printCoverage(const GCOVCoverage &Coverage) const;
void printFuncCoverage() const;
void printFileCoverage() const;

const GCOVOptions &Options;
StringMap<LineData> LineInfo;
uint32_t RunCount;
uint32_t ProgramCount;
SmallVector<GCOVCoverage, 4> FileCoverages;
MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverages;
};

}
Expand Down
96 changes: 81 additions & 15 deletions lib/IR/GCOV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
}

/// print - Print source files with collected line count information.
void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) {
for (StringMap<LineData>::const_iterator I = LineInfo.begin(),
E = LineInfo.end(); I != E; ++I) {
StringRef Filename = I->first();
Expand All @@ -454,7 +454,7 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
OS << " -: 0:Programs:" << ProgramCount << "\n";

const LineData &Line = I->second;
GCOVCoverage Coverage;
GCOVCoverage FileCoverage(Filename);
for (uint32_t LineIndex = 0; !AllLines.empty(); ++LineIndex) {
if (Options.BranchInfo) {
FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex);
Expand All @@ -473,6 +473,7 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
const BlockVector &Blocks = BlocksIt->second;

// Add up the block counts to form line counts.
DenseMap<const GCOVFunction *, bool> LineExecs;
uint64_t LineCount = 0;
for (BlockVector::const_iterator I = Blocks.begin(), E = Blocks.end();
I != E; ++I) {
Expand All @@ -485,15 +486,49 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
// Sum up all of the block counts.
LineCount += Block->getCount();
}

if (Options.FuncCoverage) {
// This is a slightly convoluted way to most accurately gather line
// statistics for functions. Basically what is happening is that we
// don't want to count a single line with multiple blocks more than
// once. However, we also don't simply want to give the total line
// count to every function that starts on the line. Thus, what is
// happening here are two things:
// 1) Ensure that the number of logical lines is only incremented
// once per function.
// 2) If there are multiple blocks on the same line, ensure that the
// number of lines executed is incremented as long as at least
// one of the blocks are executed.
const GCOVFunction *Function = &Block->getParent();
if (FuncCoverages.find(Function) == FuncCoverages.end()) {
std::pair<const GCOVFunction *, GCOVCoverage>
KeyValue(Function, GCOVCoverage(Function->getName()));
FuncCoverages.insert(KeyValue);
}
GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second;

if (LineExecs.find(Function) == LineExecs.end()) {
if (Block->getCount()) {
++FuncCoverage.LinesExec;
LineExecs[Function] = true;
} else {
LineExecs[Function] = false;
}
++FuncCoverage.LogicalLines;
} else if (!LineExecs[Function] && Block->getCount()) {
++FuncCoverage.LinesExec;
LineExecs[Function] = true;
}
}
}

if (LineCount == 0)
OS << " #####:";
else {
OS << format("%9" PRIu64 ":", LineCount);
++Coverage.LinesExec;
++FileCoverage.LinesExec;
}
++Coverage.LogicalLines;
++FileCoverage.LogicalLines;

std::pair<StringRef, StringRef> P = AllLines.split('\n');
OS << format("%5u:", LineIndex+1) << P.first << "\n";
Expand All @@ -513,17 +548,20 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
if (Options.BranchInfo) {
size_t NumEdges = Block->getNumDstEdges();
if (NumEdges > 1)
printBranchInfo(OS, *Block, Coverage, EdgeNo);
printBranchInfo(OS, *Block, FileCoverage, 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);
FileCoverages.push_back(FileCoverage);
}

// FIXME: There is no way to detect calls given current instrumentation.
if (Options.FuncCoverage)
printFuncCoverage();
printFileCoverage();
}

/// printFunctionSummary - Print function and block summary.
Expand Down Expand Up @@ -560,7 +598,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,
GCOVCoverage &Coverage, uint32_t &EdgeNo) const {
GCOVCoverage &Coverage, uint32_t &EdgeNo) {
SmallVector<uint64_t, 16> BranchCounts;
uint64_t TotalCounts = 0;
for (GCOVBlock::EdgeIterator I = Block.dst_begin(), E = Block.dst_end();
Expand All @@ -571,6 +609,14 @@ void FileInfo::printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
if (Block.getCount()) ++Coverage.BranchesExec;
if (Edge->Count) ++Coverage.BranchesTaken;
++Coverage.Branches;

if (Options.FuncCoverage) {
const GCOVFunction *Function = &Block.getParent();
GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second;
if (Block.getCount()) ++FuncCoverage.BranchesExec;
if (Edge->Count) ++FuncCoverage.BranchesTaken;
++FuncCoverage.Branches;
}
}

for (SmallVectorImpl<uint64_t>::const_iterator I = BranchCounts.begin(),
Expand All @@ -587,10 +633,9 @@ void FileInfo::printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo,
<< formatBranchInfo(Options, Count, Count) << "\n";
}

/// printFileCoverage - Print per-file coverage info.
void FileInfo::printFileCoverage(StringRef Filename,
GCOVCoverage &Coverage) const {
outs() << "File '" << Filename << "'\n";
// printCoverage - Print generic coverage info used by both printFuncCoverage
// and printFileCoverage.
void FileInfo::printCoverage(const GCOVCoverage &Coverage) const {
outs() << format("Lines executed:%.2lf%% of %u\n",
double(Coverage.LinesExec)*100/Coverage.LogicalLines,
Coverage.LogicalLines);
Expand All @@ -607,6 +652,27 @@ void FileInfo::printFileCoverage(StringRef Filename,
}
outs() << "No calls\n"; // to be consistent with gcov
}
outs() << Filename << ":creating '" << Filename << ".gcov'\n";
outs() << "\n";
}

// printFuncCoverage - Print per-function coverage info.
void FileInfo::printFuncCoverage() const {
for (MapVector<const GCOVFunction *, GCOVCoverage>::const_iterator I =
FuncCoverages.begin(), E = FuncCoverages.end(); I != E; ++I) {
const GCOVCoverage &Coverage = I->second;
outs() << "Function '" << Coverage.Name << "'\n";
printCoverage(Coverage);
outs() << "\n";
}
}

// printFileCoverage - Print per-file coverage info.
void FileInfo::printFileCoverage() const {
for (SmallVectorImpl<GCOVCoverage>::const_iterator I =
FileCoverages.begin(), E = FileCoverages.end(); I != E; ++I) {
const GCOVCoverage &Coverage = *I;
outs() << "File '" << Coverage.Name << "'\n";
printCoverage(Coverage);
outs() << Coverage.Name << ":creating '" << Coverage.Name
<< ".gcov'\n\n";
}
}
65 changes: 65 additions & 0 deletions test/tools/llvm-cov/Inputs/test_-b_-f.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
Function '_ZN1A1BEv'
Lines executed:100.00% of 1
No branches
No calls

Function '_Z7uselessv'
Lines executed:0.00% of 1
No branches
No calls

Function '_Z12more_uselessv'
Lines executed:0.00% of 1
No branches
No calls

Function '_Z3foov'
Lines executed:100.00% of 2
No branches
No calls

Function '_Z3barv'
Lines executed:0.00% of 2
No branches
No calls

Function '_Z6assignii'
Lines executed:100.00% of 3
No branches
No calls

Function '_Z15initialize_gridv'
Lines executed:100.00% of 4
Branches executed:100.00% of 4
Taken at least once:100.00% of 4
No calls

Function 'main'
Lines executed:91.67% of 24
Branches executed:100.00% of 11
Taken at least once:81.82% of 11
No calls

Function '_ZN1AC1Ev'
Lines executed:100.00% of 1
No branches
No calls

Function '_ZN1AC2Ev'
No executable lines
No branches
No calls

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'

38 changes: 38 additions & 0 deletions test/tools/llvm-cov/Inputs/test_-f.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Function '_ZN1A1BEv'
Lines executed:100.00% of 1

Function '_Z7uselessv'
Lines executed:0.00% of 1

Function '_Z12more_uselessv'
Lines executed:0.00% of 1

Function '_Z3foov'
Lines executed:100.00% of 2

Function '_Z3barv'
Lines executed:0.00% of 2

Function '_Z6assignii'
Lines executed:100.00% of 3

Function '_Z15initialize_gridv'
Lines executed:100.00% of 4

Function 'main'
Lines executed:91.67% of 24

Function '_ZN1AC1Ev'
Lines executed:100.00% of 1

Function '_ZN1AC2Ev'
Lines executed:100.00% of 1

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'

4 changes: 4 additions & 0 deletions test/tools/llvm-cov/llvm-cov.test
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ RUN: cd %t
RUN: cp %p/Inputs/test* .

RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda | diff test_no_options.output -
RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda -f | diff test_-f.output -
RUN: diff -aub test_no_options.cpp.gcov test.cpp.gcov
RUN: diff -aub test_no_options.h.gcov test.h.gcov

Expand All @@ -14,6 +15,9 @@ 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 | diff test_-b.output -
# This is expected to fail because gcov doesn't actually output real branch or
# call statistics on a per function basis.
RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda -a -b -f | not diff test_-b_-f.output -
RUN: diff -aub test_-a_-b.cpp.gcov test.cpp.gcov
RUN: diff -aub test_-a_-b.h.gcov test.h.gcov

Expand Down
6 changes: 5 additions & 1 deletion tools/llvm-cov/llvm-cov.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ static cl::opt<bool>
BranchCount("c", cl::init(false), cl::desc("display branch counts instead of \
probabilities (requires -b)"));

static cl::opt<bool>
FuncCoverage("f", cl::init(false), cl::desc("output function coverage"));

static cl::opt<bool>
UncondBranch("u", cl::init(false), cl::desc("display unconditional branch info \
(requires -b)"));
Expand Down Expand Up @@ -84,7 +87,8 @@ int main(int argc, char **argv) {
if (DumpGCOV)
GF.dump();

GCOVOptions Options(AllBlocks, BranchInfo, BranchCount, UncondBranch);
GCOVOptions Options(AllBlocks, BranchInfo, BranchCount, FuncCoverage,
UncondBranch);
FileInfo FI(Options);
GF.collectLineCounts(FI);
FI.print(InputGCNO, InputGCDA);
Expand Down

0 comments on commit d218959

Please sign in to comment.