[llvm] def2156 - [gcov] Add -i --intermediate-format
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 16 14:14:41 PDT 2020
Author: Fangrui Song
Date: 2020-06-16T14:14:28-07:00
New Revision: def21563895d757c7769de41d4ee8d9cb99714db
URL: https://github.com/llvm/llvm-project/commit/def21563895d757c7769de41d4ee8d9cb99714db
DIFF: https://github.com/llvm/llvm-project/commit/def21563895d757c7769de41d4ee8d9cb99714db.diff
LOG: [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
Added:
llvm/test/tools/llvm-cov/gcov-intermediate-format.test
Modified:
llvm/include/llvm/ProfileData/GCOV.h
llvm/lib/ProfileData/GCOV.cpp
llvm/test/tools/llvm-cov/gcov-8.c
llvm/tools/llvm-cov/gcov.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ProfileData/GCOV.h b/llvm/include/llvm/ProfileData/GCOV.h
index 294782c2c94d..58c454cbba80 100644
--- a/llvm/include/llvm/ProfileData/GCOV.h
+++ b/llvm/include/llvm/ProfileData/GCOV.h
@@ -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;
diff --git a/llvm/lib/ProfileData/GCOV.cpp b/llvm/lib/ProfileData/GCOV.cpp
index a9dd53341b01..9527993536ab 100644
--- a/llvm/lib/ProfileData/GCOV.cpp
+++ b/llvm/lib/ProfileData/GCOV.cpp
@@ -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";
}
diff --git a/llvm/test/tools/llvm-cov/gcov-8.c b/llvm/test/tools/llvm-cov/gcov-8.c
index 8099d22accc5..eef3511e93a7 100644
--- a/llvm/test/tools/llvm-cov/gcov-8.c
+++ b/llvm/test/tools/llvm-cov/gcov-8.c
@@ -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
diff --git a/llvm/test/tools/llvm-cov/gcov-intermediate-format.test b/llvm/test/tools/llvm-cov/gcov-intermediate-format.test
new file mode 100644
index 000000000000..56bad2357262
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/gcov-intermediate-format.test
@@ -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
diff --git a/llvm/tools/llvm-cov/gcov.cpp b/llvm/tools/llvm-cov/gcov.cpp
index 3ebf6a654bd3..4359ff466af0 100644
--- a/llvm/tools/llvm-cov/gcov.cpp
+++ b/llvm/tools/llvm-cov/gcov.cpp
@@ -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,
More information about the llvm-commits
mailing list