diff options
| author | Max Moroz <mmoroz@chromium.org> | 2019-03-14 17:49:27 +0000 |
|---|---|---|
| committer | Max Moroz <mmoroz@chromium.org> | 2019-03-14 17:49:27 +0000 |
| commit | a80d9ce5cfa1d109b895cd4837d0c1bb564775d7 (patch) | |
| tree | ad1d817a44bc97824e2839cc1056a6029c83491b /llvm/tools | |
| parent | 0d8df9832846c1fa0fc83282cdac78f2c01e31b2 (diff) | |
| download | bcm5719-llvm-a80d9ce5cfa1d109b895cd4837d0c1bb564775d7.tar.gz bcm5719-llvm-a80d9ce5cfa1d109b895cd4837d0c1bb564775d7.zip | |
Speeding up llvm-cov export with multithreaded renderFiles implementation.
Summary:
CoverageExporterJson::renderFiles accounts for most of the execution time given a large profdata file with multiple binaries.
Proposed solution is to generate JSON for each file in parallel and sort at the end to preserve deterministic output. Also added flags to skip generating parts of the output to trim the output size.
Patch by Sajjad Mirza (@sajjadm).
Reviewers: Dor1s, vsk
Reviewed By: Dor1s, vsk
Subscribers: liaoyuke, mgrang, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59277
llvm-svn: 356178
Diffstat (limited to 'llvm/tools')
| -rw-r--r-- | llvm/tools/llvm-cov/CodeCoverage.cpp | 13 | ||||
| -rw-r--r-- | llvm/tools/llvm-cov/CoverageExporterJson.cpp | 62 | ||||
| -rw-r--r-- | llvm/tools/llvm-cov/CoverageViewOptions.h | 2 |
3 files changed, 64 insertions, 13 deletions
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; |

