Index: tools/llvm-cov/CodeCoverage.cpp =================================================================== --- tools/llvm-cov/CodeCoverage.cpp +++ tools/llvm-cov/CodeCoverage.cpp @@ -826,6 +826,7 @@ ViewOpts.ShowOutputDirectory = ShowOutputDirectory; ViewOpts.TabSize = TabSize; ViewOpts.ProjectTitle = ProjectTitle; + ViewOpts.NumThreads = NumThreads; if (ViewOpts.hasOutputDirectory()) { if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) { @@ -847,17 +848,21 @@ ? "Created: " + ModifiedTimeStr.substr(0, found) : "Created: " + ModifiedTimeStr; + outs() << "Loading coverage data: "; + printTimestamp(); auto Coverage = load(); if (!Coverage) return 1; auto Printer = CoveragePrinter::create(ViewOpts); - + outs() << "Get unique source files: "; + printTimestamp(); if (SourceFiles.empty()) // Get the source files from the function coverage mapping. for (StringRef Filename : Coverage->getUniqueSourceFiles()) SourceFiles.push_back(Filename); - + outs() << "Creating an index out of the source files: "; + printTimestamp(); // Create an index out of the source files. if (ViewOpts.hasOutputDirectory()) { if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) { @@ -915,6 +920,12 @@ std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(), unsigned(SourceFiles.size()))); + // NumThreads = 1; + outs() << "Launching "; + outs() << NumThreads; + outs() << " threads for generating HTML files: "; + printTimestamp(); + if (!ViewOpts.hasOutputDirectory() || NumThreads == 1) { for (const std::string &SourceFile : SourceFiles) writeSourceFileView(SourceFile, Coverage.get(), Printer.get(), @@ -993,6 +1004,8 @@ int showMain(int argc, const char *argv[]) { CodeCoverageTool Tool; + outs() << "The tool has been launched: "; + printTimestamp(); return Tool.run(CodeCoverageTool::Show, argc, argv); } Index: tools/llvm-cov/CoverageReport.h =================================================================== --- tools/llvm-cov/CoverageReport.h +++ tools/llvm-cov/CoverageReport.h @@ -44,6 +44,15 @@ const CoverageViewOptions &Options, const CoverageFilter &Filters = CoverageFiltersMatchAll()); + static void prepareSingleFileReport(const StringRef &Filename, + const coverage::CoverageMapping *Coverage, FileCoverageSummary &Totals, + const CoverageViewOptions &Options, + const unsigned LCP, + std::vector &FileChunkCoverageSummary, + const CoverageFilter &Filters = CoverageFiltersMatchAll()); + + static const coverage::CoverageMapping *CoveragePtr; + /// Render file reports for every unique file in the coverage mapping. void renderFileReports(raw_ostream &OS) const; @@ -56,6 +65,8 @@ const CoverageFiltersMatchAll &Filters) const; }; +void printTimestamp(); + } // end namespace llvm #endif // LLVM_COV_COVERAGEREPORT_H Index: tools/llvm-cov/CoverageReport.cpp =================================================================== --- tools/llvm-cov/CoverageReport.cpp +++ tools/llvm-cov/CoverageReport.cpp @@ -17,8 +17,14 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Threading.h" +#include "llvm/Support/ThreadPool.h" #include +#include +#include +#include + using namespace llvm; namespace { @@ -320,41 +326,75 @@ } } +const coverage::CoverageMapping *CoverageReport::CoveragePtr = nullptr; + +void CoverageReport::prepareSingleFileReport(const StringRef &Filename, + const coverage::CoverageMapping *Coverage, FileCoverageSummary &Totals, + const CoverageViewOptions &Options, const unsigned LCP, + std::vector &FileChunkCoverageSummary, + const CoverageFilter &Filters) { + FileCoverageSummary Summary(Filename.drop_front(LCP)); + + for (const auto &Group : Coverage->getInstantiationGroups(Filename)) { + std::vector InstantiationSummaries; + for (const coverage::FunctionRecord *F : Group.getInstantiations()) { + if (!Filters.matches(*Coverage, *F)) + continue; + auto InstantiationSummary = FunctionCoverageSummary::get(*Coverage, *F); + Summary.addInstantiation(InstantiationSummary); + Totals.addInstantiation(InstantiationSummary); + InstantiationSummaries.push_back(InstantiationSummary); + } + if (InstantiationSummaries.empty()) + continue; + + auto GroupSummary = + FunctionCoverageSummary::get(Group, InstantiationSummaries); + + if (Options.Debug) + outs() << "InstantiationGroup: " << GroupSummary.Name << " with " + << "size = " << Group.size() << "\n"; + + Summary.addFunction(GroupSummary); + Totals.addFunction(GroupSummary); + } +} + std::vector CoverageReport::prepareFileReports( const coverage::CoverageMapping &Coverage, FileCoverageSummary &Totals, ArrayRef Files, const CoverageViewOptions &Options, const CoverageFilter &Filters) { - std::vector FileReports; unsigned LCP = getRedundantPrefixLen(Files); + auto NumThreads = Options.NumThreads; + // If NumThreads is not specified, auto-detect a good default. + if (NumThreads == 0) + NumThreads = + std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(), + unsigned(Files.size()))); + outs() << "Preparing file reports using "; + outs() << NumThreads; + outs() << " threads: "; + printTimestamp(); + + ThreadPool Pool(NumThreads); + std::vector> FileCoverageSummaries( + NumThreads); + CoverageReport::CoveragePtr = &Coverage; + size_t Index = 0; for (StringRef Filename : Files) { - FileCoverageSummary Summary(Filename.drop_front(LCP)); - - for (const auto &Group : Coverage.getInstantiationGroups(Filename)) { - std::vector InstantiationSummaries; - for (const coverage::FunctionRecord *F : Group.getInstantiations()) { - if (!Filters.matches(Coverage, *F)) - continue; - auto InstantiationSummary = FunctionCoverageSummary::get(Coverage, *F); - Summary.addInstantiation(InstantiationSummary); - Totals.addInstantiation(InstantiationSummary); - InstantiationSummaries.push_back(InstantiationSummary); - } - if (InstantiationSummaries.empty()) - continue; - - auto GroupSummary = - FunctionCoverageSummary::get(Group, InstantiationSummaries); - - if (Options.Debug) - outs() << "InstantiationGroup: " << GroupSummary.Name << " with " - << "size = " << Group.size() << "\n"; - - Summary.addFunction(GroupSummary); - Totals.addFunction(GroupSummary); - } + Pool.async(&CoverageReport::prepareSingleFileReport, Filename, + CoverageReport::CoveragePtr, Totals, Options, LCP, + FileCoverageSummaries[Index], Filters); + Index = (Index + 1) % NumThreads; + } + Pool.wait(); - FileReports.push_back(Summary); + std::vector FileReports; + FileReports.reserve(Files.size()); + for (const auto& FileReportsChunk : FileCoverageSummaries) { + FileReports.insert( + FileReports.end(), FileReportsChunk.begin(), FileReportsChunk.end()); } return FileReports; @@ -424,4 +464,11 @@ render(Totals, OS); } +void printTimestamp() { + using namespace std::chrono; + system_clock::time_point today = system_clock::now(); + time_t tt = system_clock::to_time_t ( today ); + std::cout << ctime(&tt) << "\n"; +} + } // end namespace llvm Index: tools/llvm-cov/CoverageViewOptions.h =================================================================== --- tools/llvm-cov/CoverageViewOptions.h +++ tools/llvm-cov/CoverageViewOptions.h @@ -39,6 +39,7 @@ uint32_t TabSize; std::string ProjectTitle; std::string CreatedTimeStr; + unsigned NumThreads; /// \brief Change the output's stream color if the colors are enabled. ColoredRawOstream colored_ostream(raw_ostream &OS, Index: tools/llvm-cov/SourceCoverageView.cpp =================================================================== --- tools/llvm-cov/SourceCoverageView.cpp +++ tools/llvm-cov/SourceCoverageView.cpp @@ -66,9 +66,12 @@ std::error_code E; raw_ostream *RawStream = new raw_fd_ostream(FullPath, E, sys::fs::F_RW); + auto OS = CoveragePrinter::OwnedStream(RawStream); if (E) return errorCodeToError(E); + + OS.get()->SetBufferSize(1 << 16); return std::move(OS); } Index: tools/llvm-cov/SourceCoverageViewHTML.cpp =================================================================== --- tools/llvm-cov/SourceCoverageViewHTML.cpp +++ tools/llvm-cov/SourceCoverageViewHTML.cpp @@ -404,9 +404,13 @@ OSRef << BeginCenteredDiv << BeginTable; emitColumnLabelsForIndex(OSRef, Opts); FileCoverageSummary Totals("TOTALS"); + outs() << "Going into prepareFileReports: "; + printTimestamp(); auto FileReports = CoverageReport::prepareFileReports( Coverage, Totals, SourceFiles, Opts, Filters); bool EmptyFiles = false; + outs() << "Going to emit summary information for each file: "; + printTimestamp(); for (unsigned I = 0, E = FileReports.size(); I < E; ++I) { if (FileReports[I].FunctionCoverage.getNumFunctions()) emitFileSummary(OSRef, SourceFiles[I], FileReports[I]); @@ -415,7 +419,8 @@ } emitFileSummary(OSRef, "Totals", Totals, /*IsTotals=*/true); OSRef << EndTable << EndCenteredDiv; - + outs() << "Going to emit link to files with no function: "; + printTimestamp(); // Emit links to files which don't contain any functions. These are normally // not very useful, but could be relevant for code which abuses the // preprocessor.