24 #include <system_error>
42 auto GFun = make_unique<GCOVFunction>(*this);
43 if (!GFun->readGCNO(Buffer,
Version))
45 Functions.push_back(std::move(GFun));
48 GCNOInitialized =
true;
55 assert(GCNOInitialized &&
"readGCDA() can only be called after readGCNO()");
62 errs() <<
"GCOV versions do not match.\n";
66 uint32_t GCDAChecksum;
67 if (!Buffer.
readInt(GCDAChecksum))
69 if (Checksum != GCDAChecksum) {
70 errs() <<
"File checksums do not match: " << Checksum
71 <<
" != " << GCDAChecksum <<
".\n";
74 for (
size_t i = 0, e = Functions.size(); i < e; ++i) {
76 errs() <<
"Unexpected number of functions.\n";
108 for (
const auto &FPtr : Functions)
115 for (
const auto &FPtr : Functions)
116 FPtr->collectLineCounts(FI);
135 uint32_t CfgChecksum;
136 if (!Buff.
readInt(CfgChecksum))
140 <<
" != " << CfgChecksum <<
" in (" <<
Name <<
").\n";
153 errs() <<
"Block tag not found.\n";
159 for (uint32_t i = 0, e = BlockCount; i != e; ++i) {
162 Blocks.push_back(make_unique<GCOVBlock>(*
this, i));
170 EdgeCount = (EdgeCount - 1) / 2;
174 if (BlockNo >= BlockCount) {
175 errs() <<
"Unexpected block number: " << BlockNo <<
" (in " <<
Name
179 for (uint32_t i = 0, e = EdgeCount; i != e; ++i) {
183 Edges.push_back(make_unique<GCOVEdge>(*Blocks[BlockNo], *Blocks[Dst]));
184 GCOVEdge *Edge = Edges.back().get();
185 Blocks[BlockNo]->addDstEdge(Edge);
186 Blocks[Dst]->addSrcEdge(Edge);
194 uint32_t LineTableLength;
196 if (!Buff.
readInt(LineTableLength))
198 uint32_t EndPos = Buff.
getCursor() + LineTableLength * 4;
203 if (BlockNo >= BlockCount) {
204 errs() <<
"Unexpected block number: " << BlockNo <<
" (in " <<
Name
215 if (Buff.
getCursor() != (EndPos -
sizeof(uint32_t))) {
221 errs() <<
"Multiple sources for a single basic block: " << Filename
222 <<
" != " << F <<
" (in " <<
Name <<
").\n";
226 while (Buff.
getCursor() < (EndPos - 2 *
sizeof(uint32_t))) {
257 if (Ident != GCDAIdent) {
258 errs() <<
"Function identifiers do not match: " << Ident
259 <<
" != " << GCDAIdent <<
" (in " <<
Name <<
").\n";
263 uint32_t GCDAChecksum;
264 if (!Buff.
readInt(GCDAChecksum))
266 if (Checksum != GCDAChecksum) {
267 errs() <<
"Function checksums do not match: " << Checksum
268 <<
" != " << GCDAChecksum <<
" (in " <<
Name <<
").\n";
272 uint32_t CfgChecksum;
274 if (!Buff.
readInt(CfgChecksum))
278 <<
" != " << CfgChecksum <<
" (in " <<
Name <<
").\n";
286 if (
Name != GCDAName) {
287 errs() <<
"Function names do not match: " <<
Name <<
" != " << GCDAName
293 errs() <<
"Arc tag not found (in " <<
Name <<
").\n";
304 for (uint32_t BlockNo = 0; Count > 0; ++BlockNo) {
306 if (BlockNo >= Blocks.size()) {
307 errs() <<
"Unexpected number of edges (in " <<
Name <<
").\n";
310 if (BlockNo == Blocks.size() - 1)
311 errs() <<
"(" <<
Name <<
") has arcs from exit block.\n";
313 for (
size_t EdgeNo = 0, End = Block.
getNumDstEdges(); EdgeNo < End;
316 errs() <<
"Unexpected number of edges (in " <<
Name <<
").\n";
333 return Blocks.front()->getCount();
339 return Blocks.back()->getCount();
344 dbgs() <<
"===== " <<
Name <<
" (" << Ident <<
") @ " << Filename <<
":"
345 << LineNumber <<
"\n";
346 for (
const auto &
Block : Blocks)
358 for (
const auto &
Block : Blocks)
359 Block->collectLineCounts(FI);
376 assert(DstEdgeNo < DstEdges.size());
377 DstEdges[DstEdgeNo]->Count =
N;
379 if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges())
380 DstEdges[DstEdgeNo]->Dst.Counter += N;
386 if (!DstEdgesAreSorted) {
387 SortDstEdgesFunctor SortEdges;
388 std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges);
395 for (uint32_t
N : Lines)
401 dbgs() <<
"Block : " << Number <<
" Counter : " << Counter <<
"\n";
402 if (!SrcEdges.empty()) {
403 dbgs() <<
"\tSource Edges : ";
404 for (
const GCOVEdge *Edge : SrcEdges)
405 dbgs() << Edge->Src.Number <<
" (" << Edge->Count <<
"), ";
408 if (!DstEdges.empty()) {
409 dbgs() <<
"\tDestination Edges : ";
410 for (
const GCOVEdge *Edge : DstEdges)
411 dbgs() << Edge->Dst.Number <<
" (" << Edge->Count <<
"), ";
414 if (!Lines.
empty()) {
415 dbgs() <<
"\tLines : ";
416 for (uint32_t
N : Lines)
417 dbgs() << (
N) <<
",";
426 static uint32_t
safeDiv(uint64_t Numerator, uint64_t Divisor) {
429 return Numerator / Divisor;
435 static uint32_t
branchDiv(uint64_t Numerator, uint64_t Divisor) {
438 if (Numerator == Divisor)
441 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
450 struct formatBranchInfo {
451 formatBranchInfo(
const GCOVOptions &Options, uint64_t Count, uint64_t Total)
452 : Options(Options), Count(Count), Total(Total) {}
456 OS <<
"never executed";
457 else if (Options.BranchCount)
458 OS <<
"taken " << Count;
460 OS <<
"taken " <<
branchDiv(Count, Total) <<
"%";
474 std::unique_ptr<MemoryBuffer> Buffer;
481 if (std::error_code EC = BufferOrErr.
getError()) {
482 errs() << Filename <<
": " << EC.message() <<
"\n";
485 Buffer = std::move(BufferOrErr.
get());
486 Remaining = Buffer->getBuffer();
489 bool empty() {
return Remaining.
empty(); }
490 void printNext(
raw_ostream &OS, uint32_t LineNum) {
495 std::tie(Line, Remaining) = Remaining.
split(
"\n");
496 OS <<
format(
"%5u:", LineNum) << Line <<
"\n";
512 for (I = S = Filename.
begin(), E = Filename.
end(); I != E; ++
I) {
516 if (I - S == 1 && *S ==
'.') {
518 }
else if (I - S == 2 && *S ==
'.' && *(S + 1) ==
'.') {
536 std::string FileInfo::getCoveragePath(
StringRef Filename,
544 std::string CoveragePath;
552 std::unique_ptr<raw_ostream>
553 FileInfo::openCoveragePath(
StringRef CoveragePath) {
555 return llvm::make_unique<raw_null_ostream>();
558 auto OS = llvm::make_unique<raw_fd_ostream>(CoveragePath, EC,
561 errs() << EC.message() <<
"\n";
562 return llvm::make_unique<raw_null_ostream>();
564 return std::move(OS);
570 for (
const auto &LI : LineInfo) {
572 auto AllLines = LineConsumer(Filename);
574 std::string CoveragePath = getCoveragePath(Filename, MainFilename);
575 std::unique_ptr<raw_ostream> CovStream = openCoveragePath(CoveragePath);
578 CovOS <<
" -: 0:Source:" << Filename <<
"\n";
579 CovOS <<
" -: 0:Graph:" << GCNOFile <<
"\n";
580 CovOS <<
" -: 0:Data:" << GCDAFile <<
"\n";
581 CovOS <<
" -: 0:Runs:" << RunCount <<
"\n";
582 CovOS <<
" -: 0:Programs:" << ProgramCount <<
"\n";
584 const LineData &Line = LI.second;
585 GCOVCoverage FileCoverage(Filename);
586 for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty();
590 if (FuncsIt != Line.Functions.end())
591 printFunctionSummary(CovOS, FuncsIt->second);
595 if (BlocksIt == Line.Blocks.end()) {
598 AllLines.printNext(CovOS, LineIndex + 1);
604 uint64_t LineCount = 0;
608 uint64_t BlockCount =
Block->getCount();
609 LineCount = LineCount > BlockCount ? LineCount : BlockCount;
612 LineCount +=
Block->getCount();
628 if (FuncCoverages.
find(Function) == FuncCoverages.
end()) {
629 std::pair<const GCOVFunction *, GCOVCoverage> KeyValue(
630 Function, GCOVCoverage(Function->
getName()));
631 FuncCoverages.
insert(KeyValue);
633 GCOVCoverage &FuncCoverage = FuncCoverages.
find(Function)->second;
635 if (LineExecs.
find(Function) == LineExecs.
end()) {
636 if (
Block->getCount()) {
637 ++FuncCoverage.LinesExec;
642 ++FuncCoverage.LogicalLines;
643 }
else if (!LineExecs[Function] &&
Block->getCount()) {
644 ++FuncCoverage.LinesExec;
653 CovOS <<
format(
"%9" PRIu64
":", LineCount);
654 ++FileCoverage.LinesExec;
656 ++FileCoverage.LogicalLines;
658 AllLines.printNext(CovOS, LineIndex + 1);
660 uint32_t BlockNo = 0;
664 if (
Block->getLastLine() != LineIndex + 1)
667 printBlockInfo(CovOS, *
Block, LineIndex, BlockNo);
669 size_t NumEdges =
Block->getNumDstEdges();
671 printBranchInfo(CovOS, *
Block, FileCoverage, EdgeNo);
673 printUncondBranchInfo(CovOS, EdgeNo,
674 (*
Block->dst_begin())->Count);
679 FileCoverages.
push_back(std::make_pair(CoveragePath, FileCoverage));
684 printFuncCoverage(InfoOS);
685 printFileCoverage(InfoOS);
690 void FileInfo::printFunctionSummary(
raw_ostream &OS,
691 const FunctionVector &Funcs)
const {
693 uint64_t EntryCount =
Func->getEntryCount();
694 uint32_t BlocksExec = 0;
696 if (
Block.getNumDstEdges() &&
Block.getCount())
699 OS <<
"function " <<
Func->getName() <<
" called " << EntryCount
700 <<
" returned " <<
safeDiv(
Func->getExitCount() * 100, EntryCount)
701 <<
"% blocks executed "
702 <<
safeDiv(BlocksExec * 100,
Func->getNumBlocks() - 1) <<
"%\n";
708 uint32_t LineIndex, uint32_t &BlockNo)
const {
713 OS <<
format(
"%5u-block %2u\n", LineIndex + 1, BlockNo++);
718 GCOVCoverage &Coverage, uint32_t &EdgeNo) {
720 uint64_t TotalCounts = 0;
723 TotalCounts += Edge->Count;
725 ++Coverage.BranchesExec;
727 ++Coverage.BranchesTaken;
732 GCOVCoverage &FuncCoverage = FuncCoverages.
find(Function)->second;
734 ++FuncCoverage.BranchesExec;
736 ++FuncCoverage.BranchesTaken;
737 ++FuncCoverage.Branches;
741 for (uint64_t
N : BranchCounts)
742 OS <<
format(
"branch %2u ", EdgeNo++)
743 << formatBranchInfo(Options,
N, TotalCounts) <<
"\n";
747 void FileInfo::printUncondBranchInfo(
raw_ostream &OS, uint32_t &EdgeNo,
748 uint64_t Count)
const {
749 OS <<
format(
"unconditional %2u ", EdgeNo++)
750 << formatBranchInfo(Options, Count, Count) <<
"\n";
756 const GCOVCoverage &Coverage)
const {
757 OS <<
format(
"Lines executed:%.2f%% of %u\n",
758 double(Coverage.LinesExec) * 100 / Coverage.LogicalLines,
759 Coverage.LogicalLines);
761 if (Coverage.Branches) {
762 OS <<
format(
"Branches executed:%.2f%% of %u\n",
763 double(Coverage.BranchesExec) * 100 / Coverage.Branches,
765 OS <<
format(
"Taken at least once:%.2f%% of %u\n",
766 double(Coverage.BranchesTaken) * 100 / Coverage.Branches,
769 OS <<
"No branches\n";
776 void FileInfo::printFuncCoverage(
raw_ostream &OS)
const {
777 for (
const auto &
FC : FuncCoverages) {
778 const GCOVCoverage &Coverage =
FC.second;
779 OS <<
"Function '" << Coverage.Name <<
"'\n";
780 printCoverage(OS, Coverage);
786 void FileInfo::printFileCoverage(
raw_ostream &OS)
const {
787 for (
const auto &
FC : FileCoverages) {
788 const std::string &Filename =
FC.first;
789 const GCOVCoverage &Coverage =
FC.second;
790 OS <<
"File '" << Coverage.Name <<
"'\n";
791 printCoverage(OS, Coverage);
793 OS << Coverage.Name <<
":creating '" << Filename <<
"'\n";
GCOVOptions - A struct for passing gcov options between functions.
void push_back(const T &Elt)
std::error_code getError() const
Represents either an error or a value T.
iterator_range< EdgeIterator > dsts() const
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version)
readGCNO - Read a function from the GCNO buffer.
bool readInt(uint32_t &Val)
bool readGCDAFormat()
readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
GCOVEdge - Collects edge information.
void addFunctionLine(StringRef Filename, uint32_t Line, const GCOVFunction *Function)
void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile, StringRef GCDAFile)
print - Print source files with collected line count information.
uint64_t getCount() const
bool readLineTag()
readLineTag - If cursor points to a line tag then increment the cursor and return true otherwise retu...
void setProgramCount(uint32_t Programs)
bool readString(StringRef &Str)
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
uint32_t getChecksum() const
std::string str() const
str - Get the contents as an std::string.
void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block)
static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths)
Convert a path to a gcov filename.
GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific read operations.
StringRef getName() const
static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor)
void collectLineCounts(FileInfo &FI)
collectLineCounts - Collect line counts.
bool readGCDA(GCOVBuffer &Buffer)
readGCDA - Read GCDA buffer.
bool readArcTag()
readArcTag - If cursor points to an gcda arc tag then increment the cursor and return true otherwise ...
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const
GCOVBlock - Collects block information.
uint64_t getExitCount() const
getExitCount - Get the number of times the function returned by retrieving the exit block's count...
iterator find(const KeyT &Key)
void sortDstEdges()
sortDstEdges - Sort destination edges by block number, nop if already sorted.
bool readInt64(uint64_t &Val)
void collectLineCounts(FileInfo &FI)
collectLineCounts - Collect line counts.
format_object< Ts...> format(const char *Fmt, const Ts &...Vals)
These are helper functions used to produce formatted output.
void append(in_iter S, in_iter E)
Append from an iterator pair.
StringRef filename(StringRef path)
Get filename.
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
void dump() const
dump - Dump GCOVFile content to dbgs() for debugging purposes.
bool readBlockTag()
readBlockTag - If cursor points to a block tag then increment the cursor and return true otherwise re...
bool readGCNOFormat()
readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
void advanceCursor(uint32_t n)
bool readGCNO(GCOVBuffer &Buffer)
readGCNO - Read GCNO buffer.
const GCOVFunction & getParent() const
bool readEdgeTag()
readEdgeTag - If cursor points to an edge tag then increment the cursor and return true otherwise ret...
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, int64_t FileSize=-1)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
void dump() const
dump - Dump GCOVFunction content to dbgs() for debugging purposes.
bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version)
readGCDA - Read a function from the GCDA buffer.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
StringRef str() const
Explicit conversion to StringRef.
bool equals(StringRef RHS) const
equals - Check for string equality, this is more efficient than compare() when the relative ordering ...
The file should be opened in text mode on platforms that make this distinction.
StringRef getFilename() const
void collectLineCounts(FileInfo &FI)
collectLineCounts - Collect line counts.
GCOVFunction - Collects function information.
size_t getNumDstEdges() const
void dump() const
dump - Dump GCOVBlock content to dbgs() for debugging purposes.
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor)
iterator find(const KeyT &Val)
bool readObjectTag()
readObjectTag - If cursor points to an object summary tag then increment the cursor and return true o...
raw_ostream & operator<<(raw_ostream &OS, const APInt &I)
uint64_t getEntryCount() const
getEntryCount - Get the number of times the function was called by retrieving the entry block's count...
uint64_t getCursor() const
~GCOVBlock()
~GCOVBlock - Delete GCOVBlock and its content.
This class implements an extremely fast bulk output stream that can only output to a stream...
bool readProgramTag()
readProgramTag - If cursor points to a program summary tag then increment the cursor and return true ...
virtual void print(raw_ostream &O, const Module *M) const
print - Print out the internal state of the pass.
StringRef - Represent a constant reference to a string, i.e.
bool readFunctionTag()
readFunctionTag - If cursor points to a function tag then increment the cursor and return true otherw...
void addCount(size_t DstEdgeNo, uint64_t N)
addCount - Add to block counter while storing the edge count.
void setRunCount(uint32_t Runs)
bool readGCOVVersion(GCOV::GCOVVersion &Version)
readGCOVVersion - Read GCOV version.
bool empty() const
empty - Check if the string is empty.