diff options
author | Vedant Kumar <vsk@apple.com> | 2016-07-13 21:38:36 +0000 |
---|---|---|
committer | Vedant Kumar <vsk@apple.com> | 2016-07-13 21:38:36 +0000 |
commit | 9240c457f72e2a507389e49715258ac329feab9a (patch) | |
tree | 8ab95db3f460a96ba63d09a01f8565a40a674266 /tools | |
parent | a48eee2309236799481c6bf7fd43a4bff76ed19b (diff) |
[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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275321 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools')
-rw-r--r-- | tools/llvm-cov/CodeCoverage.cpp | 99 |
1 files changed, 75 insertions, 24 deletions
diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp index 7b9edc0e731..693c8024920 100644 --- a/tools/llvm-cov/CodeCoverage.cpp +++ b/tools/llvm-cov/CodeCoverage.cpp @@ -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(StringRef SourceFile) { 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, const char **argv, } } - 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; } |