summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/llvm-profdata/llvm-profdata.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2017-01-24 08:32:59 +0000
committerpatrick <patrick@openbsd.org>2017-01-24 08:32:59 +0000
commit53d771aafdbe5b919f264f53cba3788e2c4cffd2 (patch)
tree7eca39498be0ff1e3a6daf583cd9ca5886bb2636 /gnu/llvm/tools/llvm-profdata/llvm-profdata.cpp
parentIn preparation of compiling our kernels with -ffreestanding, explicitly map (diff)
downloadwireguard-openbsd-53d771aafdbe5b919f264f53cba3788e2c4cffd2.tar.xz
wireguard-openbsd-53d771aafdbe5b919f264f53cba3788e2c4cffd2.zip
Import LLVM 4.0.0 rc1 including clang and lld to help the current
development effort on OpenBSD/arm64.
Diffstat (limited to 'gnu/llvm/tools/llvm-profdata/llvm-profdata.cpp')
-rw-r--r--gnu/llvm/tools/llvm-profdata/llvm-profdata.cpp220
1 files changed, 178 insertions, 42 deletions
diff --git a/gnu/llvm/tools/llvm-profdata/llvm-profdata.cpp b/gnu/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 8e4b4c3d4ed..6715566a166 100644
--- a/gnu/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/gnu/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -29,6 +29,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -108,18 +109,79 @@ static void handleMergeWriterError(Error E, StringRef WhenceFile = "",
}
struct WeightedFile {
- StringRef Filename;
+ std::string Filename;
uint64_t Weight;
-
- WeightedFile() {}
-
- WeightedFile(StringRef F, uint64_t W) : Filename{F}, Weight{W} {}
};
typedef SmallVector<WeightedFile, 5> WeightedFileVector;
+/// Keep track of merged data and reported errors.
+struct WriterContext {
+ std::mutex Lock;
+ InstrProfWriter Writer;
+ Error Err;
+ StringRef ErrWhence;
+ std::mutex &ErrLock;
+ SmallSet<instrprof_error, 4> &WriterErrorCodes;
+
+ WriterContext(bool IsSparse, std::mutex &ErrLock,
+ SmallSet<instrprof_error, 4> &WriterErrorCodes)
+ : Lock(), Writer(IsSparse), Err(Error::success()), ErrWhence(""),
+ ErrLock(ErrLock), WriterErrorCodes(WriterErrorCodes) {}
+};
+
+/// Load an input into a writer context.
+static void loadInput(const WeightedFile &Input, WriterContext *WC) {
+ std::unique_lock<std::mutex> CtxGuard{WC->Lock};
+
+ // If there's a pending hard error, don't do more work.
+ if (WC->Err)
+ return;
+
+ WC->ErrWhence = Input.Filename;
+
+ auto ReaderOrErr = InstrProfReader::create(Input.Filename);
+ if (Error E = ReaderOrErr.takeError()) {
+ // Skip the empty profiles by returning sliently.
+ instrprof_error IPE = InstrProfError::take(std::move(E));
+ if (IPE != instrprof_error::empty_raw_profile)
+ WC->Err = make_error<InstrProfError>(IPE);
+ return;
+ }
+
+ auto Reader = std::move(ReaderOrErr.get());
+ bool IsIRProfile = Reader->isIRLevelProfile();
+ if (WC->Writer.setIsIRLevelProfile(IsIRProfile)) {
+ WC->Err = make_error<StringError>(
+ "Merge IR generated profile with Clang generated profile.",
+ std::error_code());
+ return;
+ }
+
+ for (auto &I : *Reader) {
+ const StringRef FuncName = I.Name;
+ if (Error E = WC->Writer.addRecord(std::move(I), Input.Weight)) {
+ // Only show hint the first time an error occurs.
+ instrprof_error IPE = InstrProfError::take(std::move(E));
+ std::unique_lock<std::mutex> ErrGuard{WC->ErrLock};
+ bool firstTime = WC->WriterErrorCodes.insert(IPE).second;
+ handleMergeWriterError(make_error<InstrProfError>(IPE), Input.Filename,
+ FuncName, firstTime);
+ }
+ }
+ if (Reader->hasError())
+ WC->Err = Reader->getError();
+}
+
+/// Merge the \p Src writer context into \p Dst.
+static void mergeWriterContexts(WriterContext *Dst, WriterContext *Src) {
+ if (Error E = Dst->Writer.mergeRecordsFromWriter(std::move(Src->Writer)))
+ Dst->Err = std::move(E);
+}
+
static void mergeInstrProfile(const WeightedFileVector &Inputs,
StringRef OutputFilename,
- ProfileFormat OutputFormat, bool OutputSparse) {
+ ProfileFormat OutputFormat, bool OutputSparse,
+ unsigned NumThreads) {
if (OutputFilename.compare("-") == 0)
exitWithError("Cannot write indexed profdata format to stdout.");
@@ -131,30 +193,59 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
if (EC)
exitWithErrorCode(EC, OutputFilename);
- InstrProfWriter Writer(OutputSparse);
+ std::mutex ErrorLock;
SmallSet<instrprof_error, 4> WriterErrorCodes;
- for (const auto &Input : Inputs) {
- auto ReaderOrErr = InstrProfReader::create(Input.Filename);
- if (Error E = ReaderOrErr.takeError())
- exitWithError(std::move(E), Input.Filename);
-
- auto Reader = std::move(ReaderOrErr.get());
- bool IsIRProfile = Reader->isIRLevelProfile();
- if (Writer.setIsIRLevelProfile(IsIRProfile))
- exitWithError("Merge IR generated profile with Clang generated profile.");
-
- for (auto &I : *Reader) {
- if (Error E = Writer.addRecord(std::move(I), Input.Weight)) {
- // Only show hint the first time an error occurs.
- instrprof_error IPE = InstrProfError::take(std::move(E));
- bool firstTime = WriterErrorCodes.insert(IPE).second;
- handleMergeWriterError(make_error<InstrProfError>(IPE), Input.Filename,
- I.Name, firstTime);
- }
+
+ // If NumThreads is not specified, auto-detect a good default.
+ if (NumThreads == 0)
+ NumThreads = std::max(1U, std::min(std::thread::hardware_concurrency(),
+ unsigned(Inputs.size() / 2)));
+
+ // Initialize the writer contexts.
+ SmallVector<std::unique_ptr<WriterContext>, 4> Contexts;
+ for (unsigned I = 0; I < NumThreads; ++I)
+ Contexts.emplace_back(llvm::make_unique<WriterContext>(
+ OutputSparse, ErrorLock, WriterErrorCodes));
+
+ if (NumThreads == 1) {
+ for (const auto &Input : Inputs)
+ loadInput(Input, Contexts[0].get());
+ } else {
+ ThreadPool Pool(NumThreads);
+
+ // Load the inputs in parallel (N/NumThreads serial steps).
+ unsigned Ctx = 0;
+ for (const auto &Input : Inputs) {
+ Pool.async(loadInput, Input, Contexts[Ctx].get());
+ Ctx = (Ctx + 1) % NumThreads;
}
- if (Reader->hasError())
- exitWithError(Reader->getError(), Input.Filename);
+ Pool.wait();
+
+ // Merge the writer contexts together (~ lg(NumThreads) serial steps).
+ unsigned Mid = Contexts.size() / 2;
+ unsigned End = Contexts.size();
+ assert(Mid > 0 && "Expected more than one context");
+ do {
+ for (unsigned I = 0; I < Mid; ++I)
+ Pool.async(mergeWriterContexts, Contexts[I].get(),
+ Contexts[I + Mid].get());
+ Pool.wait();
+ if (End & 1) {
+ Pool.async(mergeWriterContexts, Contexts[0].get(),
+ Contexts[End - 1].get());
+ Pool.wait();
+ }
+ End = Mid;
+ Mid /= 2;
+ } while (Mid > 0);
}
+
+ // Handle deferred hard errors encountered during merging.
+ for (std::unique_ptr<WriterContext> &WC : Contexts)
+ if (WC->Err)
+ exitWithError(std::move(WC->Err), WC->ErrWhence);
+
+ InstrProfWriter &Writer = Contexts[0]->Writer;
if (OutputFormat == PF_Text)
Writer.writeText(Output);
else
@@ -216,11 +307,7 @@ static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) {
if (WeightStr.getAsInteger(10, Weight) || Weight < 1)
exitWithError("Input weight must be a positive integer.");
- if (!sys::fs::exists(FileName))
- exitWithErrorCode(make_error_code(errc::no_such_file_or_directory),
- FileName);
-
- return WeightedFile(FileName, Weight);
+ return {FileName, Weight};
}
static std::unique_ptr<MemoryBuffer>
@@ -235,6 +322,40 @@ getInputFilenamesFileBuf(const StringRef &InputFilenamesFile) {
return std::move(*BufOrError);
}
+static void addWeightedInput(WeightedFileVector &WNI, const WeightedFile &WF) {
+ StringRef Filename = WF.Filename;
+ uint64_t Weight = WF.Weight;
+
+ // If it's STDIN just pass it on.
+ if (Filename == "-") {
+ WNI.push_back({Filename, Weight});
+ return;
+ }
+
+ llvm::sys::fs::file_status Status;
+ llvm::sys::fs::status(Filename, Status);
+ if (!llvm::sys::fs::exists(Status))
+ exitWithErrorCode(make_error_code(errc::no_such_file_or_directory),
+ Filename);
+ // If it's a source file, collect it.
+ if (llvm::sys::fs::is_regular_file(Status)) {
+ WNI.push_back({Filename, Weight});
+ return;
+ }
+
+ if (llvm::sys::fs::is_directory(Status)) {
+ std::error_code EC;
+ for (llvm::sys::fs::recursive_directory_iterator F(Filename, EC), E;
+ F != E && !EC; F.increment(EC)) {
+ if (llvm::sys::fs::is_regular_file(F->path())) {
+ addWeightedInput(WNI, {F->path(), Weight});
+ }
+ }
+ if (EC)
+ exitWithErrorCode(EC, Filename);
+ }
+}
+
static void parseInputFilenamesFile(MemoryBuffer *Buffer,
WeightedFileVector &WFV) {
if (!Buffer)
@@ -250,9 +371,9 @@ static void parseInputFilenamesFile(MemoryBuffer *Buffer,
continue;
// If there's no comma, it's an unweighted profile.
else if (SanitizedEntry.find(',') == StringRef::npos)
- WFV.emplace_back(SanitizedEntry, 1);
+ addWeightedInput(WFV, {SanitizedEntry, 1});
else
- WFV.emplace_back(parseWeightedFile(SanitizedEntry));
+ addWeightedInput(WFV, parseWeightedFile(SanitizedEntry));
}
}
@@ -278,24 +399,28 @@ static int merge_main(int argc, const char *argv[]) {
cl::opt<ProfileKinds> ProfileKind(
cl::desc("Profile kind:"), cl::init(instr),
cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
- clEnumVal(sample, "Sample profile"), clEnumValEnd));
+ clEnumVal(sample, "Sample profile")));
cl::opt<ProfileFormat> OutputFormat(
cl::desc("Format of output profile"), cl::init(PF_Binary),
cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
clEnumValN(PF_Text, "text", "Text encoding"),
clEnumValN(PF_GCC, "gcc",
- "GCC encoding (only meaningful for -sample)"),
- clEnumValEnd));
+ "GCC encoding (only meaningful for -sample)")));
cl::opt<bool> OutputSparse("sparse", cl::init(false),
cl::desc("Generate a sparse profile (only meaningful for -instr)"));
+ cl::opt<unsigned> NumThreads(
+ "num-threads", cl::init(0),
+ cl::desc("Number of merge threads to use (default: autodetect)"));
+ cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
+ cl::aliasopt(NumThreads));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
WeightedFileVector WeightedInputs;
for (StringRef Filename : InputFilenames)
- WeightedInputs.emplace_back(Filename, 1);
+ addWeightedInput(WeightedInputs, {Filename, 1});
for (StringRef WeightedFilename : WeightedInputFilenames)
- WeightedInputs.emplace_back(parseWeightedFile(WeightedFilename));
+ addWeightedInput(WeightedInputs, parseWeightedFile(WeightedFilename));
// Make sure that the file buffer stays alive for the duration of the
// weighted input vector's lifetime.
@@ -314,7 +439,7 @@ static int merge_main(int argc, const char *argv[]) {
if (ProfileKind == instr)
mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat,
- OutputSparse);
+ OutputSparse, NumThreads);
else
mergeSampleProfile(WeightedInputs, OutputFilename, OutputFormat);
@@ -343,6 +468,7 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
uint64_t TotalNumValueSites = 0;
uint64_t TotalNumValueSitesWithValueProfile = 0;
uint64_t TotalNumValues = 0;
+ std::vector<unsigned> ICHistogram;
for (const auto &Func : *Reader) {
bool Show =
ShowAllFunctions || (!ShowFunction.empty() &&
@@ -395,8 +521,12 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
std::unique_ptr<InstrProfValueData[]> VD =
Func.getValueForSite(IPVK_IndirectCallTarget, I);
TotalNumValues += NV;
- if (NV)
+ if (NV) {
TotalNumValueSitesWithValueProfile++;
+ if (NV > ICHistogram.size())
+ ICHistogram.resize(NV, 0);
+ ICHistogram[NV - 1]++;
+ }
for (uint32_t V = 0; V < NV; V++) {
OS << "\t[ " << I << ", ";
OS << Symtab.getFuncName(VD[V].Value) << ", " << VD[V].Count
@@ -423,6 +553,11 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
OS << "Total Number of Sites With Values : "
<< TotalNumValueSitesWithValueProfile << "\n";
OS << "Total Number of Profiled Values : " << TotalNumValues << "\n";
+
+ OS << "IC Value histogram : \n\tNumTargets, SiteCount\n";
+ for (unsigned I = 0; I < ICHistogram.size(); I++) {
+ OS << "\t" << I + 1 << ", " << ICHistogram[I] << "\n";
+ }
}
if (ShowDetailedSummary) {
@@ -492,7 +627,7 @@ static int show_main(int argc, const char *argv[]) {
cl::opt<ProfileKinds> ProfileKind(
cl::desc("Profile kind:"), cl::init(instr),
cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
- clEnumVal(sample, "Sample profile"), clEnumValEnd));
+ clEnumVal(sample, "Sample profile")));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
@@ -545,6 +680,7 @@ int main(int argc, const char *argv[]) {
errs() << "OVERVIEW: LLVM profile data tools\n\n"
<< "USAGE: " << ProgName << " <command> [args...]\n"
<< "USAGE: " << ProgName << " <command> -help\n\n"
+ << "See each individual command --help for more details.\n"
<< "Available commands: merge, show\n";
return 0;
}