[PATCH] llvm-cov: Added -b option for branch probabilities.
Justin Bogner
mail at justinbogner.com
Thu Dec 12 11:19:58 PST 2013
Yuchen Wu <yuchenericwu at hotmail.com> writes:
>>> +// It is unlikely--but possible--for multiple functions to be on
>>> the same line.
>>> +// But optimize for the common case.
>>
>> What is this comment talking about?
>
> The reason FunctionVector exists is because LineData needs to be able
> to store all of the functions that are on a single line. The comment
> is to explain that it's unlikely two functions will be on the same
> line, so optimize for the common case by setting the SmallVector
> typedef to contain a single element.
I may have been subtly implying you should improve the comment :)
>>> +typedef SmallVector<const GCOVFunction *, 1> FunctionVector;
>>> +typedef DenseMap<uint32_t, FunctionVector> FunctionLines;
>>> typedef SmallVector<const GCOVBlock *, 4> BlockVector;
>>> -typedef DenseMap<uint32_t, BlockVector> LineData;
>>> +typedef DenseMap<uint32_t, BlockVector> BlockLines;
>
>>> +// Safe integer division, returns 0 if divisor is 0.
>>> +static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor) {
>>> + if (Divisor == 0)
>>> + return 0;
>>> + return Numerator/Divisor;
>>> +}
>>
>> Why do you need this?
>>
>>> +
>>> +// This custom division function mimics gcov's branch ouputs:
>>> +// - Round to closest whole number
>>> +// - Only output 0% or 100% if it's exactly that value
>>> +static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
>>> + uint8_t Res = safeDiv(Numerator*100+Divisor/2, Divisor);
>>> + if (Res == 0 && Numerator)
>>> + return 1;
>>
>> This seems like pretty strange behaviour if Divisor == 0.
>
> The safeDiv and branchDiv functions need to return 0 if it's asked to
> divide 0 by 0, which actually happens quite often.
Firstl, branchDiv returns 1%, not zero - that seems arbitrary and
insane. Second, you still haven't answered why this happens / is
accepted. This feels like it's papering over a problem somewhere else to
me.
> I've implemented all the other suggestions you made into this new
> patch. Enjoy!
>
> From 536dc2a15462a4e97186c9b99a87f0cc45cad1c5 Mon Sep 17 00:00:00 2001
> From: Yuchen Wu <yuchen_wu at apple.com>
> Date: Tue, 3 Dec 2013 14:27:17 -0800
> Subject: [PATCH 2/7] llvm-cov: Added -b option for branch probabilities.
>
> This option tells llvm-cov to print out branch probabilities when
> a basic block contains multiple branches. It also prints out some
> function summary info including the number of times the function enters,
> the percent of time it returns, and how many blocks were executed.
>
> Also updated tests.
> ---
> include/llvm/Support/GCOV.h | 74 ++++++++++--
> lib/IR/GCOV.cpp | 153 +++++++++++++++++++++----
> test/tools/llvm-cov/Inputs/test_-a_-b.cpp.gcov | 134 ++++++++++++++++++++++
> test/tools/llvm-cov/Inputs/test_-a_-b.h.gcov | 12 ++
> test/tools/llvm-cov/llvm-cov.test | 4 +
> tools/llvm-cov/llvm-cov.cpp | 8 +-
> 6 files changed, 349 insertions(+), 36 deletions(-)
> create mode 100644 test/tools/llvm-cov/Inputs/test_-a_-b.cpp.gcov
> create mode 100644 test/tools/llvm-cov/Inputs/test_-a_-b.h.gcov
>
> diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h
> index 852c0be..fd816c7 100644
> --- a/include/llvm/Support/GCOV.h
> +++ b/include/llvm/Support/GCOV.h
> @@ -36,9 +36,9 @@ namespace GCOV {
>
> /// GCOVOptions - A struct for passing gcov options between functions.
> struct GCOVOptions {
> - GCOVOptions(bool A): AllBlocks(A) {}
> -
> + GCOVOptions(bool A, bool B): AllBlocks(A), BranchProb(B) {}
> bool AllBlocks;
> + bool BranchProb;
> };
>
> /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
> @@ -236,6 +236,7 @@ private:
> uint32_t ProgramCount;
> };
>
> +/// GCOVEdge - Collects edge information.
> struct GCOVEdge {
> GCOVEdge(GCOVBlock *S, GCOVBlock *D): Src(S), Dst(D), Count(0) {}
>
> @@ -247,12 +248,21 @@ struct GCOVEdge {
> /// GCOVFunction - Collects function information.
> class GCOVFunction {
> public:
> + typedef SmallVectorImpl<GCOVBlock *>::const_iterator BlockIterator;
> +
> GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {}
> ~GCOVFunction();
> bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
> bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
> + StringRef getName() const { return Name; }
> StringRef getFilename() const { return Filename; }
> size_t getNumBlocks() const { return Blocks.size(); }
> + uint64_t getEntryCount() const;
> + uint64_t getExitCount() const;
> +
> + BlockIterator block_begin() const { return Blocks.begin(); }
> + BlockIterator block_end() const { return Blocks.end(); }
> +
> void dump() const;
> void collectLineCounts(FileInfo &FI);
> private:
> @@ -268,26 +278,43 @@ private:
>
> /// GCOVBlock - Collects block information.
> class GCOVBlock {
> + struct EdgeWeight {
> + EdgeWeight(GCOVBlock *D): Dst(D), Count(0) {}
> +
> + GCOVBlock *Dst;
> + uint64_t Count;
> + };
> +
> + struct SortDstEdgesFunctor {
> + bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
> + return E1->Dst->Number < E2->Dst->Number;
> + }
> + };
> public:
> typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator;
>
> - GCOVBlock(GCOVFunction &P, uint32_t N) :
> - Parent(P), Number(N), Counter(0), SrcEdges(), DstEdges(), Lines() {}
> + GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N), Counter(0),
> + DstEdgesAreSorted(true), SrcEdges(), DstEdges(), Lines() {}
> ~GCOVBlock();
> + void addLine(uint32_t N) { Lines.push_back(N); }
> + uint32_t getLastLine() const { return Lines.back(); }
> + void addCount(size_t DstEdgeNo, uint64_t N);
> + uint64_t getCount() const { return Counter; }
> +
> void addSrcEdge(GCOVEdge *Edge) {
> assert(Edge->Dst == this); // up to caller to ensure edge is valid
> SrcEdges.push_back(Edge);
> }
> void addDstEdge(GCOVEdge *Edge) {
> assert(Edge->Src == this); // up to caller to ensure edge is valid
> + // Check if adding this edge causes list to become unsorted.
> + if (DstEdges.size() && DstEdges.back()->Dst->Number > Edge->Dst->Number)
> + DstEdgesAreSorted = false;
> DstEdges.push_back(Edge);
> }
> - void addLine(uint32_t N) { Lines.push_back(N); }
> - uint32_t getLastLine() const { return Lines.back(); }
> - void addCount(size_t DstEdgeNo, uint64_t N);
> - uint64_t getCount() const { return Counter; }
> size_t getNumSrcEdges() const { return SrcEdges.size(); }
> size_t getNumDstEdges() const { return DstEdges.size(); }
> + void sortDstEdges();
>
> EdgeIterator src_begin() const { return SrcEdges.begin(); }
> EdgeIterator src_end() const { return SrcEdges.end(); }
> @@ -300,23 +327,46 @@ private:
> GCOVFunction &Parent;
> uint32_t Number;
> uint64_t Counter;
> + bool DstEdgesAreSorted;
> SmallVector<GCOVEdge *, 16> SrcEdges;
> SmallVector<GCOVEdge *, 16> DstEdges;
> SmallVector<uint32_t, 16> Lines;
> };
>
> +// It is unlikely--but possible--for multiple functions to be on the same line.
> +// But optimize for the common case.
> +typedef SmallVector<const GCOVFunction *, 1> FunctionVector;
> +typedef DenseMap<uint32_t, FunctionVector> FunctionLines;
> typedef SmallVector<const GCOVBlock *, 4> BlockVector;
> -typedef DenseMap<uint32_t, BlockVector> LineData;
> +typedef DenseMap<uint32_t, BlockVector> BlockLines;
> +
> class FileInfo {
> + struct LineData {
> + BlockLines Blocks;
> + FunctionLines Functions;
> + };
> public:
> + FileInfo(const GCOVOptions &Options) :
> + Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {}
> +
> void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
> - LineInfo[Filename][Line-1].push_back(Block);
> + LineInfo[Filename].Blocks[Line-1].push_back(Block);
> + }
> + void addFunctionLine(StringRef Filename, uint32_t Line,
> + const GCOVFunction *Function) {
> + LineInfo[Filename].Functions[Line-1].push_back(Function);
> }
> void setRunCount(uint32_t Runs) { RunCount = Runs; }
> void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
> - void print(StringRef GCNOFile, StringRef GCDAFile,
> - const GCOVOptions &Options) const;
> + void print(StringRef GCNOFile, StringRef GCDAFile) const;
> + void printFunctionSummary(raw_fd_ostream &OS, const LineData &Line,
> + uint32_t LineIndex) 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,
> + uint32_t LineIndex, uint32_t &EdgeNo) const;
> private:
> + const GCOVOptions &Options;
> StringMap<LineData> LineInfo;
> uint32_t RunCount;
> uint32_t ProgramCount;
> diff --git a/lib/IR/GCOV.cpp b/lib/IR/GCOV.cpp
> index fb73700..662113d 100644
> --- a/lib/IR/GCOV.cpp
> +++ b/lib/IR/GCOV.cpp
> @@ -19,6 +19,7 @@
> #include "llvm/Support/Format.h"
> #include "llvm/Support/MemoryObject.h"
> #include "llvm/Support/system_error.h"
> +#include <algorithm>
> using namespace llvm;
>
> //===----------------------------------------------------------------------===//
> @@ -278,10 +279,23 @@ bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
> Block.addCount(EdgeNo, ArcCount);
> --Count;
> }
> + Block.sortDstEdges();
> }
> return true;
> }
>
> +/// getEntryCount - Get the number of times the function was called by
> +/// retrieving the entry block's count.
> +uint64_t GCOVFunction::getEntryCount() const {
> + return Blocks.front()->getCount();
> +}
> +
> +/// getExitCount - Get the number of times the function returned by retrieving
> +/// the exit block's count.
> +uint64_t GCOVFunction::getExitCount() const {
> + return Blocks.back()->getCount();
> +}
> +
> /// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
> void GCOVFunction::dump() const {
> dbgs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
> @@ -296,6 +310,7 @@ void GCOVFunction::collectLineCounts(FileInfo &FI) {
> for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(),
> E = Blocks.end(); I != E; ++I)
> (*I)->collectLineCounts(FI);
> + FI.addFunctionLine(Filename, LineNumber, this);
> }
>
> //===----------------------------------------------------------------------===//
> @@ -318,6 +333,15 @@ void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) {
> DstEdges[DstEdgeNo]->Dst->Counter += N;
> }
>
> +/// sortDstEdges - Sort destination edges by block number, nop if already
> +/// sorted. This is required for printing branch info in the correct order.
> +void GCOVBlock::sortDstEdges() {
> + if (!DstEdgesAreSorted) {
> + SortDstEdgesFunctor SortEdges;
> + std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges);
> + }
> +}
> +
> /// collectLineCounts - Collect line counts. This must be used after
> /// reading .gcno and .gcda files.
> void GCOVBlock::collectLineCounts(FileInfo &FI) {
> @@ -357,9 +381,27 @@ void GCOVBlock::dump() const {
> //===----------------------------------------------------------------------===//
> // FileInfo implementation.
>
> +// Safe integer division, returns 0 if divisor is 0.
> +static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor) {
> + if (Divisor == 0)
> + return 0;
> + return Numerator/Divisor;
> +}
> +
> +// This custom division function mimics gcov's branch ouputs:
> +// - Round to closest whole number
> +// - Only output 0% or 100% if it's exactly that value
> +static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
> + uint8_t Res = safeDiv(Numerator*100+Divisor/2, Divisor);
> + if (Res == 0 && Numerator)
> + return 1;
> + if (Res == 100 && Numerator != Divisor)
> + return 99;
> + return Res;
> +}
> +
> /// print - Print source files with collected line count information.
> -void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile,
> - const GCOVOptions &Options) const {
> +void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const {
> for (StringMap<LineData>::const_iterator I = LineInfo.begin(),
> E = LineInfo.end(); I != E; ++I) {
> StringRef Filename = I->first();
> @@ -383,12 +425,21 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile,
> OS << " -: 0:Programs:" << ProgramCount << "\n";
>
> const LineData &Line = I->second;
> - for (uint32_t i = 0; !AllLines.empty(); ++i) {
> - LineData::const_iterator BlocksIt = Line.find(i);
> + for (uint32_t LineIndex = 0; !AllLines.empty(); ++LineIndex) {
> + if (Options.BranchProb)
> + printFunctionSummary(OS, Line, LineIndex);
>
> - if (BlocksIt != Line.end()) {
> - // Add up the block counts to form line counts.
> + BlockLines::const_iterator BlocksIt = Line.Blocks.find(LineIndex);
> + if (BlocksIt == Line.Blocks.end()) {
> + // No basic blocks are on this line. Not an executable line of code.
> + OS << " -:";
> + std::pair<StringRef, StringRef> P = AllLines.split('\n');
> + OS << format("%5u:", LineIndex+1) << P.first << "\n";
> + AllLines = P.second;
> + } else {
> const BlockVector &Blocks = BlocksIt->second;
> +
> + // Add up the block counts to form line counts.
> uint64_t LineCount = 0;
> for (BlockVector::const_iterator I = Blocks.begin(), E = Blocks.end();
> I != E; ++I) {
> @@ -406,30 +457,88 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile,
> OS << " #####:";
> else
> OS << format("%9" PRIu64 ":", LineCount);
> - } else {
> - OS << " -:";
> - }
> - std::pair<StringRef, StringRef> P = AllLines.split('\n');
> - OS << format("%5u:", i+1) << P.first << "\n";
> - AllLines = P.second;
>
> - if (Options.AllBlocks && BlocksIt != Line.end()) {
> - // Output the counts for each block at the last line of the block.
> + std::pair<StringRef, StringRef> P = AllLines.split('\n');
> + OS << format("%5u:", LineIndex+1) << P.first << "\n";
> + AllLines = P.second;
> +
> uint32_t BlockNo = 0;
> - const BlockVector &Blocks = BlocksIt->second;
> + uint32_t EdgeNo = 0;
> for (BlockVector::const_iterator I = Blocks.begin(), E = Blocks.end();
> I != E; ++I) {
> const GCOVBlock *Block = *I;
> - if (Block->getLastLine() != i+1)
> - continue;
>
> - if (Block->getCount() == 0)
> - OS << " $$$$$:";
> - else
> - OS << format("%9lu:", Block->getCount());
> - OS << format("%5u-block %u\n", i+1, BlockNo++);
> + // Only print block and branch information at the end of the block.
> + if (Block->getLastLine() != LineIndex+1)
> + continue;
> + if (Options.AllBlocks)
> + printBlockInfo(OS, *Block, LineIndex, BlockNo);
> + if (Options.BranchProb)
> + printBranchInfo(OS, *Block, LineIndex, EdgeNo);
> }
> }
> }
> }
> }
> +
> +/// printFunctionSummary - Print function and block summary.
> +void FileInfo::printFunctionSummary(raw_fd_ostream &OS, const LineData &Line,
> + uint32_t LineIndex) const {
> + FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex);
> + if (FuncsIt != Line.Functions.end()) {
Better to return early here and save a level of indentation.
> + const SmallVectorImpl<const GCOVFunction *> &Funcs = FuncsIt->second;
> + for (SmallVectorImpl<const GCOVFunction*>::const_iterator I =
> + Funcs.begin(), E = Funcs.end(); I != E; ++I) {
> + const GCOVFunction *Func = *I;
> + uint64_t EntryCount = Func->getEntryCount();
> + uint32_t BlocksExecuted = 0;
> + for (GCOVFunction::BlockIterator I = Func->block_begin(),
> + E = Func->block_end(); I != E; ++I) {
> + const GCOVBlock *Block = *I;
> + if (Block->getNumDstEdges() && Block->getCount())
> + ++BlocksExecuted;
> + }
> +
> + OS << "function " << Func->getName() << " called " << EntryCount
> + << " returned " << safeDiv(Func->getExitCount()*100, EntryCount)
> + << "% blocks executed "
> + << safeDiv(BlocksExecuted*100, Func->getNumBlocks()-1) << "%\n";
> + }
> + }
> +}
> +
> +/// printBlockInfo - Output counts for each block.
> +void FileInfo::printBlockInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
> + uint32_t LineIndex, uint32_t &BlockNo) const {
> + if (Block.getCount() == 0)
> + OS << " $$$$$:";
> + else
> + OS << format("%9lu:", Block.getCount());
> + OS << format("%5u-block %2u\n", LineIndex+1, BlockNo++);
> +}
> +
> +/// printBranchInfo - Print branch probabilities for blocks that have
> +/// conditional branches.
> +void FileInfo::printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
> + uint32_t LineIndex, uint32_t &EdgeNo) const {
> + if (Block.getNumDstEdges() < 2)
> + return;
> +
> + SmallVector<uint64_t, 16> BranchCounts;
> + uint64_t TotalCounts = 0;
> + for (GCOVBlock::EdgeIterator I = Block.dst_begin(), E = Block.dst_end();
> + I != E; ++I) {
> + const GCOVEdge *Edge = *I;
> + BranchCounts.push_back(Edge->Count);
> + TotalCounts += Edge->Count;
> + }
> +
> + for (SmallVectorImpl<uint64_t>::const_iterator I = BranchCounts.begin(),
> + E = BranchCounts.end(); I != E; ++I) {
> + if (TotalCounts)
> + OS << format("branch %2u taken %u%%\n", EdgeNo++,
> + branchDiv(*I, TotalCounts));
> + else
> + OS << format("branch %2u never executed\n", EdgeNo++);
> + }
> +}
> diff --git a/test/tools/llvm-cov/Inputs/test_-a_-b.cpp.gcov b/test/tools/llvm-cov/Inputs/test_-a_-b.cpp.gcov
> new file mode 100644
> index 0000000..ae21037
> --- /dev/null
> +++ b/test/tools/llvm-cov/Inputs/test_-a_-b.cpp.gcov
> @@ -0,0 +1,134 @@
> + -: 0:Source:test.cpp
> + -: 0:Graph:test.gcno
> + -: 0:Data:test.gcda
> + -: 0:Runs:2
> + -: 0:Programs:1
> + -: 1:#include "test.h"
> + -: 2:#include <cstdlib>
> + -: 3:
> + -: 4:bool on = false;
> + -: 5:int len = 42;
> + -: 6:double grid[10][10] = {0};
> + -: 7:const char * hello = "world";
> + -: 8:const char * world = "hello";
> + -: 9:
> +function _ZN1A1BEv called 8589934592 returned 100% blocks executed 100%
> +8589934592: 10:void A::B() {}
> +8589934592: 10-block 0
> + -: 11:
> +function _Z7uselessv called 0 returned 0% blocks executed 0%
> + #####: 12:void useless() {}
> + $$$$$: 12-block 0
> + -: 13:
> +function _Z12more_uselessv called 0 returned 0% blocks executed 0%
> + -: 14:double more_useless() {
> + #####: 15: return 0;
> + $$$$$: 15-block 0
> + -: 16:}
> + -: 17:
> +function _Z3foov called 2 returned 100% blocks executed 100%
> + -: 18:int foo() {
> + 2: 19: on = true;
> + 2: 20: return 3;
> + 2: 20-block 0
> + -: 21:}
> + -: 22:
> +function _Z3barv called 0 returned 0% blocks executed 0%
> + -: 23:int bar() {
> + #####: 24: len--;
> + #####: 25: return foo() + 45;
> + $$$$$: 25-block 0
> + -: 26:}
> + -: 27:
> +function _Z6assignii called 8 returned 100% blocks executed 100%
> + 8: 28:void assign(int ii, int jj) {
> + 8: 29: grid[ii][jj] = (ii+1) * (jj+1);
> + 8: 30:}
> + 8: 30-block 0
> + -: 31:
> +function _Z15initialize_gridv called 2 returned 100% blocks executed 100%
> + -: 32:void initialize_grid() {
> + 6: 33: for (int ii = 0; ii < 2; ii++)
> + 2: 33-block 0
> + 6: 33-block 1
> +branch 0 taken 67%
> +branch 1 taken 33%
> + 4: 33-block 2
> + 12: 34: for (int jj = 0; jj < 2; jj++)
> + 4: 34-block 0
> + 12: 34-block 1
> +branch 0 taken 67%
> +branch 1 taken 33%
> + 8: 34-block 2
> + 8: 35: assign(ii, jj);
> + 8: 35-block 0
> + 4: 35-block 1
> + 2: 36:}
> + 2: 36-block 0
> + -: 37:
> +function main called 2 returned 100% blocks executed 94%
> + -: 38:int main() {
> + 2: 39: initialize_grid();
> + -: 40:
> + 2: 41: int a = 2;
> + 2: 42: on = rand() % 2;
> + 2: 43: if (on) {
> + 2: 43-block 0
> +branch 0 taken 100%
> +branch 1 taken 0%
> + 2: 44: foo();
> + 2: 45: ++a;
> + 2: 46: } else {
> + 2: 46-block 0
> + #####: 47: bar();
> + #####: 48: a += rand();
> + $$$$$: 48-block 0
> + -: 49: }
> + -: 50:
> + 22: 51: for (int ii = 0; ii < 10; ++ii) {
> + 2: 51-block 0
> + 22: 51-block 1
> +branch 0 taken 91%
> +branch 1 taken 9%
> + 20: 51-block 2
> + 20: 52: switch (rand() % 5) {
> + 20: 52-block 0
> +branch 0 taken 20%
> +branch 1 taken 0%
> +branch 2 taken 10%
> +branch 3 taken 30%
> +branch 4 taken 40%
> + -: 53: case 0:
> + 4: 54: a += rand();
> + 4: 55: break;
> + 4: 55-block 0
> + -: 56: case 1:
> + -: 57: case 2:
> + 2: 58: a += rand() / rand();
> + 2: 59: break;
> + 2: 59-block 0
> + -: 60: case 3:
> + 6: 61: a -= rand();
> + 6: 62: break;
> + 6: 62-block 0
> + -: 63: default:
> + 8: 64: a = -1;
> + 8: 65: }
> + 8: 65-block 0
> + 20: 66: }
> + 20: 66-block 0
> + -: 67:
> + 2: 68: A thing;
> +8589934594: 69: for (uint64_t ii = 0; ii < 4294967296; ++ii)
> + 2: 69-block 0
> +8589934594: 69-block 1
> +branch 0 taken 99%
> +branch 1 taken 1%
> +8589934592: 69-block 2
> +8589934592: 70: thing.B();
> +8589934592: 70-block 0
> + -: 71:
> + 2: 72: return a + 8 + grid[2][3] + len;
> + 2: 72-block 0
> + -: 73: return more_useless();
> + -: 74:}
> diff --git a/test/tools/llvm-cov/Inputs/test_-a_-b.h.gcov b/test/tools/llvm-cov/Inputs/test_-a_-b.h.gcov
> new file mode 100644
> index 0000000..f3dabcb
> --- /dev/null
> +++ b/test/tools/llvm-cov/Inputs/test_-a_-b.h.gcov
> @@ -0,0 +1,12 @@
> + -: 0:Source:./test.h
> + -: 0:Graph:test.gcno
> + -: 0:Data:test.gcda
> + -: 0:Runs:2
> + -: 0:Programs:1
> +function _ZN1AC1Ev called 2 returned 100% blocks executed 100%
> +function _ZN1AC2Ev called 2 returned 100% blocks executed 100%
> + 2: 1:struct A {
> + 2: 1-block 0
> + 2: 1-block 1
> + -: 2: virtual void B();
> + -: 3:};
> diff --git a/test/tools/llvm-cov/llvm-cov.test b/test/tools/llvm-cov/llvm-cov.test
> index 43725a3..bf0fb07 100644
> --- a/test/tools/llvm-cov/llvm-cov.test
> +++ b/test/tools/llvm-cov/llvm-cov.test
> @@ -13,6 +13,10 @@ 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: diff -aub test_-a_-b.cpp.gcov test.cpp.gcov
> +RUN: diff -aub test_-a_-b.h.gcov test.h.gcov
> +
> RUN: not llvm-cov -gcno=test_read_fail.gcno -gcda=test.gcda
>
> RUN: not llvm-cov -gcno=test.gcno -gcda=test_file_checksum_fail.gcda
> diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp
> index 235670b..fd4fa24 100644
> --- a/tools/llvm-cov/llvm-cov.cpp
> +++ b/tools/llvm-cov/llvm-cov.cpp
> @@ -33,6 +33,9 @@ InputGCDA("gcda", cl::desc("<input gcda file>"), cl::init(""));
> static cl::opt<bool>
> AllBlocks("a", cl::init(false), cl::desc("display all block info"));
>
> +static cl::opt<bool>
> +BranchProb("b", cl::init(false), cl::desc("display branch info"));
> +
> //===----------------------------------------------------------------------===//
> int main(int argc, char **argv) {
> // Print a stack trace if we signal out.
> @@ -73,8 +76,9 @@ int main(int argc, char **argv) {
> if (DumpGCOV)
> GF.dump();
>
> - FileInfo FI;
> + GCOVOptions Options(AllBlocks, BranchProb);
> + FileInfo FI(Options);
> GF.collectLineCounts(FI);
> - FI.print(InputGCNO, InputGCDA, GCOVOptions(AllBlocks));
> + FI.print(InputGCNO, InputGCDA);
> return 0;
> }
More information about the llvm-commits
mailing list