1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[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

llvm-svn: 275321
This commit is contained in:
Vedant Kumar 2016-07-13 21:38:36 +00:00
parent 7706680906
commit 4b0b398802

View File

@ -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);
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));
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()) {
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;
}