mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
[gcov] Refactor llvm-cov gcov and add SourceInfo
This commit is contained in:
@@ -192,6 +192,9 @@ public:
|
||||
void dump() const;
|
||||
void collectLineCounts(FileInfo &FI);
|
||||
|
||||
std::vector<std::string> filenames;
|
||||
StringMap<unsigned> filenameToIdx;
|
||||
|
||||
private:
|
||||
bool GCNOInitialized = false;
|
||||
GCOV::GCOVVersion Version;
|
||||
@@ -201,6 +204,11 @@ private:
|
||||
std::map<uint32_t, GCOVFunction *> IdentToFunction;
|
||||
uint32_t RunCount = 0;
|
||||
uint32_t ProgramCount = 0;
|
||||
|
||||
using iterator = pointee_iterator<
|
||||
SmallVectorImpl<std::unique_ptr<GCOVFunction>>::const_iterator>;
|
||||
iterator begin() const { return iterator(Functions.begin()); }
|
||||
iterator end() const { return iterator(Functions.end()); }
|
||||
};
|
||||
|
||||
struct GCOVArc {
|
||||
@@ -220,10 +228,10 @@ public:
|
||||
using BlockIterator = pointee_iterator<
|
||||
SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
|
||||
|
||||
GCOVFunction(GCOVFile &P) {}
|
||||
GCOVFunction(GCOVFile &file) : file(file) {}
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
StringRef getFilename() const { return Filename; }
|
||||
StringRef getFilename() const;
|
||||
size_t getNumBlocks() const { return Blocks.size(); }
|
||||
uint64_t getEntryCount() const;
|
||||
uint64_t getExitCount() const;
|
||||
@@ -238,6 +246,7 @@ public:
|
||||
void dump() const;
|
||||
void collectLineCounts(FileInfo &FI);
|
||||
|
||||
GCOVFile &file;
|
||||
uint32_t ident = 0;
|
||||
uint32_t linenoChecksum;
|
||||
uint32_t cfgChecksum = 0;
|
||||
@@ -247,7 +256,7 @@ public:
|
||||
uint32_t endColumn = 0;
|
||||
uint8_t artificial = 0;
|
||||
StringRef Name;
|
||||
StringRef Filename;
|
||||
unsigned srcIdx;
|
||||
SmallVector<std::unique_ptr<GCOVBlock>, 0> Blocks;
|
||||
SmallVector<std::unique_ptr<GCOVArc>, 0> arcs, treeArcs;
|
||||
};
|
||||
@@ -312,6 +321,28 @@ public:
|
||||
SmallVector<uint32_t, 16> Lines;
|
||||
};
|
||||
|
||||
struct GCOVCoverage {
|
||||
GCOVCoverage() = default;
|
||||
GCOVCoverage(StringRef Name) : Name(Name) {}
|
||||
|
||||
StringRef Name;
|
||||
|
||||
uint32_t LogicalLines = 0;
|
||||
uint32_t LinesExec = 0;
|
||||
|
||||
uint32_t Branches = 0;
|
||||
uint32_t BranchesExec = 0;
|
||||
uint32_t BranchesTaken = 0;
|
||||
};
|
||||
|
||||
struct SourceInfo {
|
||||
StringRef filename;
|
||||
std::string name;
|
||||
std::vector<GCOVFunction *> functions;
|
||||
GCOVCoverage coverage;
|
||||
SourceInfo(StringRef filename) : filename(filename) {}
|
||||
};
|
||||
|
||||
class FileInfo {
|
||||
protected:
|
||||
// It is unlikely--but possible--for multiple functions to be on the same
|
||||
@@ -332,20 +363,8 @@ protected:
|
||||
uint32_t LastLine = 0;
|
||||
};
|
||||
|
||||
struct GCOVCoverage {
|
||||
GCOVCoverage(StringRef Name) : Name(Name) {}
|
||||
|
||||
StringRef Name;
|
||||
|
||||
uint32_t LogicalLines = 0;
|
||||
uint32_t LinesExec = 0;
|
||||
|
||||
uint32_t Branches = 0;
|
||||
uint32_t BranchesExec = 0;
|
||||
uint32_t BranchesTaken = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
friend class GCOVFile;
|
||||
FileInfo(const GCOV::Options &Options) : Options(Options) {}
|
||||
|
||||
void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
|
||||
@@ -364,7 +383,7 @@ public:
|
||||
void setRunCount(uint32_t Runs) { RunCount = Runs; }
|
||||
void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
|
||||
void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
|
||||
StringRef GCDAFile, GCOV::GCOVVersion Version);
|
||||
StringRef GCDAFile, GCOVFile &file);
|
||||
|
||||
protected:
|
||||
std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
|
||||
@@ -386,11 +405,10 @@ protected:
|
||||
uint32_t RunCount = 0;
|
||||
uint32_t ProgramCount = 0;
|
||||
|
||||
using FileCoverageList = SmallVector<std::pair<std::string, GCOVCoverage>, 4>;
|
||||
using FuncCoverageMap = MapVector<const GCOVFunction *, GCOVCoverage>;
|
||||
|
||||
FileCoverageList FileCoverages;
|
||||
FuncCoverageMap FuncCoverages;
|
||||
std::vector<SourceInfo> sources;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
@@ -68,18 +68,23 @@ bool GCOVFile::readGCNO(GCOVBuffer &buf) {
|
||||
if (Version >= GCOV::V407)
|
||||
fn->cfgChecksum = buf.getWord();
|
||||
buf.readString(fn->Name);
|
||||
StringRef filename;
|
||||
if (Version < GCOV::V800) {
|
||||
buf.readString(fn->Filename);
|
||||
filename = buf.getString();
|
||||
fn->startLine = buf.getWord();
|
||||
} else {
|
||||
fn->artificial = buf.getWord();
|
||||
fn->Filename = buf.getString();
|
||||
filename = buf.getString();
|
||||
fn->startLine = buf.getWord();
|
||||
fn->startColumn = buf.getWord();
|
||||
fn->endLine = buf.getWord();
|
||||
if (Version >= GCOV::V900)
|
||||
fn->endColumn = buf.getWord();
|
||||
}
|
||||
auto r = filenameToIdx.try_emplace(filename, filenameToIdx.size());
|
||||
if (r.second)
|
||||
filenames.emplace_back(filename);
|
||||
fn->srcIdx = r.first->second;
|
||||
IdentToFunction[fn->ident] = fn;
|
||||
} else if (tag == GCOV_TAG_BLOCKS && fn) {
|
||||
if (Version < GCOV::V800) {
|
||||
@@ -224,8 +229,8 @@ bool GCOVFile::readGCDA(GCOVBuffer &buf) {
|
||||
}
|
||||
|
||||
void GCOVFile::print(raw_ostream &OS) const {
|
||||
for (const auto &FPtr : Functions)
|
||||
FPtr->print(OS);
|
||||
for (const GCOVFunction &f : *this)
|
||||
f.print(OS);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
@@ -235,16 +240,23 @@ LLVM_DUMP_METHOD void GCOVFile::dump() const { print(dbgs()); }
|
||||
|
||||
/// collectLineCounts - Collect line counts. This must be used after
|
||||
/// reading .gcno and .gcda files.
|
||||
void GCOVFile::collectLineCounts(FileInfo &FI) {
|
||||
for (const auto &FPtr : Functions)
|
||||
FPtr->collectLineCounts(FI);
|
||||
FI.setRunCount(RunCount);
|
||||
FI.setProgramCount(ProgramCount);
|
||||
void GCOVFile::collectLineCounts(FileInfo &fi) {
|
||||
assert(fi.sources.empty());
|
||||
for (StringRef filename : filenames)
|
||||
fi.sources.emplace_back(filename);
|
||||
for (GCOVFunction &f : *this) {
|
||||
f.collectLineCounts(fi);
|
||||
fi.sources[f.srcIdx].functions.push_back(&f);
|
||||
}
|
||||
fi.setRunCount(RunCount);
|
||||
fi.setProgramCount(ProgramCount);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GCOVFunction implementation.
|
||||
|
||||
StringRef GCOVFunction::getFilename() const { return file.filenames[srcIdx]; }
|
||||
|
||||
/// getEntryCount - Get the number of times the function was called by
|
||||
/// retrieving the entry block's count.
|
||||
uint64_t GCOVFunction::getEntryCount() const {
|
||||
@@ -258,7 +270,7 @@ uint64_t GCOVFunction::getExitCount() const {
|
||||
}
|
||||
|
||||
void GCOVFunction::print(raw_ostream &OS) const {
|
||||
OS << "===== " << Name << " (" << ident << ") @ " << Filename << ":"
|
||||
OS << "===== " << Name << " (" << ident << ") @ " << getFilename() << ":"
|
||||
<< startLine << "\n";
|
||||
for (const auto &Block : Blocks)
|
||||
Block->print(OS);
|
||||
@@ -279,7 +291,7 @@ void GCOVFunction::collectLineCounts(FileInfo &FI) {
|
||||
|
||||
for (const auto &Block : Blocks)
|
||||
Block->collectLineCounts(FI);
|
||||
FI.addFunctionLine(Filename, startLine, this);
|
||||
FI.addFunctionLine(getFilename(), startLine, this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -596,8 +608,7 @@ FileInfo::openCoveragePath(StringRef CoveragePath) {
|
||||
|
||||
/// print - Print source files with collected line count information.
|
||||
void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
|
||||
StringRef GCNOFile, StringRef GCDAFile,
|
||||
GCOV::GCOVVersion Version) {
|
||||
StringRef GCNOFile, StringRef GCDAFile, GCOVFile &file) {
|
||||
SmallVector<StringRef, 4> Filenames;
|
||||
for (const auto &LI : LineInfo)
|
||||
Filenames.push_back(LI.first());
|
||||
@@ -619,7 +630,7 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
|
||||
CovOS << " -: 0:Graph:" << GCNOFile << "\n";
|
||||
CovOS << " -: 0:Data:" << GCDAFile << "\n";
|
||||
CovOS << " -: 0:Runs:" << RunCount << "\n";
|
||||
if (Version < GCOV::V900)
|
||||
if (file.getVersion() < GCOV::V900)
|
||||
CovOS << " -: 0:Programs:" << ProgramCount << "\n";
|
||||
|
||||
const LineData &Line = LineInfo[Filename];
|
||||
@@ -707,7 +718,9 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
|
||||
}
|
||||
}
|
||||
}
|
||||
FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage));
|
||||
SourceInfo &source = sources[file.filenameToIdx.find(Filename)->second];
|
||||
source.name = CoveragePath;
|
||||
source.coverage = FileCoverage;
|
||||
}
|
||||
|
||||
if (!Options.UseStdout) {
|
||||
@@ -816,13 +829,12 @@ void FileInfo::printFuncCoverage(raw_ostream &OS) const {
|
||||
|
||||
// printFileCoverage - Print per-file coverage info.
|
||||
void FileInfo::printFileCoverage(raw_ostream &OS) const {
|
||||
for (const auto &FC : FileCoverages) {
|
||||
const std::string &Filename = FC.first;
|
||||
const GCOVCoverage &Coverage = FC.second;
|
||||
for (const SourceInfo &source : sources) {
|
||||
const GCOVCoverage &Coverage = source.coverage;
|
||||
OS << "File '" << Coverage.Name << "'\n";
|
||||
printCoverage(OS, Coverage);
|
||||
if (!Options.NoOutput)
|
||||
OS << "Creating '" << Filename << "'\n";
|
||||
OS << "Creating '" << source.name << "'\n";
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,18 +131,18 @@ RUN: FileCheck %s --check-prefixes=H,H-A,H-B --match-full-lines --strict-whitesp
|
||||
OUT-FB-NEXT:Taken at least once:81.82% of 11
|
||||
OUT-FB-NEXT:No calls
|
||||
OUT-F-EMPTY:
|
||||
OUT:File './test.h'
|
||||
OUT-NEXT:Lines executed:100.00% of 1
|
||||
OUT-B-NEXT:No branches
|
||||
OUT-B-NEXT:No calls
|
||||
OUTFILE-NEXT:Creating 'test.h.gcov'
|
||||
OUT-EMPTY:
|
||||
OUT-NEXT:File 'test.cpp'
|
||||
OUT:File 'test.cpp'
|
||||
OUT-NEXT:Lines executed:81.40% of 43
|
||||
OUT-B-NEXT:Branches executed:100.00% of 15
|
||||
OUT-B-NEXT:Taken at least once:86.67% of 15
|
||||
OUT-B-NEXT:No calls
|
||||
OUTFILE-NEXT:Creating 'test.cpp.gcov'
|
||||
OUT-EMPTY:
|
||||
OUT-NEXT:File './test.h'
|
||||
OUT-NEXT:Lines executed:100.00% of 1
|
||||
OUT-B-NEXT:No branches
|
||||
OUT-B-NEXT:No calls
|
||||
OUTFILE-NEXT:Creating 'test.h.gcov'
|
||||
|
||||
# Summarize unconditional branches too.
|
||||
RUN: llvm-cov gcov test.c -a -b -u | FileCheck %s --check-prefixes=OUT,OUTFILE,OUT-B
|
||||
@@ -158,13 +158,13 @@ H-C: unconditional 0 taken 1
|
||||
RUN: llvm-cov gcov test.c -gcda=no_such_gcda_file | FileCheck %s --check-prefix=NO-GCDA
|
||||
RUN: diff -aub test_no_gcda.cpp.gcov test.cpp.gcov
|
||||
RUN: diff -aub test_no_gcda.h.gcov test.h.gcov
|
||||
NO-GCDA: File './test.h'
|
||||
NO-GCDA-NEXT: Lines executed:0.00% of 1
|
||||
NO-GCDA-NEXT: Creating 'test.h.gcov'
|
||||
NO-GCDA-EMPTY:
|
||||
NO-GCDA-NEXT: File 'test.cpp'
|
||||
NO-GCDA: File 'test.cpp'
|
||||
NO-GCDA-NEXT: Lines executed:0.00% of 43
|
||||
NO-GCDA-NEXT: Creating 'test.cpp.gcov'
|
||||
NO-GCDA-EMPTY:
|
||||
NO-GCDA-NEXT: File './test.h'
|
||||
NO-GCDA-NEXT: Lines executed:0.00% of 1
|
||||
NO-GCDA-NEXT: Creating 'test.h.gcov'
|
||||
|
||||
# Invalid gcno file.
|
||||
RUN: llvm-cov gcov test.c -gcno=test_read_fail.gcno
|
||||
|
||||
@@ -77,7 +77,7 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
|
||||
|
||||
FileInfo FI(Options);
|
||||
GF.collectLineCounts(FI);
|
||||
FI.print(llvm::outs(), SourceFile, GCNO, GCDA, GF.getVersion());
|
||||
FI.print(llvm::outs(), SourceFile, GCNO, GCDA, GF);
|
||||
}
|
||||
|
||||
int gcovMain(int argc, const char *argv[]) {
|
||||
|
||||
Reference in New Issue
Block a user