[llvm-cov] Multi-threaded implementation of prepareFileReports method.

Summary:
Local testing has demonstrated a great speed improvement, compare the following:

1) Existing version:
```
$ time llvm-cov show -format=html -output-dir=report -instr-profile=... ...
The tool has been launched:                            00:00:00
Loading coverage data:                                 00:00:00
Get unique source files:                               00:00:33
Creating an index out of the source files:             00:00:34
Going into prepareFileReports:                         00:00:34
Going to emit summary information for each file:       00:28:55 <-- 28:21 min!
Going to emit links to files with no function:         00:28:55
Launching 32 threads for generating HTML files:        00:28:55

real  37m43.651s
user  112m5.540s
sys   7m39.872s
```

2) Multi-threaded version with 32 CPUs:
```
$ time llvm-cov show -format=html -output-dir=report -instr-profile=... ...
The tool has been launched:                            00:00:00
Loading coverage data:                                 00:00:00
Get unique source files:                               00:00:38
Creating an index out of the source files:             00:00:40
Going into prepareFileReports:                         00:00:40
Preparing file reports using 32 threads:               00:00:40
# Creating thread tasks for the following number of files: 16422
Going to emit summary information for each file:       00:01:57 <-- 1:17 min!
Going to emit links to files with no function:         00:01:58
Launching 32 threads for generating HTML files:        00:01:58

real  11m2.044s
user  134m48.124s
sys   7m53.388s
```

Reviewers: vsk, morehouse

Reviewed By: vsk

Subscribers: Dor1s, llvm-commits, kcc

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

llvm-svn: 321871
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 9c553a7..aafdc43 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -16,6 +16,8 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/Threading.h"
 #include <numeric>
 
 using namespace llvm;
@@ -319,42 +321,60 @@
   }
 }
 
+void CoverageReport::prepareSingleFileReport(const StringRef Filename,
+    const coverage::CoverageMapping *Coverage,
+    const CoverageViewOptions &Options, const unsigned LCP,
+    FileCoverageSummary *FileReport, const CoverageFilter *Filters) {
+  for (const auto &Group : Coverage->getInstantiationGroups(Filename)) {
+    std::vector<FunctionCoverageSummary> InstantiationSummaries;
+    for (const coverage::FunctionRecord *F : Group.getInstantiations()) {
+      if (!Filters->matches(*Coverage, *F))
+        continue;
+      auto InstantiationSummary = FunctionCoverageSummary::get(*Coverage, *F);
+      FileReport->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";
+
+    FileReport->addFunction(GroupSummary);
+  }
+}
+
 std::vector<FileCoverageSummary> CoverageReport::prepareFileReports(
     const coverage::CoverageMapping &Coverage, FileCoverageSummary &Totals,
     ArrayRef<std::string> Files, const CoverageViewOptions &Options,
     const CoverageFilter &Filters) {
-  std::vector<FileCoverageSummary> 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())));
+
+  ThreadPool Pool(NumThreads);
+
+  std::vector<FileCoverageSummary> FileReports;
+  FileReports.reserve(Files.size());
 
   for (StringRef Filename : Files) {
-    FileCoverageSummary Summary(Filename.drop_front(LCP));
-
-    for (const auto &Group : Coverage.getInstantiationGroups(Filename)) {
-      std::vector<FunctionCoverageSummary> 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);
+    FileReports.emplace_back(Filename.drop_front(LCP));
+    Pool.async(&CoverageReport::prepareSingleFileReport, Filename,
+               &Coverage, Options, LCP, &FileReports.back(), &Filters);
   }
+  Pool.wait();
+
+  for (const auto &FileReport : FileReports)
+    Totals += FileReport;
 
   return FileReports;
 }