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:
parent
7706680906
commit
4b0b398802
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user