23 #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()");
61 if (Version != GCDAVersion) {
62 errs() <<
"GCOV versions do not match.\n";
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";
79 if (!Functions[
i]->
readGCDA(Buffer, Version))
108 for (
const auto &FPtr : Functions)
115 for (
const auto &FPtr : Functions)
116 FPtr->collectLineCounts(FI);
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
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);
196 if (!Buff.
readInt(LineTableLength))
203 if (BlockNo >= BlockCount) {
204 errs() <<
"Unexpected block number: " << BlockNo <<
" (in " << Name
221 errs() <<
"Multiple sources for a single basic block: " << Filename
222 <<
" != " << F <<
" (in " << Name <<
").\n";
251 if (!Buff.
readInt(HeaderLength))
259 if (Ident != GCDAIdent) {
260 errs() <<
"Function identifiers do not match: " << Ident
261 <<
" != " << GCDAIdent <<
" (in " << Name <<
").\n";
266 if (!Buff.
readInt(GCDAChecksum))
268 if (Checksum != GCDAChecksum) {
269 errs() <<
"Function checksums do not match: " << Checksum
270 <<
" != " << GCDAChecksum <<
" (in " << Name <<
").\n";
276 if (!Buff.
readInt(CfgChecksum))
280 <<
" != " << CfgChecksum <<
" (in " << Name <<
").\n";
289 if (Name != GCDAName) {
290 errs() <<
"Function names do not match: " << Name <<
" != " << GCDAName
297 errs() <<
"Arc tag not found (in " << Name <<
").\n";
308 for (
uint32_t BlockNo = 0; Count > 0; ++BlockNo) {
310 if (BlockNo >= Blocks.size()) {
311 errs() <<
"Unexpected number of edges (in " << Name <<
").\n";
314 if (BlockNo == Blocks.size() - 1)
315 errs() <<
"(" << Name <<
") has arcs from exit block.\n";
320 errs() <<
"Unexpected number of edges (in " << Name <<
").\n";
337 return Blocks.front()->getCount();
343 return Blocks.back()->getCount();
348 dbgs() <<
"===== " << Name <<
" (" << Ident <<
") @ " << Filename <<
":"
349 << LineNumber <<
"\n";
350 for (
const auto &Block : Blocks)
362 for (
const auto &Block : Blocks)
363 Block->collectLineCounts(FI);
380 assert(DstEdgeNo < DstEdges.size());
381 DstEdges[DstEdgeNo]->Count =
N;
383 if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges())
384 DstEdges[DstEdgeNo]->Dst.Counter += N;
390 if (!DstEdgesAreSorted) {
391 SortDstEdgesFunctor SortEdges;
392 std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges);
405 dbgs() <<
"Block : " << Number <<
" Counter : " << Counter <<
"\n";
406 if (!SrcEdges.empty()) {
407 dbgs() <<
"\tSource Edges : ";
408 for (
const GCOVEdge *Edge : SrcEdges)
409 dbgs() << Edge->Src.Number <<
" (" << Edge->Count <<
"), ";
412 if (!DstEdges.empty()) {
413 dbgs() <<
"\tDestination Edges : ";
414 for (
const GCOVEdge *Edge : DstEdges)
415 dbgs() << Edge->Dst.Number <<
" (" << Edge->Count <<
"), ";
418 if (!Lines.
empty()) {
419 dbgs() <<
"\tLines : ";
421 dbgs() << (
N) <<
",";
433 return Numerator / Divisor;
442 if (Numerator == Divisor)
445 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
454 struct formatBranchInfo {
455 formatBranchInfo(
const GCOV::Options &Options, uint64_t Count, uint64_t Total)
456 : Options(Options), Count(Count), Total(Total) {}
460 OS <<
"never executed";
461 else if (Options.BranchCount)
462 OS <<
"taken " << Count;
464 OS <<
"taken " <<
branchDiv(Count, Total) <<
"%";
478 std::unique_ptr<MemoryBuffer> Buffer;
485 if (std::error_code EC = BufferOrErr.
getError()) {
486 errs() << Filename <<
": " <<
EC.message() <<
"\n";
489 Buffer = std::move(BufferOrErr.
get());
490 Remaining = Buffer->getBuffer();
493 bool empty() {
return Remaining.empty(); }
499 std::tie(Line, Remaining) = Remaining.
split(
"\n");
500 OS <<
format(
"%5u:", LineNum) << Line <<
"\n";
516 for (I = S = Filename.
begin(), E = Filename.
end(); I !=
E; ++
I) {
520 if (I - S == 1 && *S ==
'.') {
522 }
else if (I - S == 2 && *S ==
'.' && *(S + 1) ==
'.') {
540 std::string FileInfo::getCoveragePath(
StringRef Filename,
548 std::string CoveragePath;
556 std::unique_ptr<raw_ostream>
557 FileInfo::openCoveragePath(
StringRef CoveragePath) {
559 return llvm::make_unique<raw_null_ostream>();
562 auto OS = llvm::make_unique<raw_fd_ostream>(CoveragePath, EC,
565 errs() << EC.message() <<
"\n";
566 return llvm::make_unique<raw_null_ostream>();
568 return std::move(OS);
574 for (
const auto &LI : LineInfo) {
576 auto AllLines = LineConsumer(Filename);
578 std::string CoveragePath = getCoveragePath(Filename, MainFilename);
579 std::unique_ptr<raw_ostream> CovStream = openCoveragePath(CoveragePath);
582 CovOS <<
" -: 0:Source:" << Filename <<
"\n";
583 CovOS <<
" -: 0:Graph:" << GCNOFile <<
"\n";
584 CovOS <<
" -: 0:Data:" << GCDAFile <<
"\n";
585 CovOS <<
" -: 0:Runs:" << RunCount <<
"\n";
586 CovOS <<
" -: 0:Programs:" << ProgramCount <<
"\n";
588 const LineData &Line = LI.second;
589 GCOVCoverage FileCoverage(Filename);
590 for (
uint32_t LineIndex = 0; LineIndex < Line.LastLine || !
AllLines.empty();
594 if (FuncsIt != Line.Functions.end())
595 printFunctionSummary(CovOS, FuncsIt->second);
599 if (BlocksIt == Line.Blocks.end()) {
602 AllLines.printNext(CovOS, LineIndex + 1);
608 uint64_t LineCount = 0;
612 uint64_t BlockCount = Block->getCount();
613 LineCount = LineCount > BlockCount ? LineCount : BlockCount;
616 LineCount += Block->getCount();
632 if (FuncCoverages.
find(Function) == FuncCoverages.
end()) {
633 std::pair<const GCOVFunction *, GCOVCoverage> KeyValue(
634 Function, GCOVCoverage(Function->
getName()));
635 FuncCoverages.
insert(KeyValue);
637 GCOVCoverage &FuncCoverage = FuncCoverages.
find(Function)->second;
639 if (LineExecs.
find(Function) == LineExecs.
end()) {
640 if (Block->getCount()) {
641 ++FuncCoverage.LinesExec;
642 LineExecs[Function] =
true;
644 LineExecs[Function] =
false;
646 ++FuncCoverage.LogicalLines;
647 }
else if (!LineExecs[Function] && Block->getCount()) {
648 ++FuncCoverage.LinesExec;
649 LineExecs[Function] =
true;
657 CovOS <<
format(
"%9" PRIu64
":", LineCount);
658 ++FileCoverage.LinesExec;
660 ++FileCoverage.LogicalLines;
662 AllLines.printNext(CovOS, LineIndex + 1);
668 if (Block->getLastLine() != LineIndex + 1)
671 printBlockInfo(CovOS, *Block, LineIndex, BlockNo);
673 size_t NumEdges = Block->getNumDstEdges();
675 printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo);
677 printUncondBranchInfo(CovOS, EdgeNo,
678 (*Block->dst_begin())->Count);
683 FileCoverages.
push_back(std::make_pair(CoveragePath, FileCoverage));
688 printFuncCoverage(InfoOS);
689 printFileCoverage(InfoOS);
693 void FileInfo::printFunctionSummary(
raw_ostream &OS,
694 const FunctionVector &Funcs)
const {
696 uint64_t EntryCount =
Func->getEntryCount();
699 if (Block.getNumDstEdges() && Block.getCount())
702 OS <<
"function " <<
Func->getName() <<
" called " << EntryCount
703 <<
" returned " <<
safeDiv(
Func->getExitCount() * 100, EntryCount)
704 <<
"% blocks executed "
705 <<
safeDiv(BlocksExec * 100,
Func->getNumBlocks() - 1) <<
"%\n";
716 OS <<
format(
"%5u-block %2u\n", LineIndex + 1, BlockNo++);
721 GCOVCoverage &Coverage,
uint32_t &EdgeNo) {
723 uint64_t TotalCounts = 0;
726 TotalCounts += Edge->Count;
728 ++Coverage.BranchesExec;
730 ++Coverage.BranchesTaken;
735 GCOVCoverage &FuncCoverage = FuncCoverages.
find(Function)->second;
737 ++FuncCoverage.BranchesExec;
739 ++FuncCoverage.BranchesTaken;
740 ++FuncCoverage.Branches;
744 for (uint64_t
N : BranchCounts)
745 OS <<
format(
"branch %2u ", EdgeNo++)
746 << formatBranchInfo(Options,
N, TotalCounts) <<
"\n";
751 uint64_t Count)
const {
752 OS <<
format(
"unconditional %2u ", EdgeNo++)
753 << formatBranchInfo(Options, Count, Count) <<
"\n";
759 const GCOVCoverage &Coverage)
const {
760 OS <<
format(
"Lines executed:%.2f%% of %u\n",
761 double(Coverage.LinesExec) * 100 / Coverage.LogicalLines,
762 Coverage.LogicalLines);
764 if (Coverage.Branches) {
765 OS <<
format(
"Branches executed:%.2f%% of %u\n",
766 double(Coverage.BranchesExec) * 100 / Coverage.Branches,
768 OS <<
format(
"Taken at least once:%.2f%% of %u\n",
769 double(Coverage.BranchesTaken) * 100 / Coverage.Branches,
772 OS <<
"No branches\n";
779 void FileInfo::printFuncCoverage(
raw_ostream &OS)
const {
780 for (
const auto &
FC : FuncCoverages) {
781 const GCOVCoverage &Coverage =
FC.second;
782 OS <<
"Function '" << Coverage.Name <<
"'\n";
783 printCoverage(OS, Coverage);
789 void FileInfo::printFileCoverage(
raw_ostream &OS)
const {
790 for (
const auto &
FC : FileCoverages) {
791 const std::string &Filename =
FC.first;
792 const GCOVCoverage &Coverage =
FC.second;
793 OS <<
"File '" << Coverage.Name <<
"'\n";
794 printCoverage(OS, Coverage);
796 OS << Coverage.Name <<
":creating '" << Filename <<
"'\n";
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.
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds...
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)
uint32_t getChecksum() const
A struct for passing gcov options between functions.
void dump() const
dump - Dump GCOVFile content to dbgs() for debugging purposes.
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)
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool equals(StringRef RHS) const
equals - Check for string equality, this is more efficient than compare() when the relative ordering ...
void collectLineCounts(FileInfo &FI)
collectLineCounts - Collect line counts.
LLVM_NODISCARD bool empty() const
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 ...
void dump() const
dump - Dump GCOVBlock content to dbgs() for debugging purposes.
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)
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
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.
bool readBlockTag()
readBlockTag - If cursor points to a block tag then increment the cursor and return true otherwise re...
static const unsigned End
void dump() const
dump - Dump GCOVFunction content to dbgs() for debugging purposes.
bool readGCNOFormat()
readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
void advanceCursor(uint32_t n)
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
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)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
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.
LLVM_NODISCARD std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
The file should be opened in text mode on platforms that make this distinction.
StringRef getFilename() const
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, int64_t FileSize=-1, bool RequiresNullTerminator=true)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
void collectLineCounts(FileInfo &FI)
collectLineCounts - Collect line counts.
GCOVFunction - Collects function information.
size_t getNumDstEdges() const
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...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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 ...
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.