[llvm] r346506 - [llvm-cov] Add lcov tracefile export format.

Max Moroz via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 9 08:10:44 PST 2018


Author: dor1s
Date: Fri Nov  9 08:10:44 2018
New Revision: 346506

URL: http://llvm.org/viewvc/llvm-project?rev=346506&view=rev
Log:
[llvm-cov] Add lcov tracefile export format.

Summary:
lcov tracefiles are used by various coverage reporting tools and build
systems (e.g., Bazel). It is a simple text-based format to parse and
more convenient to use than the JSON export format, which needs
additional processing to map regions/segments back to line numbers.

It's a little unfortunate that "text" format is now overloaded to refer
specifically to JSON for export, but I wanted to avoid making any
breaking changes to the UI of the llvm-cov tool at this time.

Patch by Tony Allevato (@allevato).

Reviewers: Dor1s, vsk

Reviewed By: Dor1s, vsk

Subscribers: mgorny, llvm-commits

Differential Revision: https://reviews.llvm.org/D54266

Added:
    llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts-lcov.test
    llvm/trunk/tools/llvm-cov/CoverageExporterLcov.cpp
    llvm/trunk/tools/llvm-cov/CoverageExporterLcov.h
Modified:
    llvm/trunk/docs/CommandGuide/llvm-cov.rst
    llvm/trunk/docs/ReleaseNotes.rst
    llvm/trunk/tools/llvm-cov/CMakeLists.txt
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
    llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
    llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp

Modified: llvm/trunk/docs/CommandGuide/llvm-cov.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-cov.rst?rev=346506&r1=346505&r2=346506&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/llvm-cov.rst (original)
+++ llvm/trunk/docs/CommandGuide/llvm-cov.rst Fri Nov  9 08:10:44 2018
@@ -374,9 +374,15 @@ SYNOPSIS
 DESCRIPTION
 ^^^^^^^^^^^
 
-The :program:`llvm-cov export` command exports regions, functions, expansions,
-and summaries of the coverage of the binaries *BIN*,... using the profile data
-*PROFILE* as JSON. It can optionally be filtered to only export the coverage
+The :program:`llvm-cov export` command exports coverage data of the binaries
+*BIN*,... using the profile data *PROFILE* in either JSON or lcov trace file
+format.
+
+When exporting JSON, the regions, functions, expansions, and summaries of the
+coverage data will be exported. When exporting an lcov trace file, the
+line-based coverage and summaries will be exported.
+
+The exported data can optionally be filtered to only export the coverage
 for the files listed in *SOURCES*.
 
 For information on compiling programs for coverage and generating profile data,
@@ -392,12 +398,18 @@ OPTIONS
  universal binary or to use an architecture that does not match a
  non-universal binary.
 
+.. option:: -format=<FORMAT>
+
+ Use the specified output format. The supported formats are: "text" (JSON),
+ "lcov".
+
 .. option:: -summary-only
 
  Export only summary information for each file in the coverage data. This mode
  will not export coverage information for smaller units such as individual
- functions or regions. The result will be the same as produced by :program:
- `llvm-cov report` command, but presented in JSON format rather than text.
+ functions or regions. The result will contain the same information as produced
+ by the :program:`llvm-cov report` command, but presented in JSON or lcov
+ format rather than text.
 
 .. option:: -ignore-filename-regex=<PATTERN>
 

Modified: llvm/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.rst?rev=346506&r1=346505&r2=346506&view=diff
==============================================================================
--- llvm/trunk/docs/ReleaseNotes.rst (original)
+++ llvm/trunk/docs/ReleaseNotes.rst Fri Nov  9 08:10:44 2018
@@ -40,7 +40,8 @@ Non-comprehensive list of changes in thi
    functionality, or simply have a lot to talk about), see the `NOTE` below
    for adding a new subsection.
 
-* Note..
+* The **llvm-cov** tool can now export lcov trace files using the
+  `-format=lcov` option of the `export` command.
 
 .. NOTE
    If you would like to document a larger change, then you can add a

Added: llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts-lcov.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts-lcov.test?rev=346506&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts-lcov.test (added)
+++ llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts-lcov.test Fri Nov  9 08:10:44 2018
@@ -0,0 +1,38 @@
+// FULL: SF:{{.*}}showLineExecutionCounts.cpp
+// FULL: FN:6,main
+// FULL: FNDA:161,main
+// FULL: FNF:1
+// FULL: FNH:1
+int main() {                              // FULL: DA:[[@LINE]],161
+  int x = 0;                              // FULL: DA:[[@LINE]],161
+                                          // FULL: DA:[[@LINE]],161
+  if (x) {                                // FULL: DA:[[@LINE]],161
+    x = 0;                                // FULL: DA:[[@LINE]],0
+  } else {                                // FULL: DA:[[@LINE]],161
+    x = 1;                                // FULL: DA:[[@LINE]],161
+  }                                       // FULL: DA:[[@LINE]],161
+                                          // FULL: DA:[[@LINE]],161
+  for (int i = 0; i < 100; ++i) {         // FULL: DA:[[@LINE]],16261
+    x = 1;                                // FULL: DA:[[@LINE]],16100
+  }                                       // FULL: DA:[[@LINE]],16100
+                                          // FULL: DA:[[@LINE]],161
+  x = x < 10 ? x + 1 : x - 1;             // FULL: DA:[[@LINE]],161
+  x = x > 10 ?                            // FULL: DA:[[@LINE]],161
+        x - 1:                            // FULL: DA:[[@LINE]],0
+        x + 1;                            // FULL: DA:[[@LINE]],161
+                                          // FULL: DA:[[@LINE]],161
+  return 0;                               // FULL: DA:[[@LINE]],161
+}                                         // FULL: DA:[[@LINE]],161
+// FULL: LF:20
+// FULL: LH:18
+// FULL: end_of_record
+// RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
+// RUN: llvm-cov export -format=lcov %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata %s | FileCheck -check-prefixes=FULL %s
+
+// RUN: llvm-cov export -format=lcov -summary-only %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata %s | FileCheck -check-prefixes=SUMMARYONLY %s
+// SUMMARYONLY: SF:{{.*}}showLineExecutionCounts.cpp
+// SUMMARYONLY: FNF:1
+// SUMMARYONLY: FNH:1
+// SUMMARYONLY: LF:20
+// SUMMARYONLY: LH:18
+// SUMMARYONLY: end_of_record

Modified: llvm/trunk/tools/llvm-cov/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CMakeLists.txt?rev=346506&r1=346505&r2=346506&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-cov/CMakeLists.txt Fri Nov  9 08:10:44 2018
@@ -5,6 +5,7 @@ add_llvm_tool(llvm-cov
   gcov.cpp
   CodeCoverage.cpp
   CoverageExporterJson.cpp
+  CoverageExporterLcov.cpp
   CoverageFilters.cpp
   CoverageReport.cpp
   CoverageSummaryInfo.cpp

Modified: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=346506&r1=346505&r2=346506&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Fri Nov  9 08:10:44 2018
@@ -14,6 +14,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CoverageExporterJson.h"
+#include "CoverageExporterLcov.h"
 #include "CoverageFilters.h"
 #include "CoverageReport.h"
 #include "CoverageSummaryInfo.h"
@@ -566,7 +567,9 @@ int CodeCoverageTool::run(Command Cmd, i
       cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
                             "Text output"),
                  clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
-                            "HTML output")),
+                            "HTML output"),
+                 clEnumValN(CoverageViewOptions::OutputFormat::Lcov, "lcov",
+                            "lcov tracefile output")),
       cl::init(CoverageViewOptions::OutputFormat::Text));
 
   cl::opt<std::string> PathRemap(
@@ -674,6 +677,11 @@ int CodeCoverageTool::run(Command Cmd, i
         errs() << "Color output cannot be disabled when generating html.\n";
       ViewOpts.Colors = true;
       break;
+    case CoverageViewOptions::OutputFormat::Lcov:
+      if (UseColor == cl::BOU_TRUE)
+        errs() << "Color output cannot be enabled when generating lcov.\n";
+      ViewOpts.Colors = false;
+      break;
     }
 
     // If path-equivalence was given and is a comma seperated pair then set
@@ -833,6 +841,11 @@ int CodeCoverageTool::doShow(int argc, c
   if (Err)
     return Err;
 
+  if (ViewOpts.Format == CoverageViewOptions::OutputFormat::Lcov) {
+    error("Lcov format should be used with 'llvm-cov export'.");
+    return 1;
+  }
+
   ViewOpts.ShowLineNumbers = true;
   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
                            !ShowRegions || ShowBestLineRegionsCounts;
@@ -964,6 +977,9 @@ int CodeCoverageTool::doReport(int argc,
   if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
     error("HTML output for summary reports is not yet supported.");
     return 1;
+  } else if (ViewOpts.Format == CoverageViewOptions::OutputFormat::Lcov) {
+    error("Lcov format should be used with 'llvm-cov export'.");
+    return 1;
   }
 
   auto Coverage = load();
@@ -995,8 +1011,10 @@ int CodeCoverageTool::doExport(int argc,
   if (Err)
     return Err;
 
-  if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
-    error("Coverage data can only be exported as textual JSON.");
+  if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text &&
+      ViewOpts.Format != CoverageViewOptions::OutputFormat::Lcov) {
+    error("Coverage data can only be exported as textual JSON or an "
+          "lcov tracefile.");
     return 1;
   }
 
@@ -1006,12 +1024,29 @@ int CodeCoverageTool::doExport(int argc,
     return 1;
   }
 
-  auto Exporter = CoverageExporterJson(*Coverage.get(), ViewOpts, outs());
+  std::unique_ptr<CoverageExporter> Exporter;
+
+  switch (ViewOpts.Format) {
+  case CoverageViewOptions::OutputFormat::Text:
+    Exporter = llvm::make_unique<CoverageExporterJson>(*Coverage.get(),
+                                                       ViewOpts, outs());
+    break;
+  case CoverageViewOptions::OutputFormat::HTML:
+    // Unreachable because we should have gracefully terminated with an error
+    // above.
+    llvm_unreachable("Export in HTML is not supported!");
+  case CoverageViewOptions::OutputFormat::Lcov:
+    Exporter = llvm::make_unique<CoverageExporterLcov>(*Coverage.get(),
+                                                       ViewOpts, outs());
+    break;
+  default:
+    llvm_unreachable("Unknown coverage output format!");
+  }
 
   if (SourceFiles.empty())
-    Exporter.renderRoot(IgnoreFilenameFilters);
+    Exporter->renderRoot(IgnoreFilenameFilters);
   else
-    Exporter.renderRoot(SourceFiles);
+    Exporter->renderRoot(SourceFiles);
 
   return 0;
 }

Added: llvm/trunk/tools/llvm-cov/CoverageExporterLcov.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageExporterLcov.cpp?rev=346506&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageExporterLcov.cpp (added)
+++ llvm/trunk/tools/llvm-cov/CoverageExporterLcov.cpp Fri Nov  9 08:10:44 2018
@@ -0,0 +1,125 @@
+//===- CoverageExporterLcov.cpp - Code coverage export --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements export of code coverage data to lcov trace file format.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+//
+// The trace file code coverage export follows the following format (see also
+// https://linux.die.net/man/1/geninfo). Each quoted string appears on its own
+// line; the indentation shown here is only for documentation purposes.
+//
+// - for each source file:
+//   - "SF:<absolute path to source file>"
+//   - for each function:
+//     - "FN:<line number of function start>,<function name>"
+//   - for each function:
+//     - "FNDA:<execution count>,<function name>"
+//   - "FNF:<number of functions found>"
+//   - "FNH:<number of functions hit>"
+//   - for each instrumented line:
+//     - "DA:<line number>,<execution count>[,<checksum>]
+//   - "LH:<number of lines with non-zero execution count>"
+//   - "LF:<nubmer of instrumented lines>"
+//   - "end_of_record"
+//
+// If the user is exporting summary information only, then the FN, FNDA, and DA
+// lines will not be present.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageExporterLcov.h"
+#include "CoverageReport.h"
+
+using namespace llvm;
+
+namespace {
+
+void renderFunctionSummary(raw_ostream &OS,
+                           const FileCoverageSummary &Summary) {
+  OS << "FNF:" << Summary.FunctionCoverage.getNumFunctions() << '\n'
+     << "FNH:" << Summary.FunctionCoverage.getExecuted() << '\n';
+}
+
+void renderFunctions(
+    raw_ostream &OS,
+    const iterator_range<coverage::FunctionRecordIterator> &Functions) {
+  for (const auto &F : Functions) {
+    auto StartLine = F.CountedRegions.front().LineStart;
+    OS << "FN:" << StartLine << ',' << F.Name << '\n';
+  }
+  for (const auto &F : Functions)
+    OS << "FNDA:" << F.ExecutionCount << ',' << F.Name << '\n';
+}
+
+void renderLineExecutionCounts(raw_ostream &OS,
+                               const coverage::CoverageData &FileCoverage) {
+  coverage::LineCoverageIterator LCI{FileCoverage, 1};
+  coverage::LineCoverageIterator LCIEnd = LCI.getEnd();
+  for (; LCI != LCIEnd; ++LCI) {
+    const coverage::LineCoverageStats &LCS = *LCI;
+    if (LCS.isMapped()) {
+      OS << "DA:" << LCS.getLine() << ',' << LCS.getExecutionCount() << '\n';
+    }
+  }
+}
+
+void renderLineSummary(raw_ostream &OS, const FileCoverageSummary &Summary) {
+  OS << "LF:" << Summary.LineCoverage.getNumLines() << '\n'
+     << "LH:" << Summary.LineCoverage.getCovered() << '\n';
+}
+
+void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
+                const std::string &Filename,
+                const FileCoverageSummary &FileReport, bool ExportSummaryOnly) {
+  OS << "SF:" << Filename << '\n';
+
+  if (!ExportSummaryOnly) {
+    renderFunctions(OS, Coverage.getCoveredFunctions());
+  }
+  renderFunctionSummary(OS, FileReport);
+
+  if (!ExportSummaryOnly) {
+    // Calculate and render detailed coverage information for given file.
+    auto FileCoverage = Coverage.getCoverageForFile(Filename);
+    renderLineExecutionCounts(OS, FileCoverage);
+  }
+  renderLineSummary(OS, FileReport);
+
+  OS << "end_of_record\n";
+}
+
+void renderFiles(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
+                 ArrayRef<std::string> SourceFiles,
+                 ArrayRef<FileCoverageSummary> FileReports,
+                 bool ExportSummaryOnly) {
+  for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I)
+    renderFile(OS, Coverage, SourceFiles[I], FileReports[I], ExportSummaryOnly);
+}
+
+} // end anonymous namespace
+
+void CoverageExporterLcov::renderRoot(const CoverageFilters &IgnoreFilters) {
+  std::vector<std::string> SourceFiles;
+  for (StringRef SF : Coverage.getUniqueSourceFiles()) {
+    if (!IgnoreFilters.matchesFilename(SF))
+      SourceFiles.emplace_back(SF);
+  }
+  renderRoot(SourceFiles);
+}
+
+void CoverageExporterLcov::renderRoot(ArrayRef<std::string> SourceFiles) {
+  FileCoverageSummary Totals = FileCoverageSummary("Totals");
+  auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
+                                                        SourceFiles, Options);
+  renderFiles(OS, Coverage, SourceFiles, FileReports,
+              Options.ExportSummaryOnly);
+}

Added: llvm/trunk/tools/llvm-cov/CoverageExporterLcov.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageExporterLcov.h?rev=346506&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageExporterLcov.h (added)
+++ llvm/trunk/tools/llvm-cov/CoverageExporterLcov.h Fri Nov  9 08:10:44 2018
@@ -0,0 +1,36 @@
+//===- CoverageExporterLcov.h - Code coverage lcov exporter ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements a code coverage exporter for lcov trace file format.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGEEXPORTERLCOV_H
+#define LLVM_COV_COVERAGEEXPORTERLCOV_H
+
+#include "CoverageExporter.h"
+
+namespace llvm {
+
+class CoverageExporterLcov : public CoverageExporter {
+public:
+  CoverageExporterLcov(const coverage::CoverageMapping &CoverageMapping,
+                       const CoverageViewOptions &Options, raw_ostream &OS)
+      : CoverageExporter(CoverageMapping, Options, OS) {}
+
+  /// Render the CoverageMapping object.
+  void renderRoot(const CoverageFilters &IgnoreFilters) override;
+
+  /// Render the CoverageMapping object for specified source files.
+  void renderRoot(ArrayRef<std::string> SourceFiles) override;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_COV_COVERAGEEXPORTERLCOV_H

Modified: llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageViewOptions.h?rev=346506&r1=346505&r2=346506&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageViewOptions.h (original)
+++ llvm/trunk/tools/llvm-cov/CoverageViewOptions.h Fri Nov  9 08:10:44 2018
@@ -20,7 +20,8 @@ namespace llvm {
 struct CoverageViewOptions {
   enum class OutputFormat {
     Text,
-    HTML
+    HTML,
+    Lcov
   };
 
   bool Debug;

Modified: llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp?rev=346506&r1=346505&r2=346506&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp (original)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp Fri Nov  9 08:10:44 2018
@@ -80,6 +80,10 @@ CoveragePrinter::create(const CoverageVi
     return llvm::make_unique<CoveragePrinterText>(Opts);
   case CoverageViewOptions::OutputFormat::HTML:
     return llvm::make_unique<CoveragePrinterHTML>(Opts);
+  case CoverageViewOptions::OutputFormat::Lcov:
+    // Unreachable because CodeCoverage.cpp should terminate with an error
+    // before we get here.
+    llvm_unreachable("Lcov format is not supported!");
   }
   llvm_unreachable("Unknown coverage output format!");
 }
@@ -143,6 +147,10 @@ SourceCoverageView::create(StringRef Sou
   case CoverageViewOptions::OutputFormat::HTML:
     return llvm::make_unique<SourceCoverageViewHTML>(
         SourceName, File, Options, std::move(CoverageInfo));
+  case CoverageViewOptions::OutputFormat::Lcov:
+    // Unreachable because CodeCoverage.cpp should terminate with an error
+    // before we get here.
+    llvm_unreachable("Lcov format is not supported!");
   }
   llvm_unreachable("Unknown coverage output format!");
 }




More information about the llvm-commits mailing list