summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/docs/CommandGuide/llvm-cov.rst13
-rw-r--r--llvm/test/tools/llvm-cov/export_functions.test10
-rw-r--r--llvm/test/tools/llvm-cov/showExpansions.cpp3
-rw-r--r--llvm/tools/llvm-cov/CodeCoverage.cpp13
-rw-r--r--llvm/tools/llvm-cov/CoverageExporterJson.cpp62
-rw-r--r--llvm/tools/llvm-cov/CoverageViewOptions.h2
6 files changed, 90 insertions, 13 deletions
diff --git a/llvm/docs/CommandGuide/llvm-cov.rst b/llvm/docs/CommandGuide/llvm-cov.rst
index 6e90760cbaf..7cc7d3faf2e 100644
--- a/llvm/docs/CommandGuide/llvm-cov.rst
+++ b/llvm/docs/CommandGuide/llvm-cov.rst
@@ -419,3 +419,16 @@ OPTIONS
.. option:: -ignore-filename-regex=<PATTERN>
Skip source code files with file paths that match the given regular expression.
+
+ .. option:: -skip-expansions
+
+ Skip exporting macro expansion coverage data.
+
+ .. option:: -skip-functions
+
+ Skip exporting per-function coverage data.
+
+ .. option:: -num-threads=N, -j=N
+
+ Use N threads to export coverage data. When N=0, llvm-cov auto-detects an
+ appropriate number of threads to use. This is the default.
diff --git a/llvm/test/tools/llvm-cov/export_functions.test b/llvm/test/tools/llvm-cov/export_functions.test
new file mode 100644
index 00000000000..03f355f3238
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/export_functions.test
@@ -0,0 +1,10 @@
+# Test that llvm-cov export produces function data by default and that it can be
+# turned off with a flag.
+
+RUN: llvm-cov export %S/Inputs/report.covmapping -instr-profile %S/Inputs/report.profdata 2>&1 | FileCheck %s
+RUN: llvm-cov export %S/Inputs/report.covmapping -instr-profile %S/Inputs/report.profdata -skip-functions 2>&1 | FileCheck -check-prefix=SKIP-FUNCTIONS %s
+
+CHECK: "functions":[
+SKIP-FUNCTIONS-NOT: "functions":[
+
+
diff --git a/llvm/test/tools/llvm-cov/showExpansions.cpp b/llvm/test/tools/llvm-cov/showExpansions.cpp
index f9d63e95e75..5b165da3dc6 100644
--- a/llvm/test/tools/llvm-cov/showExpansions.cpp
+++ b/llvm/test/tools/llvm-cov/showExpansions.cpp
@@ -25,3 +25,6 @@ int main(int argc, const char *argv[]) {
return 0;
}
// RUN: llvm-cov export %S/Inputs/showExpansions.covmapping -instr-profile %S/Inputs/showExpansions.profdata 2>&1 | FileCheck %S/Inputs/showExpansions.json
+
+// RUN: llvm-cov export %S/Inputs/showExpansions.covmapping -instr-profile %S/Inputs/showExpansions.profdata -skip-expansions 2>&1 | FileCheck %s -check-prefix=SKIP-EXPANSIONS
+// SKIP-EXPANSIONS-NOT: "expansions"
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 43311a41c42..f707e3c7ab5 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -1006,10 +1006,23 @@ int CodeCoverageTool::doReport(int argc, const char **argv,
int CodeCoverageTool::doExport(int argc, const char **argv,
CommandLineParserType commandLineParser) {
+ cl::OptionCategory ExportCategory("Exporting options");
+
+ cl::opt<bool> SkipExpansions("skip-expansions", cl::Optional,
+ cl::desc("Don't export expanded source regions"),
+ cl::cat(ExportCategory));
+
+ cl::opt<bool> SkipFunctions("skip-functions", cl::Optional,
+ cl::desc("Don't export per-function data"),
+ cl::cat(ExportCategory));
+
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
+ ViewOpts.SkipExpansions = SkipExpansions;
+ ViewOpts.SkipFunctions = SkipFunctions;
+
if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text &&
ViewOpts.Format != CoverageViewOptions::OutputFormat::Lcov) {
error("Coverage data can only be exported as textual JSON or an "
diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index e6361d48b8e..181d428ed9d 100644
--- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -42,7 +42,14 @@
#include "CoverageExporterJson.h"
#include "CoverageReport.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/JSON.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/Threading.h"
+#include <algorithm>
+#include <mutex>
+#include <utility>
/// The semantic version combined as a string.
#define LLVM_COVERAGE_EXPORT_JSON_STR "2.0.0"
@@ -127,13 +134,15 @@ json::Array renderFileSegments(const coverage::CoverageData &FileCoverage,
json::Object renderFile(const coverage::CoverageMapping &Coverage,
const std::string &Filename,
const FileCoverageSummary &FileReport,
- bool ExportSummaryOnly) {
+ const CoverageViewOptions &Options) {
json::Object File({{"filename", Filename}});
- if (!ExportSummaryOnly) {
+ if (!Options.ExportSummaryOnly) {
// Calculate and render detailed coverage information for given file.
auto FileCoverage = Coverage.getCoverageForFile(Filename);
File["segments"] = renderFileSegments(FileCoverage, FileReport);
- File["expansions"] = renderFileExpansions(FileCoverage, FileReport);
+ if (!Options.SkipExpansions) {
+ File["expansions"] = renderFileExpansions(FileCoverage, FileReport);
+ }
}
File["summary"] = renderSummary(FileReport);
return File;
@@ -142,11 +151,28 @@ json::Object renderFile(const coverage::CoverageMapping &Coverage,
json::Array renderFiles(const coverage::CoverageMapping &Coverage,
ArrayRef<std::string> SourceFiles,
ArrayRef<FileCoverageSummary> FileReports,
- bool ExportSummaryOnly) {
+ const CoverageViewOptions &Options) {
+ auto NumThreads = Options.NumThreads;
+ if (NumThreads == 0) {
+ NumThreads = std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
+ unsigned(SourceFiles.size())));
+ }
+ ThreadPool Pool(NumThreads);
json::Array FileArray;
- for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I)
- FileArray.push_back(renderFile(Coverage, SourceFiles[I], FileReports[I],
- ExportSummaryOnly));
+ std::mutex FileArrayMutex;
+
+ for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) {
+ auto &SourceFile = SourceFiles[I];
+ auto &FileReport = FileReports[I];
+ Pool.async([&] {
+ auto File = renderFile(Coverage, SourceFile, FileReport, Options);
+ {
+ std::lock_guard<std::mutex> Lock(FileArrayMutex);
+ FileArray.push_back(std::move(File));
+ }
+ });
+ }
+ Pool.wait();
return FileArray;
}
@@ -177,12 +203,22 @@ void CoverageExporterJson::renderRoot(ArrayRef<std::string> SourceFiles) {
FileCoverageSummary Totals = FileCoverageSummary("Totals");
auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
SourceFiles, Options);
- auto Export =
- json::Object({{"files", renderFiles(Coverage, SourceFiles, FileReports,
- Options.ExportSummaryOnly)},
- {"totals", renderSummary(Totals)}});
- // Skip functions-level information for summary-only export mode.
- if (!Options.ExportSummaryOnly)
+ auto Files = renderFiles(Coverage, SourceFiles, FileReports, Options);
+ // Sort files in order of their names.
+ std::sort(Files.begin(), Files.end(),
+ [](const json::Value &A, const json::Value &B) {
+ const json::Object *ObjA = A.getAsObject();
+ const json::Object *ObjB = B.getAsObject();
+ assert(ObjA != nullptr && "Value A was not an Object");
+ assert(ObjB != nullptr && "Value B was not an Object");
+ const StringRef FilenameA = ObjA->getString("filename").getValue();
+ const StringRef FilenameB = ObjB->getString("filename").getValue();
+ return FilenameA.compare(FilenameB) < 0;
+ });
+ auto Export = json::Object(
+ {{"files", std::move(Files)}, {"totals", renderSummary(Totals)}});
+ // Skip functions-level information if necessary.
+ if (!Options.ExportSummaryOnly && !Options.SkipFunctions)
Export["functions"] = renderFunctions(Coverage.getCoveredFunctions());
auto ExportArray = json::Array({std::move(Export)});
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index 0a3e211cabc..dde0c692ab0 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -34,6 +34,8 @@ struct CoverageViewOptions {
bool ShowRegionSummary;
bool ShowInstantiationSummary;
bool ExportSummaryOnly;
+ bool SkipExpansions;
+ bool SkipFunctions;
OutputFormat Format;
std::string ShowOutputDirectory;
std::vector<std::string> DemanglerOpts;
OpenPOWER on IntegriCloud