[llvm] r275321 - [llvm-cov] Use a thread pool to speed up report generation (NFC)

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 13 14:38:36 PDT 2016


Author: vedantk
Date: Wed Jul 13 16:38:36 2016
New Revision: 275321

URL: http://llvm.org/viewvc/llvm-project?rev=275321&view=rev
Log:
[llvm-cov] Use a thread pool to speed up report generation (NFC)

It's safe to print out source coverage views using multiple threads when
using the -output-dir mode of the `llvm-cov show` sub-command.

While testing this on my development machine, I observed that the speed
up is roughly linear with the number of available cores. Avg. time for
`llvm-cov show ./llvm-as -show-line-counts-or-regions`:

    1 thread: 7.79s user 0.33s system 98% cpu 8.228 total
    4 threads: 7.82s user 0.34s system 283% cpu 2.880 total

Modified:
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp

Modified: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=275321&r1=275320&r2=275321&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Wed Jul 13 16:38:36 2016
@@ -28,6 +28,7 @@
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
+#include "llvm/Support/ThreadPool.h"
 #include <functional>
 #include <system_error>
 
@@ -48,6 +49,15 @@ public:
   /// \brief Print the error message to the error output stream.
   void error(const Twine &Message, StringRef Whence = "");
 
+  /// \brief Record (but do not print) an error message in a thread-safe way.
+  void deferError(const Twine &Message, StringRef Whence = "");
+
+  /// \brief Record (but do not print) a warning message in a thread-safe way.
+  void deferWarning(const Twine &Message, StringRef Whence = "");
+
+  /// \brief Print (and then clear) all deferred error and warning messages.
+  void consumeDeferredMessages();
+
   /// \brief Append a reference to a private copy of \p Path into SourceFiles.
   void addCollectedPath(const std::string &Path);
 
@@ -85,22 +95,51 @@ public:
   std::string PGOFilename;
   CoverageFiltersMatchAll Filters;
   std::vector<StringRef> SourceFiles;
-  std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
-      LoadedSourceFiles;
   bool CompareFilenamesOnly;
   StringMap<std::string> RemappedFilenames;
   std::string CoverageArch;
 
 private:
   std::vector<std::string> CollectedPaths;
+
+  std::mutex DeferredMessagesLock;
+  std::vector<std::string> DeferredMessages;
+
+  std::mutex LoadedSourceFilesLock;
+  std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
+      LoadedSourceFiles;
 };
 }
 
-void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
-  errs() << "error: ";
+static std::string getErrorString(const Twine &Message, StringRef Whence,
+                                  bool Warning) {
+  std::string Str = (Warning ? "warning" : "error");
+  Str += ": ";
   if (!Whence.empty())
-    errs() << Whence << ": ";
-  errs() << Message << "\n";
+    Str += Whence;
+  Str += Message.str() + "\n";
+  return Str;
+}
+
+void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
+  errs() << getErrorString(Message, Whence, false);
+}
+
+void CodeCoverageTool::deferError(const Twine &Message, StringRef Whence) {
+  std::unique_lock<std::mutex> Guard{DeferredMessagesLock};
+  DeferredMessages.emplace_back(getErrorString(Message, Whence, false));
+}
+
+void CodeCoverageTool::deferWarning(const Twine &Message, StringRef Whence) {
+  std::unique_lock<std::mutex> Guard{DeferredMessagesLock};
+  DeferredMessages.emplace_back(getErrorString(Message, Whence, true));
+}
+
+void CodeCoverageTool::consumeDeferredMessages() {
+  std::unique_lock<std::mutex> Guard{DeferredMessagesLock};
+  for (const std::string &Message : DeferredMessages)
+    ViewOpts.colored_ostream(errs(), raw_ostream::RED) << Message;
+  DeferredMessages.clear();
 }
 
 void CodeCoverageTool::addCollectedPath(const std::string &Path) {
@@ -121,9 +160,10 @@ CodeCoverageTool::getSourceFile(StringRe
       return *Files.second;
   auto Buffer = MemoryBuffer::getFile(SourceFile);
   if (auto EC = Buffer.getError()) {
-    error(EC.message(), SourceFile);
+    deferError(EC.message(), SourceFile);
     return EC;
   }
+  std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock};
   LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
   return *LoadedSourceFiles.back().second;
 }
@@ -505,26 +545,37 @@ int CodeCoverageTool::show(int argc, con
     }
   }
 
-  for (const auto &SourceFile : SourceFiles) {
-    auto mainView = createSourceFileView(SourceFile, *Coverage);
-    if (!mainView) {
-      ViewOpts.colored_ostream(errs(), raw_ostream::RED)
-          << "warning: The file '" << SourceFile << "' isn't covered.";
-      errs() << "\n";
-      continue;
-    }
+  // In -output-dir mode, it's safe to use multiple threads to print files.
+  unsigned ThreadCount = 1;
+  if (ViewOpts.hasOutputDirectory())
+    ThreadCount = std::thread::hardware_concurrency();
+  ThreadPool Pool(ThreadCount);
+
+  for (StringRef &SourceFile : SourceFiles) {
+    Pool.async([this, &SourceFile, &Coverage, &Printer, ShowFilenames] {
+      auto View = createSourceFileView(SourceFile, *Coverage);
+      if (!View) {
+        deferWarning("The file '" + SourceFile.str() + "' isn't covered.");
+        return;
+      }
 
-    auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
-    if (Error E = OSOrErr.takeError()) {
-      error(toString(std::move(E)));
-      return 1;
-    }
-    auto OS = std::move(OSOrErr.get());
-    mainView->print(*OS.get(), /*Wholefile=*/true,
-                    /*ShowSourceName=*/ShowFilenames);
-    Printer->closeViewFile(std::move(OS));
+      auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
+      if (Error E = OSOrErr.takeError()) {
+        deferError(toString(std::move(E)));
+        return;
+      }
+      auto OS = std::move(OSOrErr.get());
+
+      View->print(*OS.get(), /*Wholefile=*/true,
+                  /*ShowSourceName=*/ShowFilenames);
+      Printer->closeViewFile(std::move(OS));
+    });
   }
 
+  Pool.wait();
+
+  consumeDeferredMessages();
+
   return 0;
 }
 




More information about the llvm-commits mailing list