[llvm] [compiler-rt] [Profile] Allow profile merging with multiple correlate files. (PR #75957)
Zequan Wu via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 19 09:52:25 PST 2023
https://github.com/ZequanWu created https://github.com/llvm/llvm-project/pull/75957
This allows llvm-profdata to merge lightweight raw profiles with multiple correlate files and associate lightweight raw profiles with correlate files using binary id. For correlate files without binary id, it will be used for lightweight raw profiles without binary id as well.
This doesn't support the following:
1. Merging raw profile that is generated by a binary which linked with objects with mixed correlation modes. This is because the binary has only one binary id and it can only be used either for debug info correlation or binary correlation, not both.
2. Merging raw profile that is generated by a statically linked binary which has some objects compiled with correlation and some without correlation. This is because it will generate a raw profile with data and name info for some counters but not all. The rest counters need data and name info from correlation files, which is hard to differentiate those two kinds of counter.
>From d72f0e1ad7759bad81767418604d27f11d74d6de Mon Sep 17 00:00:00 2001
From: Zequan Wu <zequanwu at google.com>
Date: Tue, 19 Dec 2023 12:32:15 -0500
Subject: [PATCH 1/2] [Profile] Allow profile merging with multiple correlate
files.
---
.../Linux/instrprof-correlation-mixed.test | 33 ++++
.../Linux/instrprof-debug-info-correlate.c | 19 ++
.../llvm/ProfileData/InstrProfCorrelator.h | 124 ++++++++++---
.../llvm/ProfileData/InstrProfReader.h | 17 +-
llvm/lib/Object/BuildID.cpp | 18 ++
llvm/lib/ProfileData/InstrProfCorrelator.cpp | 164 +++++++++++++-----
llvm/lib/ProfileData/InstrProfReader.cpp | 26 ++-
llvm/tools/llvm-profdata/llvm-profdata.cpp | 84 +++++----
8 files changed, 358 insertions(+), 127 deletions(-)
create mode 100644 compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test
diff --git a/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test b/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test
new file mode 100644
index 00000000000000..8cc4611eec4f0b
--- /dev/null
+++ b/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test
@@ -0,0 +1,33 @@
+// REQUIRES: lld-available
+// Test llvm-profdata merging with multiple correlation files mixing different correlation modes.
+
+// RUN: %clang_pgogen -o %t.normal -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
+
+// Compiling with differnt configs.
+// RUN: %clang_pgogen -o %t -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp -c -o %t-main.o
+// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp -c -o %t-main.debug.o
+// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-foo.cpp -fpic -shared -Wl,--build-id -o %t-libfoo.debug.so
+// RUN: %clang_pgogen -o %t -mllvm -profile-correlate=binary -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-foo.cpp -fpic -shared -Wl,--build-id -o %t-libfoo.binary.so
+
+// Test mixing default raw profile and lightweight raw profile generated with debug info correlate.
+// The raw profiles are mixed in %t.proflite.
+// RUN: %clang_pgogen -o %t %t-main.o %t-libfoo.debug.so -Wl,--build-id -o %t
+// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t-libfoo.debug.so %t.proflite
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+// Two separate raw profiles.
+// RUN: rm -rf %t.dir && mkdir %t.dir
+// RUN: env LLVM_PROFILE_FILE=%t.dir/raw%m.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t-libfoo.debug.so %t.dir
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// Test lightweight raw profiles generated with debug info correlate and binary correlate.
+// Note we can not mix different correlation modes in static linking because when merging, the same correlate file can not be used for more than one correaltion mode.
+// Two separate lightweight raw profiles.
+// RUN: %clang_pgogen -o %t -g %t-main.debug.o %t-libfoo.binary.so -Wl,--build-id -o %t
+// RUN: rm -rf %t.dir && mkdir %t.dir
+// RUN: env LLVM_PROFILE_FILE=%t.dir/raw%m.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t --binary-file=%t-libfoo.binary.so %t.dir
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
diff --git a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
index a918d7b6299005..47dbf3c87e68f1 100644
--- a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
+++ b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
@@ -25,6 +25,25 @@
// RUN: diff <(llvm-profdata show --all-functions --counts %t.cov.normal.profdata) <(llvm-profdata show --all-functions --counts %t.cov.profdata)
+// Test debug info correlate with build id.
+
+// Both binaries are built with build id.
+// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-foo.cpp -c -fpic -shared -Wl,--build-id -o %t-libfoo.so
+// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %t-libfoo.so -Wl,--build-id -o %t
+// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t,%t-libfoo.o %t.proflite
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// One binary is built without build id.
+// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %t-libfoo.so -o %t
+// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t,%t-libfoo.o %t.proflite
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// Warning about multiple correlate files have the same build id.
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t,%t,%t-libfoo.o %t.proflite 2>&1 >/dev/null | FileCheck %s --check-prefix=WARN
+// WARN: Duplicate build id ({{.*}}) found for {{.*}} and {{.*}}
+
// Test debug info correlate with online merging.
// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal
diff --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
index c07c67d287e2ce..1b579e0ac2fd24 100644
--- a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
+++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
@@ -13,6 +13,7 @@
#define LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
#include "llvm/ADT/DenseSet.h"
+#include "llvm/Object/BuildID.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -35,20 +36,33 @@ class InstrProfCorrelator {
/// correlate.
enum ProfCorrelatorKind { NONE, DEBUG_INFO, BINARY };
+ struct AtomicWarningCounter {
+ AtomicWarningCounter(uint64_t MaxWarnings)
+ : MaxWarnings(MaxWarnings), WarningCount(0){};
+ bool shouldEmitWarning();
+ ~AtomicWarningCounter();
+
+ private:
+ const uint64_t MaxWarnings;
+ std::atomic<uint64_t> WarningCount;
+ };
+
static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
- get(StringRef Filename, ProfCorrelatorKind FileKind);
+ get(StringRef Filename, ProfCorrelatorKind FileKind,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter);
/// Construct a ProfileData vector used to correlate raw instrumentation data
/// to their functions.
- /// \param MaxWarnings the maximum number of warnings to emit (0 = no limit)
- virtual Error correlateProfileData(int MaxWarnings) = 0;
+ virtual Error correlateProfileData() = 0;
/// Process debug info and dump the correlation data.
- /// \param MaxWarnings the maximum number of warnings to emit (0 = no limit)
- virtual Error dumpYaml(int MaxWarnings, raw_ostream &OS) = 0;
+ virtual Error dumpYaml(raw_ostream &OS) = 0;
+
+ virtual const char *getDataPointer() const = 0;
/// Return the number of ProfileData elements.
- std::optional<size_t> getDataSize() const;
+ size_t getDataSize() const;
/// Return a pointer to the names string that this class constructs.
const char *getNamesPointer() const { return Names.c_str(); }
@@ -61,6 +75,8 @@ class InstrProfCorrelator {
return Ctx->CountersSectionEnd - Ctx->CountersSectionStart;
}
+ object::BuildIDRef getBuildID() const { return Ctx->BuildID; }
+
static const char *FunctionNameAttributeName;
static const char *CFGHashAttributeName;
static const char *NumCountersAttributeName;
@@ -84,16 +100,25 @@ class InstrProfCorrelator {
const char *DataEnd;
const char *NameStart;
size_t NameSize;
+ object::BuildIDRef BuildID;
/// True if target and host have different endian orders.
bool ShouldSwapBytes;
};
const std::unique_ptr<Context> Ctx;
- InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr<Context> Ctx)
- : Ctx(std::move(Ctx)), Kind(K) {}
+ InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr<Context> Ctx,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter)
+ : Ctx(std::move(Ctx)), IsCorrelated(false), CorrelateLock(CorrelateLock),
+ WarnLock(WarnLock), WarnCounter(WarnCounter), Kind(K) {}
std::string Names;
- std::vector<std::string> NamesVec;
+ /// True if correlation is already done.
+ bool IsCorrelated;
+ std::mutex &CorrelateLock;
+ std::mutex &WarnLock;
+
+ bool shouldEmitWarning();
struct Probe {
std::string FunctionName;
@@ -115,8 +140,11 @@ class InstrProfCorrelator {
private:
static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
- get(std::unique_ptr<MemoryBuffer> Buffer, ProfCorrelatorKind FileKind);
+ get(std::unique_ptr<MemoryBuffer> Buffer, ProfCorrelatorKind FileKind,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter);
+ AtomicWarningCounter *WarnCounter;
const InstrProfCorrelatorKind Kind;
};
@@ -125,13 +153,15 @@ class InstrProfCorrelator {
template <class IntPtrT>
class InstrProfCorrelatorImpl : public InstrProfCorrelator {
public:
- InstrProfCorrelatorImpl(std::unique_ptr<InstrProfCorrelator::Context> Ctx);
+ InstrProfCorrelatorImpl(std::unique_ptr<InstrProfCorrelator::Context> Ctx,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter);
static bool classof(const InstrProfCorrelator *C);
/// Return a pointer to the underlying ProfileData vector that this class
/// constructs.
- const RawInstrProf::ProfileData<IntPtrT> *getDataPointer() const {
- return Data.empty() ? nullptr : Data.data();
+ const char *getDataPointer() const override {
+ return Data.empty() ? nullptr : (const char *)Data.data();
}
/// Return the number of ProfileData elements.
@@ -139,19 +169,20 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator {
static llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
get(std::unique_ptr<InstrProfCorrelator::Context> Ctx,
- const object::ObjectFile &Obj, ProfCorrelatorKind FileKind);
+ const object::ObjectFile &Obj, ProfCorrelatorKind FileKind,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter);
protected:
std::vector<RawInstrProf::ProfileData<IntPtrT>> Data;
- Error correlateProfileData(int MaxWarnings) override;
+ Error correlateProfileData() override;
virtual void correlateProfileDataImpl(
- int MaxWarnings,
InstrProfCorrelator::CorrelationData *Data = nullptr) = 0;
virtual Error correlateProfileNameImpl() = 0;
- Error dumpYaml(int MaxWarnings, raw_ostream &OS) override;
+ Error dumpYaml(raw_ostream &OS) override;
void addDataProbe(uint64_t FunctionName, uint64_t CFGHash,
IntPtrT CounterOffset, IntPtrT FunctionPtr,
@@ -164,8 +195,11 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator {
private:
InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind,
- std::unique_ptr<InstrProfCorrelator::Context> Ctx)
- : InstrProfCorrelator(Kind, std::move(Ctx)){};
+ std::unique_ptr<InstrProfCorrelator::Context> Ctx,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter)
+ : InstrProfCorrelator(Kind, std::move(Ctx), CorrelateLock, WarnLock,
+ WarnCounter){};
llvm::DenseSet<IntPtrT> CounterOffsets;
};
@@ -174,13 +208,18 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator {
template <class IntPtrT>
class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
public:
- DwarfInstrProfCorrelator(std::unique_ptr<DWARFContext> DICtx,
- std::unique_ptr<InstrProfCorrelator::Context> Ctx)
- : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)),
+ DwarfInstrProfCorrelator(
+ std::unique_ptr<DWARFContext> DICtx,
+ std::unique_ptr<InstrProfCorrelator::Context> Ctx,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ InstrProfCorrelator::AtomicWarningCounter *WarnCounter)
+ : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx), CorrelateLock,
+ WarnLock, WarnCounter),
DICtx(std::move(DICtx)) {}
private:
std::unique_ptr<DWARFContext> DICtx;
+ std::vector<std::string> NamesVec;
/// Return the address of the object that the provided DIE symbolizes.
std::optional<uint64_t> getLocation(const DWARFDie &Die) const;
@@ -217,7 +256,6 @@ class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
/// \param MaxWarnings the maximum number of warnings to emit (0 = no limit)
/// \param Data if provided, populate with the correlation data found
void correlateProfileDataImpl(
- int MaxWarnings,
InstrProfCorrelator::CorrelationData *Data = nullptr) override;
Error correlateProfileNameImpl() override;
@@ -228,8 +266,12 @@ class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
template <class IntPtrT>
class BinaryInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
public:
- BinaryInstrProfCorrelator(std::unique_ptr<InstrProfCorrelator::Context> Ctx)
- : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)) {}
+ BinaryInstrProfCorrelator(
+ std::unique_ptr<InstrProfCorrelator::Context> Ctx,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ InstrProfCorrelator::AtomicWarningCounter *WarnCounter)
+ : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx), CorrelateLock,
+ WarnLock, WarnCounter) {}
/// Return a pointer to the names string that this class constructs.
const char *getNamesPointer() const { return this->Ctx.NameStart; }
@@ -239,12 +281,42 @@ class BinaryInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
private:
void correlateProfileDataImpl(
- int MaxWarnings,
InstrProfCorrelator::CorrelationData *Data = nullptr) override;
Error correlateProfileNameImpl() override;
};
+// InstrProfCorrelators contains a map from BuildID to InstrProfCorrelator and
+// correlate profile on-demand when users call getCorrelator.
+class InstrProfCorrelators {
+public:
+ static llvm::Expected<std::unique_ptr<InstrProfCorrelators>>
+ get(ArrayRef<std::pair<StringRef, InstrProfCorrelator::ProfCorrelatorKind>>
+ CorrelateInputs,
+ uint32_t MaxWarnings);
+
+ InstrProfCorrelators(
+ StringMap<std::unique_ptr<InstrProfCorrelator>> &&CorrelatorMap,
+ std::unique_ptr<std::mutex> CorrelateLock,
+ std::unique_ptr<std::mutex> WarnLock,
+ std::unique_ptr<InstrProfCorrelator::AtomicWarningCounter> WarnCounter)
+ : CorrelatorMap(std::move(CorrelatorMap)),
+ CorrelateLock(std::move(CorrelateLock)), WarnLock(std::move(WarnLock)),
+ WarnCounter(std::move(WarnCounter)) {}
+
+ llvm::Expected<const InstrProfCorrelator *>
+ getCorrelator(object::BuildIDRef BuildID) const;
+
+ bool empty() const { return CorrelatorMap.empty(); }
+ Error dumpYaml(raw_ostream &OS);
+
+private:
+ // A map from BuildID to correlator.
+ const StringMap<std::unique_ptr<InstrProfCorrelator>> CorrelatorMap;
+ std::unique_ptr<std::mutex> CorrelateLock;
+ std::unique_ptr<std::mutex> WarnLock;
+ std::unique_ptr<InstrProfCorrelator::AtomicWarningCounter> WarnCounter;
+};
} // end namespace llvm
#endif // LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index ff50dfde0e7938..c7810c8b1af50c 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -199,12 +199,12 @@ class InstrProfReader {
/// instrprof file.
static Expected<std::unique_ptr<InstrProfReader>>
create(const Twine &Path, vfs::FileSystem &FS,
- const InstrProfCorrelator *Correlator = nullptr,
+ const InstrProfCorrelators *Correlators = nullptr,
std::function<void(Error)> Warn = nullptr);
static Expected<std::unique_ptr<InstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer,
- const InstrProfCorrelator *Correlator = nullptr,
+ const InstrProfCorrelators *Correlators = nullptr,
std::function<void(Error)> Warn = nullptr);
/// \param Weight for raw profiles use this as the temporal profile trace
@@ -313,7 +313,8 @@ class RawInstrProfReader : public InstrProfReader {
std::unique_ptr<MemoryBuffer> DataBuffer;
/// If available, this hold the ProfileData array used to correlate raw
/// instrumentation data to their functions.
- const InstrProfCorrelatorImpl<IntPtrT> *Correlator;
+ const InstrProfCorrelators *Correlators;
+ bool IsCorrelatorUsed;
/// A list of timestamps paired with a function name reference.
std::vector<std::pair<uint64_t, uint64_t>> TemporalProfTimestamps;
bool ShouldSwapBytes;
@@ -346,11 +347,9 @@ class RawInstrProfReader : public InstrProfReader {
public:
RawInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer,
- const InstrProfCorrelator *Correlator,
+ const InstrProfCorrelators *Correlator,
std::function<void(Error)> Warn)
- : DataBuffer(std::move(DataBuffer)),
- Correlator(dyn_cast_or_null<const InstrProfCorrelatorImpl<IntPtrT>>(
- Correlator)),
+ : DataBuffer(std::move(DataBuffer)), Correlators((Correlator)),
Warn(Warn) {}
RawInstrProfReader(const RawInstrProfReader &) = delete;
RawInstrProfReader &operator=(const RawInstrProfReader &) = delete;
@@ -434,8 +433,8 @@ class RawInstrProfReader : public InstrProfReader {
bool atEnd() const { return Data == DataEnd; }
void advanceData() {
- // `CountersDelta` is a constant zero when using debug info correlation.
- if (!Correlator) {
+ // `CountersDelta` is a constant zero when using correlation.
+ if (!IsCorrelatorUsed) {
// The initial CountersDelta is the in-memory address difference between
// the data and counts sections:
// start(__llvm_prf_cnts) - start(__llvm_prf_data)
diff --git a/llvm/lib/Object/BuildID.cpp b/llvm/lib/Object/BuildID.cpp
index ef21458060abd6..363d2d379e9aa3 100644
--- a/llvm/lib/Object/BuildID.cpp
+++ b/llvm/lib/Object/BuildID.cpp
@@ -14,6 +14,7 @@
#include "llvm/Object/BuildID.h"
+#include "llvm/Object/COFF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -42,6 +43,21 @@ template <typename ELFT> BuildIDRef getBuildID(const ELFFile<ELFT> &Obj) {
return {};
}
+BuildIDRef getBuildID(const COFFObjectFile *Obj) {
+ for (const debug_directory &D : Obj->debug_directories()) {
+ if (D.AddressOfRawData == 0 || D.Type != COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
+ continue;
+ const codeview::DebugInfo *DebugInfo;
+ StringRef PDBFileName;
+ if (Error E = Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName))
+ consumeError(std::move(E));
+ if (DebugInfo->Signature.CVSignature == OMF::Signature::PDB70)
+ return ArrayRef(DebugInfo->PDB70.Signature,
+ sizeof(DebugInfo->PDB70.Signature));
+ }
+ return {};
+}
+
} // namespace
BuildID llvm::object::parseBuildID(StringRef Str) {
@@ -62,6 +78,8 @@ BuildIDRef llvm::object::getBuildID(const ObjectFile *Obj) {
return ::getBuildID(O->getELFFile());
if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
return ::getBuildID(O->getELFFile());
+ if (auto *O = dyn_cast<COFFObjectFile>(Obj))
+ return ::getBuildID(O);
return std::nullopt;
}
diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
index cf80a58f43bd90..edd38fdcf9c446 100644
--- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp
+++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
@@ -52,6 +52,18 @@ const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash";
const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
+bool InstrProfCorrelator::AtomicWarningCounter::shouldEmitWarning() {
+ return MaxWarnings == 0 ||
+ WarningCount.fetch_add(1, std::memory_order_relaxed) < MaxWarnings;
+}
+
+InstrProfCorrelator::AtomicWarningCounter::~AtomicWarningCounter() {
+ if (MaxWarnings > 0 && WarningCount > MaxWarnings) {
+ WithColor::warning() << format("Suppressed %d additional warnings\n",
+ WarningCount - MaxWarnings);
+ }
+}
+
llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>>
InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
const object::ObjectFile &Obj,
@@ -87,11 +99,14 @@ InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
++C->CountersSectionStart;
C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost;
+ C->BuildID = object::getBuildID(&Obj);
return Expected<std::unique_ptr<Context>>(std::move(C));
}
llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
-InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind) {
+InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter) {
if (FileKind == DEBUG_INFO) {
auto DsymObjectsOrErr =
object::MachOObjectFile::findDsymObjectMembers(Filename);
@@ -110,14 +125,16 @@ InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind) {
if (auto Err = BufferOrErr.takeError())
return std::move(Err);
- return get(std::move(*BufferOrErr), FileKind);
+ return get(std::move(*BufferOrErr), FileKind, CorrelateLock, WarnLock,
+ WarnCounter);
}
if (FileKind == BINARY) {
auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename));
if (auto Err = BufferOrErr.takeError())
return std::move(Err);
- return get(std::move(*BufferOrErr), FileKind);
+ return get(std::move(*BufferOrErr), FileKind, CorrelateLock, WarnLock,
+ WarnCounter);
}
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
@@ -127,7 +144,9 @@ InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind) {
llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer,
- ProfCorrelatorKind FileKind) {
+ ProfCorrelatorKind FileKind, std::mutex &CorrelateLock,
+ std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter) {
auto BinOrErr = object::createBinary(*Buffer);
if (auto Err = BinOrErr.takeError())
return std::move(Err);
@@ -139,36 +158,46 @@ InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer,
auto T = Obj->makeTriple();
if (T.isArch64Bit())
return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj,
- FileKind);
+ FileKind, CorrelateLock,
+ WarnLock, WarnCounter);
if (T.isArch32Bit())
return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj,
- FileKind);
+ FileKind, CorrelateLock,
+ WarnLock, WarnCounter);
}
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile, "not an object file");
}
-std::optional<size_t> InstrProfCorrelator::getDataSize() const {
+size_t InstrProfCorrelator::getDataSize() const {
if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint32_t>>(this)) {
return C->getDataSize();
} else if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint64_t>>(this)) {
return C->getDataSize();
}
- return {};
+ return 0;
+}
+
+bool InstrProfCorrelator::shouldEmitWarning() {
+ return WarnCounter && WarnCounter->shouldEmitWarning();
}
namespace llvm {
template <>
InstrProfCorrelatorImpl<uint32_t>::InstrProfCorrelatorImpl(
- std::unique_ptr<InstrProfCorrelator::Context> Ctx)
- : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit,
- std::move(Ctx)) {}
+ std::unique_ptr<InstrProfCorrelator::Context> Ctx,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter)
+ : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit, std::move(Ctx),
+ CorrelateLock, WarnLock, WarnCounter) {}
template <>
InstrProfCorrelatorImpl<uint64_t>::InstrProfCorrelatorImpl(
- std::unique_ptr<InstrProfCorrelator::Context> Ctx)
- : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit,
- std::move(Ctx)) {}
+ std::unique_ptr<InstrProfCorrelator::Context> Ctx,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter)
+ : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit, std::move(Ctx),
+ CorrelateLock, WarnLock, WarnCounter) {}
template <>
bool InstrProfCorrelatorImpl<uint32_t>::classof(const InstrProfCorrelator *C) {
return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
@@ -184,35 +213,42 @@ template <class IntPtrT>
llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
InstrProfCorrelatorImpl<IntPtrT>::get(
std::unique_ptr<InstrProfCorrelator::Context> Ctx,
- const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) {
+ const object::ObjectFile &Obj, ProfCorrelatorKind FileKind,
+ std::mutex &CorrelateLock, std::mutex &WarnLock,
+ AtomicWarningCounter *WarnCounter) {
if (FileKind == DEBUG_INFO) {
if (Obj.isELF() || Obj.isMachO()) {
auto DICtx = DWARFContext::create(Obj);
return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
- std::move(DICtx), std::move(Ctx));
+ std::move(DICtx), std::move(Ctx), CorrelateLock, WarnLock,
+ WarnCounter);
}
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
"unsupported debug info format (only DWARF is supported)");
}
if (Obj.isELF() || Obj.isCOFF())
- return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx));
+ return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(
+ std::move(Ctx), CorrelateLock, WarnLock, WarnCounter);
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
"unsupported binary format (only ELF and COFF are supported)");
}
template <class IntPtrT>
-Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData(int MaxWarnings) {
- assert(Data.empty() && Names.empty() && NamesVec.empty());
- correlateProfileDataImpl(MaxWarnings);
+Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData() {
+ std::lock_guard<std::mutex> Guard(this->CorrelateLock);
+ if (IsCorrelated)
+ return Error::success();
+ assert(Data.empty() && Names.empty());
+ correlateProfileDataImpl();
if (this->Data.empty())
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
"could not find any profile data metadata in correlated file");
Error Result = correlateProfileNameImpl();
- this->CounterOffsets.clear();
- this->NamesVec.clear();
+ CounterOffsets.clear();
+ IsCorrelated = true;
return Result;
}
@@ -240,10 +276,9 @@ template <> struct yaml::SequenceElementTraits<InstrProfCorrelator::Probe> {
};
template <class IntPtrT>
-Error InstrProfCorrelatorImpl<IntPtrT>::dumpYaml(int MaxWarnings,
- raw_ostream &OS) {
+Error InstrProfCorrelatorImpl<IntPtrT>::dumpYaml(raw_ostream &OS) {
InstrProfCorrelator::CorrelationData Data;
- correlateProfileDataImpl(MaxWarnings, &Data);
+ correlateProfileDataImpl(&Data);
if (Data.Probes.empty())
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
@@ -324,10 +359,7 @@ bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) {
template <class IntPtrT>
void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
- int MaxWarnings, InstrProfCorrelator::CorrelationData *Data) {
- bool UnlimitedWarnings = (MaxWarnings == 0);
- // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
- int NumSuppressedWarnings = -MaxWarnings;
+ InstrProfCorrelator::CorrelationData *Data) {
auto maybeAddProbe = [&](DWARFDie Die) {
if (!isDIEOfProbe(Die))
return;
@@ -364,7 +396,8 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
}
}
if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
- if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+ if (this->shouldEmitWarning()) {
+ std::lock_guard<std::mutex> Guard(this->WarnLock);
WithColor::warning()
<< "Incomplete DIE for function " << FunctionName
<< ": CFGHash=" << CFGHash << " CounterPtr=" << CounterPtr
@@ -376,7 +409,8 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
uint64_t CountersStart = this->Ctx->CountersSectionStart;
uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
- if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+ if (this->shouldEmitWarning()) {
+ std::lock_guard<std::mutex> Guard(this->WarnLock);
WithColor::warning()
<< format("CounterPtr out of range for function %s: Actual=0x%x "
"Expected=[0x%x, 0x%x)\n",
@@ -385,7 +419,8 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
}
return;
}
- if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
+ if (!FunctionPtr && this->shouldEmitWarning()) {
+ std::lock_guard<std::mutex> Guard(this->WarnLock);
WithColor::warning() << format("Could not find address of function %s\n",
*FunctionName);
LLVM_DEBUG(Die.dump(dbgs()));
@@ -411,7 +446,7 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
} else {
this->addDataProbe(IndexedInstrProf::ComputeHash(*FunctionName), *CFGHash,
CounterOffset, FunctionPtr.value_or(0), *NumCounters);
- this->NamesVec.push_back(*FunctionName);
+ NamesVec.push_back(*FunctionName);
}
};
for (auto &CU : DICtx->normal_units())
@@ -420,33 +455,25 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
for (auto &CU : DICtx->dwo_units())
for (const auto &Entry : CU->dies())
maybeAddProbe(DWARFDie(CU.get(), &Entry));
-
- if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
- WithColor::warning() << format("Suppressed %d additional warnings\n",
- NumSuppressedWarnings);
}
template <class IntPtrT>
Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
- if (this->NamesVec.empty()) {
+ if (NamesVec.empty()) {
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
"could not find any profile name metadata in debug info");
}
auto Result =
- collectGlobalObjectNameStrings(this->NamesVec,
+ collectGlobalObjectNameStrings(NamesVec,
/*doCompression=*/false, this->Names);
return Result;
}
template <class IntPtrT>
void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
- int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) {
+ InstrProfCorrelator::CorrelationData *CorrelateData) {
using RawProfData = RawInstrProf::ProfileData<IntPtrT>;
- bool UnlimitedWarnings = (MaxWarnings == 0);
- // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
- int NumSuppressedWarnings = -MaxWarnings;
-
const RawProfData *DataStart = (const RawProfData *)this->Ctx->DataStart;
const RawProfData *DataEnd = (const RawProfData *)this->Ctx->DataEnd;
// We need to use < here because the last data record may have no padding.
@@ -455,7 +482,8 @@ void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
uint64_t CountersStart = this->Ctx->CountersSectionStart;
uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
- if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+ if (this->shouldEmitWarning()) {
+ std::lock_guard<std::mutex> Guard(this->WarnLock);
WithColor::warning()
<< format("CounterPtr out of range for function: Actual=0x%x "
"Expected=[0x%x, 0x%x) at data offset=0x%x\n",
@@ -481,3 +509,49 @@ Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
return Error::success();
}
+
+llvm::Expected<std::unique_ptr<InstrProfCorrelators>> InstrProfCorrelators::get(
+ ArrayRef<std::pair<StringRef, InstrProfCorrelator::ProfCorrelatorKind>>
+ CorrelateInputs,
+ uint32_t MaxWarnings) {
+ StringMap<std::unique_ptr<InstrProfCorrelator>> CorrelatorMap;
+ StringMap<StringRef> FileMap;
+ auto WarnCounter =
+ std::make_unique<InstrProfCorrelator::AtomicWarningCounter>(MaxWarnings);
+ std::unique_ptr<std::mutex> CorrelateLock = std::make_unique<std::mutex>();
+ std::unique_ptr<std::mutex> WarnLock = std::make_unique<std::mutex>();
+ for (const auto &Input : CorrelateInputs) {
+ std::unique_ptr<InstrProfCorrelator> Correlator;
+ if (auto Err = InstrProfCorrelator::get(Input.first, Input.second,
+ *CorrelateLock.get(),
+ *WarnLock.get(), WarnCounter.get())
+ .moveInto(Correlator))
+ return Err;
+ std::string BuildID = toHex(Correlator->getBuildID());
+ FileMap.try_emplace(BuildID, Input.first);
+ bool Inserted =
+ CorrelatorMap.try_emplace(BuildID, std::move(Correlator)).second;
+ if (!Inserted && WarnCounter->shouldEmitWarning()) {
+ std::lock_guard<std::mutex> Guard(*WarnLock);
+ WithColor::warning() << format(
+ "Duplicate build id (%s) found for %s and %s\n", BuildID.c_str(),
+ FileMap[BuildID].str().c_str(), Input.first.str().c_str());
+ }
+ }
+ return std::make_unique<InstrProfCorrelators>(
+ std::move(CorrelatorMap), std::move(CorrelateLock), std::move(WarnLock),
+ std::move(WarnCounter));
+}
+
+llvm::Expected<const InstrProfCorrelator *>
+InstrProfCorrelators::getCorrelator(object::BuildIDRef BuildID) const {
+ std::string BuildIDStr = toHex(BuildID);
+ auto I = CorrelatorMap.find(BuildIDStr);
+ if (I == CorrelatorMap.end())
+ return make_error<InstrProfError>(
+ instrprof_error::unable_to_correlate_profile,
+ "missing correlator file with build id " + BuildIDStr + "\n");
+ if (auto Err = I->getValue()->correlateProfileData())
+ return Err;
+ return I->getValue().get();
+}
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 068922d421f8b9..c135710961cd43 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -155,19 +155,19 @@ printBinaryIdsInternal(raw_ostream &OS,
Expected<std::unique_ptr<InstrProfReader>>
InstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
- const InstrProfCorrelator *Correlator,
+ const InstrProfCorrelators *Correlators,
std::function<void(Error)> Warn) {
// Set up the buffer to read.
auto BufferOrError = setupMemoryBuffer(Path, FS);
if (Error E = BufferOrError.takeError())
return std::move(E);
- return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
+ return InstrProfReader::create(std::move(BufferOrError.get()), Correlators,
Warn);
}
Expected<std::unique_ptr<InstrProfReader>>
InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
- const InstrProfCorrelator *Correlator,
+ const InstrProfCorrelators *Correlators,
std::function<void(Error)> Warn) {
if (Buffer->getBufferSize() == 0)
return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
@@ -177,9 +177,9 @@ InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
if (IndexedInstrProfReader::hasFormat(*Buffer))
Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
else if (RawInstrProfReader64::hasFormat(*Buffer))
- Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator, Warn));
+ Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlators, Warn));
else if (RawInstrProfReader32::hasFormat(*Buffer))
- Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator, Warn));
+ Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlators, Warn));
else if (TextInstrProfReader::hasFormat(*Buffer))
Result.reset(new TextInstrProfReader(std::move(Buffer)));
else
@@ -559,6 +559,7 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
uint64_t BinaryIdSize = swap(Header.BinaryIdsSize);
// Binary id start just after the header if exists.
+ object::BuildIDRef BinaryId;
const uint8_t *BinaryIdStart =
reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
const uint8_t *BinaryIdEnd = BinaryIdStart + BinaryIdSize;
@@ -570,6 +571,7 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
readBinaryIdsInternal(*DataBuffer, BinaryIdSize, BinaryIdStart,
BinaryIds, getDataEndianness()))
return Err;
+ BinaryId = BinaryIds.back();
}
CountersDelta = swap(Header.CountersDelta);
@@ -600,22 +602,28 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
return error(instrprof_error::bad_header);
- if (Correlator) {
+ if (DataSize == 0 && NamesSize == 0 && Correlators && !Correlators->empty()) {
// These sizes in the raw file are zero because we constructed them in the
// Correlator.
- if (!(DataSize == 0 && NamesSize == 0 && CountersDelta == 0 &&
- NamesDelta == 0))
+ if (!(CountersDelta == 0 && NamesDelta == 0))
return error(instrprof_error::unexpected_correlation_info);
- Data = Correlator->getDataPointer();
+ auto CorrelatorOrErr = Correlators->getCorrelator(BinaryId);
+ if (!CorrelatorOrErr)
+ return CorrelatorOrErr.takeError();
+ auto *Correlator = CorrelatorOrErr.get();
+ Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
+ Correlator->getDataPointer());
DataEnd = Data + Correlator->getDataSize();
NamesStart = Correlator->getNamesPointer();
NamesEnd = NamesStart + Correlator->getNamesSize();
+ IsCorrelatorUsed = true;
} else {
Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
Start + DataOffset);
DataEnd = Data + NumData;
NamesStart = Start + NamesOffset;
NamesEnd = NamesStart + NamesSize;
+ IsCorrelatorUsed = false;
}
CountersStart = Start + CountersOffset;
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 322b7da2678f4f..05a7f79bd6d72e 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -118,18 +118,18 @@ cl::opt<std::string> ProfiledBinary(
"profiled-binary", cl::init(""),
cl::desc("Path to binary from which the profile was collected."),
cl::sub(ShowSubcommand), cl::sub(MergeSubcommand));
-cl::opt<std::string> DebugInfoFilename(
- "debug-info", cl::init(""),
+cl::list<std::string> DebugInfoFilenames(
+ "debug-info",
cl::desc(
"For show, read and extract profile metadata from debug info and show "
"the functions it found. For merge, use the provided debug info to "
"correlate the raw profile."),
cl::sub(ShowSubcommand), cl::sub(MergeSubcommand));
-cl::opt<std::string>
- BinaryFilename("binary-file", cl::init(""),
- cl::desc("For merge, use the provided unstripped bianry to "
- "correlate the raw profile."),
- cl::sub(MergeSubcommand));
+cl::list<std::string>
+ BinaryFilenames("binary-file",
+ cl::desc("For merge, use the provided unstripped bianry to "
+ "correlate the raw profile."),
+ cl::sub(MergeSubcommand));
cl::opt<std::string> FuncNameFilter(
"function",
cl::desc("Details for matching functions. For overlapping CSSPGO, this "
@@ -607,7 +607,7 @@ static void overlapInput(const std::string &BaseFilename,
/// Load an input into a writer context.
static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
- const InstrProfCorrelator *Correlator,
+ const InstrProfCorrelators *Correlators,
const StringRef ProfiledBinary, WriterContext *WC) {
std::unique_lock<std::mutex> CtxGuard{WC->Lock};
@@ -675,7 +675,7 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
ReaderWarning = {make_error<InstrProfError>(ErrCode, Msg), Filename};
};
auto ReaderOrErr =
- InstrProfReader::create(Input.Filename, *FS, Correlator, Warn);
+ InstrProfReader::create(Input.Filename, *FS, Correlators, Warn);
if (Error E = ReaderOrErr.takeError()) {
// Skip the empty profiles by returning silently.
auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
@@ -793,28 +793,27 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
OutputFormat != PF_Text)
exitWithError("unknown format is specified");
- // TODO: Maybe we should support correlation with mixture of different
- // correlation modes(w/wo debug-info/object correlation).
- if (!DebugInfoFilename.empty() && !BinaryFilename.empty())
- exitWithError("Expected only one of -debug-info, -binary-file");
- std::string CorrelateFilename;
- ProfCorrelatorKind CorrelateKind = ProfCorrelatorKind::NONE;
- if (!DebugInfoFilename.empty()) {
- CorrelateFilename = DebugInfoFilename;
- CorrelateKind = ProfCorrelatorKind::DEBUG_INFO;
- } else if (!BinaryFilename.empty()) {
- CorrelateFilename = BinaryFilename;
- CorrelateKind = ProfCorrelatorKind::BINARY;
- }
+ std::unique_ptr<InstrProfCorrelators> Correlators;
+ SmallVector<std::pair<StringRef, InstrProfCorrelator::ProfCorrelatorKind>>
+ CorrelateInputs;
- std::unique_ptr<InstrProfCorrelator> Correlator;
- if (CorrelateKind != InstrProfCorrelator::NONE) {
- if (auto Err = InstrProfCorrelator::get(CorrelateFilename, CorrelateKind)
- .moveInto(Correlator))
- exitWithError(std::move(Err), CorrelateFilename);
- if (auto Err = Correlator->correlateProfileData(MaxDbgCorrelationWarnings))
- exitWithError(std::move(Err), CorrelateFilename);
+ for (StringRef Filenames : DebugInfoFilenames) {
+ SmallVector<StringRef, 1> FilenameVec;
+ Filenames.split(FilenameVec, ',');
+ for (StringRef Filename : FilenameVec)
+ CorrelateInputs.push_back({Filename, InstrProfCorrelator::DEBUG_INFO});
}
+ for (StringRef Filenames : BinaryFilenames) {
+ SmallVector<StringRef, 1> FilenameVec;
+ Filenames.split(FilenameVec, ',');
+ for (StringRef Filename : FilenameVec)
+ CorrelateInputs.push_back({Filename, InstrProfCorrelator::BINARY});
+ }
+ if (!CorrelateInputs.empty())
+ if (auto Err = InstrProfCorrelators::get(CorrelateInputs,
+ MaxDbgCorrelationWarnings)
+ .moveInto(Correlators))
+ exitWithError(std::move(Err));
std::mutex ErrorLock;
SmallSet<instrprof_error, 4> WriterErrorCodes;
@@ -833,7 +832,7 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
if (NumThreads == 1) {
for (const auto &Input : Inputs)
- loadInput(Input, Remapper, Correlator.get(), ProfiledBinary,
+ loadInput(Input, Remapper, Correlators.get(), ProfiledBinary,
Contexts[0].get());
} else {
ThreadPool Pool(hardware_concurrency(NumThreads));
@@ -841,7 +840,7 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
// Load the inputs in parallel (N/NumThreads serial steps).
unsigned Ctx = 0;
for (const auto &Input : Inputs) {
- Pool.async(loadInput, Input, Remapper, Correlator.get(), ProfiledBinary,
+ Pool.async(loadInput, Input, Remapper, Correlators.get(), ProfiledBinary,
Contexts[Ctx].get());
Ctx = (Ctx + 1) % NumThreads;
}
@@ -3077,17 +3076,22 @@ static int showDebugInfoCorrelation(const std::string &Filename,
if (SFormat == ShowFormat::Json)
exitWithError("JSON output is not supported for debug info correlation");
std::unique_ptr<InstrProfCorrelator> Correlator;
+ InstrProfCorrelator::AtomicWarningCounter WarnCounter(
+ MaxDbgCorrelationWarnings);
+ std::mutex CorrelateLock;
+ std::mutex WarnLock;
if (auto Err =
- InstrProfCorrelator::get(Filename, InstrProfCorrelator::DEBUG_INFO)
+ InstrProfCorrelator::get(Filename, InstrProfCorrelator::DEBUG_INFO,
+ CorrelateLock, WarnLock, &WarnCounter)
.moveInto(Correlator))
exitWithError(std::move(Err), Filename);
if (SFormat == ShowFormat::Yaml) {
- if (auto Err = Correlator->dumpYaml(MaxDbgCorrelationWarnings, OS))
+ if (auto Err = Correlator->dumpYaml(OS))
exitWithError(std::move(Err), Filename);
return 0;
}
- if (auto Err = Correlator->correlateProfileData(MaxDbgCorrelationWarnings))
+ if (auto Err = Correlator->correlateProfileData())
exitWithError(std::move(Err), Filename);
InstrProfSymtab Symtab;
@@ -3108,10 +3112,10 @@ static int showDebugInfoCorrelation(const std::string &Filename,
}
static int show_main(int argc, const char *argv[]) {
- if (Filename.empty() && DebugInfoFilename.empty())
+ if (Filename.empty() && DebugInfoFilenames.empty())
exitWithError(
"the positional argument '<profdata-file>' is required unless '--" +
- DebugInfoFilename.ArgStr + "' is provided");
+ DebugInfoFilenames.ArgStr + "' is provided");
if (Filename == OutputFilename) {
errs() << sys::path::filename(argv[0]) << " " << argv[1]
@@ -3129,8 +3133,12 @@ static int show_main(int argc, const char *argv[]) {
if (ShowAllFunctions && !FuncNameFilter.empty())
WithColor::warning() << "-function argument ignored: showing all functions\n";
- if (!DebugInfoFilename.empty())
- return showDebugInfoCorrelation(DebugInfoFilename, SFormat, OS);
+ if (!DebugInfoFilenames.empty()) {
+ if (DebugInfoFilenames.size() > 1)
+ exitWithError("'--" + DebugInfoFilenames.ArgStr +
+ "' only accept one argument in show subcommand");
+ return showDebugInfoCorrelation(DebugInfoFilenames[0], SFormat, OS);
+ }
if (ShowProfileKind == instr)
return showInstrProfile(SFormat, OS);
>From 3481cf6ddd3b7a9759c2a7b37cf288cc36e25847 Mon Sep 17 00:00:00 2001
From: Zequan Wu <zequanwu at google.com>
Date: Tue, 19 Dec 2023 12:36:32 -0500
Subject: [PATCH 2/2] fixup! [Profile] Allow profile merging with multiple
correlate files.
---
.../test/profile/Linux/instrprof-debug-info-correlate.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
index 47dbf3c87e68f1..af19101f91a2f1 100644
--- a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
+++ b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
@@ -31,13 +31,13 @@
// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-foo.cpp -c -fpic -shared -Wl,--build-id -o %t-libfoo.so
// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %t-libfoo.so -Wl,--build-id -o %t
// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
-// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t,%t-libfoo.o %t.proflite
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t,%t-libfoo.so %t.proflite
// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
// One binary is built without build id.
// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %t-libfoo.so -o %t
// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
-// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t,%t-libfoo.o %t.proflite
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t,%t-libfoo.so %t.proflite
// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
// Warning about multiple correlate files have the same build id.
More information about the llvm-commits
mailing list