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, + FileCoverageSummary *FileReportsChunk, + 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,108 @@ } } +const coverage::CoverageMapping *CoverageReport::CoveragePtr = nullptr; + +void CoverageReport::prepareSingleFileReport(const StringRef &Filename, + const coverage::CoverageMapping *Coverage, FileCoverageSummary *Totals, + const CoverageViewOptions &Options, const unsigned LCP, + FileCoverageSummary *FileReportsChunk, + const CoverageFilter &Filters) { + // outs() << "HELLO!!!!!\n"; + //FileCoverageSummary Summary(Filename.drop_front(LCP)); + FileReportsChunk->Name = 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); + FileReportsChunk->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); + FileReportsChunk->addFunction(GroupSummary); + Totals->addFunction(GroupSummary); + } + + // outs() << "Inserting into FileReportsChunk of size: "; + // outs() << FileReportsChunk.size(); + // outs() << " at "; + // printTimestamp(); + // FileReportsChunk.push_back(Summary); + // outs() << "FileReportsChunk size so far: "; + // outs() << FileReportsChunk.size(); + // outs() << " at "; + // printTimestamp(); +} + 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> FileReportsChunks(NumThreads); + std::vector TotalsChunks(NumThreads); + + CoverageReport::CoveragePtr = &Coverage; + size_t Index = 0; + outs() << "Creating thread tasks for the following number of files: "; + outs() << Files.size(); + outs() << "\n"; + std::vector FileReports(Files.size()); + //FileReports.reserve(Files.size()); for (StringRef Filename : Files) { - FileCoverageSummary Summary(Filename.drop_front(LCP)); + Pool.async(&CoverageReport::prepareSingleFileReport, Filename, + CoverageReport::CoveragePtr, &TotalsChunks[Index % NumThreads], + Options, LCP, &FileReports[Index], Filters); + //Index = (Index + 1) % NumThreads; + ++Index; + } + Pool.wait(); + +// std::vector FileReports; +// // FileReports.reserve(Files.size()); +// for (const auto& FileReportsChunk : FileReportsChunks) { +// outs() << "Inserting FileReportsChunk of size: "; +// outs() << FileReportsChunk.size(); +// outs() << " at "; +// printTimestamp(); +// FileReports.insert( +// FileReports.end(), FileReportsChunk.begin(), FileReportsChunk.end()); +// outs() << "FileReports size so far: " ; +// outs() << FileReports.size(); +// outs() << " at "; +// printTimestamp(); +// } - 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); - } - - FileReports.push_back(Summary); + for (const auto& TotalsChunk : TotalsChunks) { + Totals += TotalsChunk; } return FileReports; @@ -424,4 +497,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/CoverageSummaryInfo.h =================================================================== --- tools/llvm-cov/CoverageSummaryInfo.h +++ tools/llvm-cov/CoverageSummaryInfo.h @@ -116,6 +116,12 @@ FunctionCoverageInfo(size_t Executed, size_t NumFunctions) : Executed(Executed), NumFunctions(NumFunctions) {} + FunctionCoverageInfo &operator+=(const FunctionCoverageInfo &RHS) { + Executed += RHS.Executed; + NumFunctions += RHS.NumFunctions; + return *this; + } + void addFunction(bool Covered) { if (Covered) ++Executed; @@ -172,10 +178,22 @@ FunctionCoverageInfo FunctionCoverage; FunctionCoverageInfo InstantiationCoverage; + FileCoverageSummary() + : Name(), RegionCoverage(), LineCoverage(), FunctionCoverage(), + InstantiationCoverage() {} + FileCoverageSummary(StringRef Name) : Name(Name), RegionCoverage(), LineCoverage(), FunctionCoverage(), InstantiationCoverage() {} + FileCoverageSummary &operator+=(const FileCoverageSummary &RHS) { + RegionCoverage += RHS.RegionCoverage; + LineCoverage += RHS.LineCoverage; + FunctionCoverage += RHS.FunctionCoverage; + InstantiationCoverage += RHS.InstantiationCoverage; + return *this; + } + void addFunction(const FunctionCoverageSummary &Function) { RegionCoverage += Function.RegionCoverage; LineCoverage += Function.LineCoverage; 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.