1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 10:32:48 +02:00

[gcov] Add -i --intermediate-format

Between gcov 4.9~8, `gcov -i $file` prints coverage information to
$file.gcov in an intermediate text format (single file, instead of
$source.gcov for each source file).

lcov newer than 2019-05-24 detects -i support and uses it to increase
processing speed.  gcov 9 (GCC r265587) removed --intermediate-format
and -i was changed to mean --json-format. However, we consider this
format still useful and support it. geninfo (part of lcov) supports this
format even if we announce that we are compatible with gcov 9.0.0
This commit is contained in:
Fangrui Song 2020-06-16 14:13:51 -07:00
parent 69837fa7b5
commit d1d0909fd1
5 changed files with 164 additions and 14 deletions

View File

@ -46,11 +46,11 @@ enum GCOVVersion { V304, V407, V408, V800, V900 };
/// A struct for passing gcov options between functions.
struct Options {
Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N,
bool T, bool X)
Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L,
bool N, bool T, bool X)
: AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N),
UseStdout(T), HashFilenames(X) {}
PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L),
NoOutput(N), UseStdout(T), HashFilenames(X) {}
bool AllBlocks;
bool BranchInfo;
@ -58,6 +58,7 @@ struct Options {
bool FuncCoverage;
bool PreservePaths;
bool UncondBranch;
bool Intermediate;
bool LongFileNames;
bool NoOutput;
bool UseStdout;

View File

@ -512,6 +512,7 @@ class LineConsumer {
StringRef Remaining;
public:
LineConsumer() = default;
LineConsumer(StringRef Filename) {
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
MemoryBuffer::getFileOrSTDIN(Filename);
@ -615,11 +616,11 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
llvm::sort(Filenames);
for (StringRef Filename : Filenames) {
auto AllLines = LineConsumer(Filename);
auto AllLines =
Options.Intermediate ? LineConsumer() : LineConsumer(Filename);
std::string CoveragePath = getCoveragePath(Filename, MainFilename);
std::unique_ptr<raw_ostream> CovStream;
if (Options.NoOutput)
if (Options.NoOutput || Options.Intermediate)
CovStream = std::make_unique<raw_null_ostream>();
else if (!Options.UseStdout)
CovStream = openCoveragePath(CoveragePath);
@ -723,6 +724,51 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
source.coverage = FileCoverage;
}
if (Options.Intermediate && !Options.NoOutput) {
// gcov 7.* unexpectedly create multiple .gcov files, which was fixed in 8.0
// (PR GCC/82702). We create just one file.
std::string outputPath(sys::path::filename(MainFilename));
std::error_code ec;
raw_fd_ostream os(outputPath + ".gcov", ec, sys::fs::OF_Text);
if (ec) {
errs() << ec.message() << "\n";
return;
}
for (const SourceInfo &source : sources) {
os << "file:" << source.filename << '\n';
for (const GCOVFunction *f : source.functions)
os << "function:" << f->startLine << ',' << f->getEntryCount() << ','
<< f->Name << '\n';
const LineData &line = LineInfo[source.filename];
for (uint32_t lineNum = 0; lineNum != line.LastLine; ++lineNum) {
BlockLines::const_iterator blocksIt = line.Blocks.find(lineNum);
if (blocksIt == line.Blocks.end())
continue;
const BlockVector &blocks = blocksIt->second;
// GCC 8 (r254259) added third third field for Ada:
// lcount:<line>,<count>,<has_unexecuted_blocks>
// We don't need the third field.
os << "lcount:" << (lineNum + 1) << ','
<< GCOVBlock::getLineCount(blocks) << '\n';
if (!Options.BranchInfo)
continue;
for (const GCOVBlock *block : blocks) {
if (block->getLastLine() != lineNum + 1 ||
block->getNumDstEdges() < 2)
continue;
for (const GCOVArc *arc : block->dsts()) {
const char *type = block->getCount()
? arc->Count ? "taken" : "nottaken"
: "notexec";
os << "branch:" << (lineNum + 1) << ',' << type << '\n';
}
}
}
}
}
if (!Options.UseStdout) {
// FIXME: There is no way to detect calls given current instrumentation.
if (Options.FuncCoverage)
@ -833,7 +879,7 @@ void FileInfo::printFileCoverage(raw_ostream &OS) const {
const GCOVCoverage &Coverage = source.coverage;
OS << "File '" << Coverage.Name << "'\n";
printCoverage(OS, Coverage);
if (!Options.NoOutput)
if (!Options.NoOutput && !Options.Intermediate)
OS << "Creating '" << source.name << "'\n";
OS << "\n";
}

View File

@ -19,10 +19,14 @@ int main() { // GCOV: 1: [[@LINE]]:int
// RUN: cp %s %p/Inputs/gcov-8.gc* .
/// FIXME Lines executed:100.00% of 12
// RUN: llvm-cov gcov gcov-8.c | FileCheck %s
// CHECK: File 'gcov-8.c'
// CHECK-NEXT: Lines executed:77.78% of 9
// CHECK-NEXT: Creating 'gcov-8.c.gcov'
// RUN: llvm-cov gcov gcov-8.c | FileCheck %s --check-prefixes=OUT,OUTFILE
// OUT: File 'gcov-8.c'
// OUT-NEXT: Lines executed:77.78% of 9
// OUT-B-NEXT: Branches executed:85.71% of 14
// OUT-B-NEXT: Taken at least once:42.86% of 14
// OUT-B-NEXT: No calls
// OUTFILE-NEXT: Creating 'gcov-8.c.gcov'
// OUT-EMPTY:
// RUN: FileCheck --input-file=%t/gcov-8.c.gcov --check-prefix=HEADER %s
// RUN: FileCheck --input-file=%t/gcov-8.c.gcov --check-prefix=GCOV %s
@ -33,3 +37,37 @@ int main() { // GCOV: 1: [[@LINE]]:int
// HEADER-NEXT: -: 0:Runs:1{{$}}
// HEADER-NEXT: -: 0:Programs:1
// HEADER-NEXT: -: 1:/// Test that llvm-cov
// RUN: llvm-cov gcov -i gcov-8.c | FileCheck %s --check-prefix=OUT
// RUN: FileCheck %s --check-prefix=I < gcov-8.c.gcov
// RUN: llvm-cov gcov --intermediate-format gcov-8.c
// RUN: FileCheck %s --check-prefix=I < gcov-8.c.gcov
// RUN: llvm-cov gcov -i -b gcov-8.c | FileCheck %s --check-prefixes=OUT,OUT-B
// RUN: FileCheck %s --check-prefixes=I,I-B < gcov-8.c.gcov
// I:file:gcov-8.c
// I-NEXT:function:4,1,main
// I-NEXT:lcount:4,1
// I-NEXT:lcount:6,12
// I-B-NEXT:branch:6,taken
// I-B-NEXT:branch:6,nottaken
// I-NEXT:lcount:7,11
// I-B-NEXT:branch:7,taken
// I-B-NEXT:branch:7,nottaken
// I-NEXT:lcount:8,7
// I-B-NEXT:branch:8,taken
// I-B-NEXT:branch:8,nottaken
// I-NEXT:lcount:9,11
// I-NEXT:lcount:10,11
// I-B-NEXT:branch:10,taken
// I-B-NEXT:branch:10,nottaken
// I-NEXT:lcount:11,11
// I-B-NEXT:branch:11,taken
// I-B-NEXT:branch:11,nottaken
// I-B-NEXT:branch:11,taken
// I-B-NEXT:branch:11,nottaken
// I-NEXT:lcount:12,0
// I-B-NEXT:branch:12,notexec
// I-B-NEXT:branch:12,notexec
// I-NEXT:lcount:14,0

View File

@ -0,0 +1,55 @@
REQUIRES: shell
RUN: rm -rf %t && mkdir %t && cd %t
RUN: cp %S/Inputs/test.gcno %S/Inputs/test.gcda .
RUN: llvm-cov gcov -i test.cpp 2> %t.err | FileCheck %s --check-prefixes=OUT
RUN: FileCheck %s --check-prefix=I < test.cpp.gcov
RUN: cp test.cpp.gcov saved.cpp.gcov
# -i does not read source files. No ENOENT diagnostic.
RUN: count 0 < %t.err
# -n suppresses the .gcov output.
RUN: llvm-cov gcov -i -n test. | FileCheck %s --check-prefixes=OUT
RUN: not ls test..gcov
# The output filename is formed by appending ".gcov" to the specifiled filename.
RUN: llvm-cov gcov -i test. | FileCheck %s --check-prefix=OUT
RUN: cmp test..gcov saved.cpp.gcov
RUN: llvm-cov gcov -i -b test.cpp | FileCheck %s --check-prefixes=OUT,OUT-B
RUN: FileCheck %s --check-prefixes=I,I-B --match-full-lines --strict-whitespace < test.cpp.gcov
# Many other options are ignored.
RUN: rm -f test.cpp.gcov && llvm-cov gcov -i -a -c -l -p -u -x test.cpp
RUN: cmp test.cpp.gcov saved.cpp.gcov
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
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
OUT-EMPTY:
I:file:test.cpp
I:function:10,4294967296,_ZN1A1BEv
I-NEXT:function:12,0,_Z7uselessv
I-NEXT:function:14,0,_Z12more_uselessv
I-NEXT:function:18,1,_Z3foov
I-NEXT:function:23,0,_Z3barv
I-NEXT:function:28,4,_Z6assignii
I-NEXT:function:32,1,_Z15initialize_gridv
I-NEXT:function:38,1,main
I:lcount:10,4294967296
I:lcount:33,3
I-B-NEXT:branch:33,taken
I-B-NEXT:branch:33,taken
I:file:./test.h
I-NEXT:function:2,1,_ZN1AC2Ev
I-NEXT:lcount:2,1

View File

@ -105,6 +105,16 @@ int gcovMain(int argc, const char *argv[]) {
cl::desc("Show coverage for each function"));
cl::alias FuncSummaryA("function-summaries", cl::aliasopt(FuncSummary));
// Supported by gcov 4.9~8. gcov 9 (GCC r265587) removed --intermediate-format
// and -i was changed to mean --json-format. We consider this format still
// useful and support -i.
cl::opt<bool> Intermediate(
"intermediate-format", cl::init(false),
cl::desc("Output .gcov in intermediate text format"));
cl::alias IntermediateA("i", cl::desc("Alias for --intermediate-format"),
cl::Grouping, cl::NotHidden,
cl::aliasopt(Intermediate));
cl::opt<bool> NoOutput("n", cl::Grouping, cl::init(false),
cl::desc("Do not output any .gcov files"));
cl::alias NoOutputA("no-output", cl::aliasopt(NoOutput));
@ -144,8 +154,8 @@ int gcovMain(int argc, const char *argv[]) {
cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
GCOV::Options Options(AllBlocks, BranchProb, BranchCount, FuncSummary,
PreservePaths, UncondBranch, LongNames, NoOutput,
UseStdout, HashFilenames);
PreservePaths, UncondBranch, Intermediate, LongNames,
NoOutput, UseStdout, HashFilenames);
for (const auto &SourceFile : SourceFiles)
reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV,