17 #include "llvm/Config/llvm-config.h" 24 #include <system_error> 43 auto GFun = make_unique<GCOVFunction>(*this);
44 if (!GFun->readGCNO(Buffer, Version))
46 Functions.push_back(std::move(GFun));
49 GCNOInitialized =
true;
56 assert(GCNOInitialized &&
"readGCDA() can only be called after readGCNO()");
62 if (Version != GCDAVersion) {
63 errs() <<
"GCOV versions do not match.\n";
68 if (!Buffer.
readInt(GCDAChecksum))
70 if (Checksum != GCDAChecksum) {
71 errs() <<
"File checksums do not match: " << Checksum
72 <<
" != " << GCDAChecksum <<
".\n";
75 for (
size_t i = 0, e = Functions.size(); i < e; ++i) {
77 errs() <<
"Unexpected number of functions.\n";
80 if (!Functions[i]->
readGCDA(Buffer, Version))
108 for (
const auto &FPtr : Functions)
112 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 120 for (
const auto &FPtr : Functions)
121 FPtr->collectLineCounts(FI);
141 if (!Buff.
readInt(CfgChecksum))
143 if (Parent.getChecksum() != CfgChecksum) {
144 errs() <<
"File checksums do not match: " << Parent.getChecksum()
145 <<
" != " << CfgChecksum <<
" in (" <<
Name <<
").\n";
158 errs() <<
"Block tag not found.\n";
164 for (
uint32_t i = 0, e = BlockCount; i != e; ++i) {
167 Blocks.push_back(make_unique<GCOVBlock>(*
this, i));
175 EdgeCount = (EdgeCount - 1) / 2;
179 if (BlockNo >= BlockCount) {
180 errs() <<
"Unexpected block number: " << BlockNo <<
" (in " <<
Name 184 for (
uint32_t i = 0, e = EdgeCount; i != e; ++i) {
188 Edges.push_back(make_unique<GCOVEdge>(*Blocks[BlockNo], *Blocks[Dst]));
189 GCOVEdge *Edge = Edges.back().get();
190 Blocks[BlockNo]->addDstEdge(Edge);
191 Blocks[Dst]->addSrcEdge(Edge);
201 if (!Buff.
readInt(LineTableLength))
208 if (BlockNo >= BlockCount) {
209 errs() <<
"Unexpected block number: " << BlockNo <<
" (in " <<
Name 226 errs() <<
"Multiple sources for a single basic block: " << Filename
227 <<
" != " << F <<
" (in " <<
Name <<
").\n";
256 if (!Buff.
readInt(HeaderLength))
264 if (Ident != GCDAIdent) {
265 errs() <<
"Function identifiers do not match: " << Ident
266 <<
" != " << GCDAIdent <<
" (in " <<
Name <<
").\n";
271 if (!Buff.
readInt(GCDAChecksum))
273 if (Checksum != GCDAChecksum) {
274 errs() <<
"Function checksums do not match: " << Checksum
275 <<
" != " << GCDAChecksum <<
" (in " <<
Name <<
").\n";
281 if (!Buff.
readInt(CfgChecksum))
283 if (Parent.getChecksum() != CfgChecksum) {
284 errs() <<
"File checksums do not match: " << Parent.getChecksum()
285 <<
" != " << CfgChecksum <<
" (in " <<
Name <<
").\n";
294 if (
Name != GCDAName) {
295 errs() <<
"Function names do not match: " <<
Name <<
" != " << GCDAName
302 errs() <<
"Arc tag not found (in " <<
Name <<
").\n";
313 for (
uint32_t BlockNo = 0; Count > 0; ++BlockNo) {
315 if (BlockNo >= Blocks.size()) {
316 errs() <<
"Unexpected number of edges (in " <<
Name <<
").\n";
319 if (BlockNo == Blocks.size() - 1)
320 errs() <<
"(" <<
Name <<
") has arcs from exit block.\n";
322 for (
size_t EdgeNo = 0, End = Block.
getNumDstEdges(); EdgeNo < End;
325 errs() <<
"Unexpected number of edges (in " <<
Name <<
").\n";
342 return Blocks.front()->getCount();
348 return Blocks.back()->getCount();
352 OS <<
"===== " <<
Name <<
" (" << Ident <<
") @ " << Filename <<
":" 353 << LineNumber <<
"\n";
354 for (
const auto &Block : Blocks)
358 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 371 for (
const auto &Block : Blocks)
372 Block->collectLineCounts(FI);
389 assert(DstEdgeNo < DstEdges.size());
390 DstEdges[DstEdgeNo]->Count =
N;
392 if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges())
393 DstEdges[DstEdgeNo]->Dst.Counter += N;
399 if (!DstEdgesAreSorted) {
400 SortDstEdgesFunctor SortEdges;
401 std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges);
413 OS <<
"Block : " <<
Number <<
" Counter : " << Counter <<
"\n";
414 if (!SrcEdges.empty()) {
415 OS <<
"\tSource Edges : ";
416 for (
const GCOVEdge *Edge : SrcEdges)
417 OS << Edge->Src.Number <<
" (" << Edge->Count <<
"), ";
420 if (!DstEdges.empty()) {
421 OS <<
"\tDestination Edges : ";
422 for (
const GCOVEdge *Edge : DstEdges)
423 OS << Edge->Dst.Number <<
" (" << Edge->Count <<
"), ";
426 if (!Lines.empty()) {
434 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 449 for (
auto E : Path) {
450 CycleCount = std::min(
E->CyclesCount, CycleCount);
452 for (
auto E : Path) {
453 E->CyclesCount -= CycleCount;
461 auto it =
find(Blocked, U);
462 if (it == Blocked.
end()) {
466 const size_t index = it - Blocked.
begin();
471 for (
auto GB : ToUnblock) {
482 bool FoundCircuit =
false;
484 for (
auto E : V->
dsts()) {
486 if (W < Start ||
find(Blocks, W) == Blocks.
end()) {
496 }
else if (
find(Blocked, W) == Blocked.
end() &&
508 for (
auto E : V->
dsts()) {
510 if (W < Start ||
find(Blocks, W) == Blocks.
end()) {
513 const size_t index =
find(Blocked, W) - Blocked.
begin();
515 if (
find(List, V) == List.
end()) {
526 for (
auto Block : Blocks) {
540 for (
auto Block : Blocks) {
541 if (Block->getNumSrcEdges() == 0) {
544 Count += Block->getCount();
547 for (
auto E : Block->srcs()) {
549 if (
find(Blocks, W) == Blocks.end()) {
554 for (
auto E : Block->dsts()) {
555 E->CyclesCount =
E->Count;
571 return Numerator / Divisor;
580 if (Numerator == Divisor)
583 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
592 struct formatBranchInfo {
593 formatBranchInfo(
const GCOV::Options &Options, uint64_t Count, uint64_t Total)
594 : Options(Options), Count(Count), Total(Total) {}
598 OS <<
"never executed";
600 OS <<
"taken " << Count;
602 OS <<
"taken " <<
branchDiv(Count, Total) <<
"%";
616 std::unique_ptr<MemoryBuffer> Buffer;
623 if (std::error_code EC = BufferOrErr.
getError()) {
624 errs() << Filename <<
": " << EC.message() <<
"\n";
627 Buffer = std::move(BufferOrErr.
get());
628 Remaining = Buffer->getBuffer();
637 std::tie(Line, Remaining) = Remaining.
split(
"\n");
638 OS <<
format(
"%5u:", LineNum) << Line <<
"\n";
654 for (I = S = Filename.
begin(), E = Filename.
end(); I !=
E; ++
I) {
658 if (I - S == 1 && *S ==
'.') {
660 }
else if (I - S == 2 && *S ==
'.' && *(S + 1) ==
'.') {
680 if (Options.NoOutput)
686 std::string CoveragePath;
687 if (Options.LongFileNames && !Filename.
equals(MainFilename))
694 std::unique_ptr<raw_ostream>
696 if (Options.NoOutput)
697 return llvm::make_unique<raw_null_ostream>();
703 errs() << EC.message() <<
"\n";
704 return llvm::make_unique<raw_null_ostream>();
706 return std::move(OS);
713 for (
const auto &LI : LineInfo)
718 auto AllLines = LineConsumer(Filename);
720 std::string CoveragePath = getCoveragePath(Filename, MainFilename);
721 std::unique_ptr<raw_ostream> CovStream = openCoveragePath(CoveragePath);
724 CovOS <<
" -: 0:Source:" << Filename <<
"\n";
725 CovOS <<
" -: 0:Graph:" << GCNOFile <<
"\n";
726 CovOS <<
" -: 0:Data:" << GCDAFile <<
"\n";
727 CovOS <<
" -: 0:Runs:" << RunCount <<
"\n";
728 CovOS <<
" -: 0:Programs:" << ProgramCount <<
"\n";
730 const LineData &Line = LineInfo[Filename];
732 for (
uint32_t LineIndex = 0; LineIndex < Line.
LastLine || !AllLines.empty();
734 if (Options.BranchInfo) {
737 printFunctionSummary(CovOS, FuncsIt->second);
744 AllLines.printNext(CovOS, LineIndex + 1);
751 if (Options.FuncCoverage) {
764 if (FuncCoverages.find(Function) == FuncCoverages.end()) {
765 std::pair<const GCOVFunction *, GCOVCoverage> KeyValue(
767 FuncCoverages.insert(KeyValue);
769 GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second;
771 if (LineExecs.
find(Function) == LineExecs.
end()) {
772 if (Block->getCount()) {
774 LineExecs[Function] =
true;
776 LineExecs[Function] =
false;
779 }
else if (!LineExecs[Function] && Block->getCount()) {
781 LineExecs[Function] =
true;
790 CovOS <<
format(
"%9" PRIu64
":", LineCount);
795 AllLines.printNext(CovOS, LineIndex + 1);
801 if (Block->getLastLine() != LineIndex + 1)
803 if (Options.AllBlocks)
804 printBlockInfo(CovOS, *Block, LineIndex, BlockNo);
805 if (Options.BranchInfo) {
806 size_t NumEdges = Block->getNumDstEdges();
808 printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo);
809 else if (Options.UncondBranch && NumEdges == 1)
810 printUncondBranchInfo(CovOS, EdgeNo,
811 (*Block->dst_begin())->Count);
816 FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage));
820 if (Options.FuncCoverage)
821 printFuncCoverage(InfoOS);
822 printFileCoverage(InfoOS);
829 uint64_t EntryCount = Func->getEntryCount();
831 for (
const GCOVBlock &Block : Func->blocks())
832 if (Block.getNumDstEdges() && Block.getCount())
835 OS <<
"function " << Func->getName() <<
" called " << EntryCount
836 <<
" returned " <<
safeDiv(Func->getExitCount() * 100, EntryCount)
837 <<
"% blocks executed " 838 <<
safeDiv(BlocksExec * 100, Func->getNumBlocks() - 1) <<
"%\n";
849 OS <<
format(
"%5u-block %2u\n", LineIndex + 1, BlockNo++);
856 uint64_t TotalCounts = 0;
859 TotalCounts += Edge->Count;
866 if (Options.FuncCoverage) {
868 GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second;
877 for (uint64_t
N : BranchCounts)
878 OS <<
format(
"branch %2u ", EdgeNo++)
879 << formatBranchInfo(Options,
N, TotalCounts) <<
"\n";
884 uint64_t Count)
const {
885 OS <<
format(
"unconditional %2u ", EdgeNo++)
886 << formatBranchInfo(Options, Count, Count) <<
"\n";
893 OS <<
format(
"Lines executed:%.2f%% of %u\n",
896 if (Options.BranchInfo) {
898 OS <<
format(
"Branches executed:%.2f%% of %u\n",
901 OS <<
format(
"Taken at least once:%.2f%% of %u\n",
905 OS <<
"No branches\n";
913 for (
const auto &
FC : FuncCoverages) {
915 OS <<
"Function '" << Coverage.
Name <<
"'\n";
916 printCoverage(OS, Coverage);
923 for (
const auto &
FC : FileCoverages) {
924 const std::string &Filename =
FC.first;
926 OS <<
"File '" << Coverage.
Name <<
"'\n";
927 printCoverage(OS, Coverage);
928 if (!Options.NoOutput)
929 OS << Coverage.
Name <<
":creating '" << Filename <<
"'\n";
Represents either an error or a value T.
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.
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
bool readInt(uint32_t &Val)
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
bool readGCDAFormat()
readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
static void getCyclesCount(const BlockVector &Blocks, uint64_t &Count)
Get the count for the list of blocks which lie on the same line.
GCOVEdge - Collects edge information.
This class represents lattice values for constants.
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.
bool readLineTag()
readLineTag - If cursor points to a line tag then increment the cursor and return true otherwise retu...
void setProgramCount(uint32_t Programs)
void push_back(const T &Elt)
void printFuncCoverage(raw_ostream &OS) const
bool readString(StringRef &Str)
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block, uint32_t LineIndex, uint32_t &BlockNo) const
printBlockInfo - Output counts for each block.
A struct for passing gcov options between functions.
uint64_t getCursor() const
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.
void print(raw_ostream &OS) const
amdgpu Simplify well known AMD library false Value Value const Twine & Name
uint64_t getCount() const
static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor)
void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const
printFunctionSummary - Print function and block summary.
void printFileCoverage(raw_ostream &OS) const
std::string getCoveragePath(StringRef Filename, StringRef MainFilename)
void collectLineCounts(FileInfo &FI)
collectLineCounts - Collect line counts.
StringRef str() const
Explicit conversion to StringRef.
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.
StringRef getName() const
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const
empty - Check if the string is empty.
GCOVBlock - Collects block information.
void sortDstEdges()
sortDstEdges - Sort destination edges by block number, nop if already sorted.
bool readInt64(uint64_t &Val)
void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const
void collectLineCounts(FileInfo &FI)
collectLineCounts - Collect line counts.
void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block, GCOVCoverage &Coverage, uint32_t &EdgeNo)
printBranchInfo - Print conditional branch probabilities.
std::unique_ptr< raw_ostream > openCoveragePath(StringRef CoveragePath)
iterator find(const_arg_type_t< KeyT > Val)
void append(in_iter S, in_iter E)
Append from an iterator pair.
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
iterator_range< EdgeIterator > dsts() const
bool readBlockTag()
readBlockTag - If cursor points to a block tag then increment the cursor and return true otherwise re...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
std::error_code getError() const
uint64_t getExitCount() const
getExitCount - Get the number of times the function returned by retrieving the exit block's count...
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
iterator erase(const_iterator CI)
auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range))
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly...
bool readEdgeTag()
readEdgeTag - If cursor points to an edge tag then increment the cursor and return true otherwise ret...
void sort(IteratorTy Start, IteratorTy End)
constexpr bool empty(const T &RangeOrContainer)
Test whether RangeOrContainer is empty. Similar to C++17 std::empty.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
LLVM_NODISCARD std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
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.
void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo, uint64_t Count) const
printUncondBranchInfo - Print unconditional branch probabilities.
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 ...
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.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
void dump() const
dump - Dump GCOVFile content to dbgs() for debugging purposes.
size_t getNumDstEdges() const
static uint64_t getCycleCount(const Edges &Path)
Get the count for the detected cycle.
GCOVFunction - Collects function information.
void emplace_back(ArgTypes &&... Args)
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor)
static uint64_t getLineCount(const BlockVector &Blocks)
Get the count for the list of blocks which lie on the same line.
static bool lookForCircuit(const GCOVBlock *V, const GCOVBlock *Start, Edges &Path, BlockVector &Blocked, BlockVectorLists &BlockLists, const BlockVector &Blocks, uint64_t &Count)
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)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
~GCOVBlock()
~GCOVBlock - Delete GCOVBlock and its content.
This class implements an extremely fast bulk output stream that can only output to a stream...
static void unblock(const GCOVBlock *U, BlockVector &Blocked, BlockVectorLists &BlockLists)
Unblock a vertex previously marked as blocked.
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.
void print(raw_ostream &OS) const
void print(raw_ostream &OS) const
void dump() const
dump - Dump GCOVFunction content to dbgs() for debugging purposes.
uint64_t getEntryCount() const
getEntryCount - Get the number of times the function was called by retrieving the entry block's count...