https://github.com/ZequanWu updated https://github.com/llvm/llvm-project/pull/75957
>From d72f0e1ad7759bad81767418604d27f11d74d6de Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Tue, 19 Dec 2023 12:32:15 -0500 Subject: [PATCH 1/4] [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 <zequa...@google.com> Date: Tue, 19 Dec 2023 12:36:32 -0500 Subject: [PATCH 2/4] 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. >From 5f90bc2f97df90766483657cfc7634cffc67caeb Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Wed, 20 Dec 2023 13:20:10 -0500 Subject: [PATCH 3/4] add windows binary id test and clean up. --- .../Linux/instrprof-correlation-mixed.test | 5 +- .../Linux/instrprof-debug-info-correlate.c | 62 +++++++++++-------- .../Windows/instrprof-binary-correlate.c | 41 ++++++++++++ .../test/profile/instrprof-binary-correlate.c | 2 - llvm/lib/ProfileData/InstrProfCorrelator.cpp | 2 +- llvm/lib/ProfileData/InstrProfReader.cpp | 6 +- 6 files changed, 85 insertions(+), 33 deletions(-) create mode 100644 compiler-rt/test/profile/Windows/instrprof-binary-correlate.c diff --git a/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test b/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test index 8cc4611eec4f0b..60f167dee4a49c 100644 --- a/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test +++ b/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test @@ -7,8 +7,9 @@ // 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 -g -mllvm -profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp -c -o %t-main.debug.o +// RUN: %clang_pgogen -o %t -mllvm -profile-correlate=binary -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-foo.cpp -c -o %t-foo.binary.o +// RUN: %clang_pgogen -o %t -g -mllvm -profile-correlate=debug-info -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. 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 af19101f91a2f1..fa2ab6fb2cd27d 100644 --- a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c +++ b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c @@ -7,13 +7,16 @@ // RUN: env LLVM_PROFILE_FILE=%t.d4.proflite %run %t.d4 // RUN: llvm-profdata merge -o %t.d4.profdata --debug-info=%t.d4 %t.d4.proflite -// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.d4.profdata) +// RUN: llvm-profdata show --all-functions --counts %t.normal.profdata > %t.normal.profdata.show +// RUN: llvm-profdata show --all-functions --counts %t.d4.profdata > %t.d4.profdata.show +// RUN: diff %t.normal.profdata.show %t.d4.profdata.show // RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -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.proflite %run %t // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite -// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata) +// RUN: llvm-profdata show --all-functions --counts %t.profdata > %t.profdata.show +// RUN: diff %t.normal.profdata.show %t.profdata.show // RUN: %clang_pgogen -o %t.cov -g -mllvm --debug-info-correlate -mllvm -pgo-function-entry-coverage -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.cov.proflite %run %t.cov @@ -23,43 +26,50 @@ // RUN: env LLVM_PROFILE_FILE=%t.cov.profraw %run %t.cov.normal // RUN: llvm-profdata merge -o %t.cov.normal.profdata %t.cov.profraw -// 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.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.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. -// 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 {{.*}} +// RUN: llvm-profdata show --all-functions --counts %t.cov.normal.profdata > %t.cov.normal.profdata.show +// RUN: llvm-profdata show --all-functions --counts %t.cov.profdata > %t.cov.profdata.show +// RUN: diff %t.cov.normal.profdata.show %t.cov.profdata.show // Test debug info correlate with online merging. // RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal // RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal -// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw +// RUN: llvm-profdata merge -o %t.merged.normal.profdata %t-1.profraw %t-2.profraw // RUN: rm -rf %t.profdir && mkdir %t.profdir // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t -// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.profdir/ +// RUN: llvm-profdata merge -o %t.merged.profdata --debug-info=%t %t.profdir/ -// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata) +// RUN: llvm-profdata show --all-functions --counts %t.merged.normal.profdata > %t.merged.normal.profdata.show +// RUN: llvm-profdata show --all-functions --counts %t.merged.profdata > %t.merged.profdata.show +// RUN: diff %t.merged.normal.profdata.show %t.merged.profdata.show // RUN: rm -rf %t.profdir && mkdir %t.profdir // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.cov.proflite %run %t.cov // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.cov.proflite %run %t.cov // RUN: llvm-profdata merge -o %t.cov.profdata --debug-info=%t.cov %t.profdir/ -// RUN: diff <(llvm-profdata show --all-functions --counts %t.cov.normal.profdata) <(llvm-profdata show --all-functions --counts %t.cov.profdata) +// RUN: llvm-profdata show --all-functions --counts %t.cov.profdata > %t.cov.profdata.show +// RUN: diff %t.cov.normal.profdata.show %t.cov.profdata.show + +// 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 -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.so %t.proflite +// RUN: llvm-profdata show --all-functions --counts %t.profdata > %t.profdata.show +// RUN: diff %t.normal.profdata.show %t.profdata.show + +// 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.so %t.proflite +// RUN: llvm-profdata show --all-functions --counts %t.profdata > %t.profdata.show +// RUN: diff %t.normal.profdata.show %t.profdata.show + +// Warning about multiple correlate files have the same build id. +// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t,%t,%t-libfoo.so %t.proflite 2>&1 >/dev/null | FileCheck %s --check-prefix=WARN +// WARN: Duplicate build id ("") found for {{.*}} and {{.*}} diff --git a/compiler-rt/test/profile/Windows/instrprof-binary-correlate.c b/compiler-rt/test/profile/Windows/instrprof-binary-correlate.c new file mode 100644 index 00000000000000..f01fa2b85ee1f3 --- /dev/null +++ b/compiler-rt/test/profile/Windows/instrprof-binary-correlate.c @@ -0,0 +1,41 @@ +// REQUIRES: target={{.*windows-msvc.*}} +// REQUIRES: lld-available + +// Test binary correlate with build id. + +// Three binaries are built with build id. +// RUN: rm -rf %t.dir && split-file %s %t.dir +// RUN: %clang_profgen %t.dir/main.c %t.dir/foo.c %t.dir/bar.c -o %t.dir/main.exe +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.dir/main.exe +// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw +// RUN: llvm-profdata show --all-functions --counts %t.normal.profdata > %t.normal.profdata.show + +// RUN: %clang_profgen -mllvm -profile-correlate=binary %t.dir/foo.c -fuse-ld=lld -Wl,-build-id -Wl,-dll -o %t.dir/foo.dll +// RUN: %clang_profgen -mllvm -profile-correlate=binary %t.dir/bar.c -fuse-ld=lld -Wl,-build-id -Wl,-dll -o %t.dir/bar.dll +// RUN: %clang_profgen -mllvm -profile-correlate=binary %t.dir/main.c -fuse-ld=lld -Wl,-build-id %t.dir/foo.lib %t.dir/bar.lib -o %t.dir/main.exe +// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t.dir/main.exe +// RUN: llvm-profdata merge -o %t.profdata %t.proflite --binary-file=%t.dir/foo.dll,%t.dir/bar.dll,%t.dir/main.exe +// RUN: llvm-profdata show --all-functions --counts %t.profdata > %t.profdata.show +// RUN: diff %t.normal.profdata.show %t.profdata.show + +// One binary is built without build id. +// RUN: %clang_profgen -mllvm -profile-correlate=binary %t.dir/main.c -fuse-ld=lld %t.dir/foo.lib %t.dir/bar.lib -o %t.dir/main.exe +// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t.dir/main.exe +// RUN: llvm-profdata merge -o %t.profdata %t.proflite --binary-file=%t.dir/foo.dll,%t.dir/bar.dll,%t.dir/main.exe +// RUN: llvm-profdata show --all-functions --counts %t.profdata > %t.profdata.show +// RUN: diff %t.normal.profdata.show %t.profdata.show + +//--- foo.c +__declspec(dllexport) void foo() {} + +//--- bar.c +__declspec(dllexport) void bar() {} + +//--- main.c +__declspec(dllimport) void foo(); +__declspec(dllimport) void bar(); +int main() { + foo(); + bar(); + return 0; +} diff --git a/compiler-rt/test/profile/instrprof-binary-correlate.c b/compiler-rt/test/profile/instrprof-binary-correlate.c index 0e96745a9b58f4..2e9b636cb712a2 100644 --- a/compiler-rt/test/profile/instrprof-binary-correlate.c +++ b/compiler-rt/test/profile/instrprof-binary-correlate.c @@ -47,5 +47,3 @@ // RUN: diff %t.normal.merged.profdata.show %t-4.profdata.show // RUN: diff %t.normal.merged.report %t-4.report // RUN: diff %t.normal.merged.show %t-4.show - -// TODO: After adding support for binary ID, test binaries with different binary IDs. diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp index edd38fdcf9c446..ff2488654b70a0 100644 --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -534,7 +534,7 @@ llvm::Expected<std::unique_ptr<InstrProfCorrelators>> InstrProfCorrelators::get( 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(), + "Duplicate build id (\"%s\") found for %s and %s\n", BuildID.c_str(), FileMap[BuildID].str().c_str(), Input.first.str().c_str()); } } diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp index ba3f8696a3fd45..8f7e694eba9691 100644 --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -177,9 +177,11 @@ 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), Correlators, Warn)); + Result.reset( + new RawInstrProfReader64(std::move(Buffer), Correlators, Warn)); else if (RawInstrProfReader32::hasFormat(*Buffer)) - Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlators, Warn)); + Result.reset( + new RawInstrProfReader32(std::move(Buffer), Correlators, Warn)); else if (TextInstrProfReader::hasFormat(*Buffer)) Result.reset(new TextInstrProfReader(std::move(Buffer))); else >From eab927ccc77288509318260dafb8ba7c0a877961 Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Wed, 20 Dec 2023 15:34:25 -0500 Subject: [PATCH 4/4] Address comments --- .../Linux/instrprof-correlation-mixed.test | 5 +- .../llvm/ProfileData/InstrProfCorrelator.h | 66 ++++++---------- llvm/lib/ProfileData/InstrProfCorrelator.cpp | 75 +++++++------------ llvm/tools/llvm-profdata/llvm-profdata.cpp | 11 +-- 4 files changed, 56 insertions(+), 101 deletions(-) diff --git a/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test b/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test index 60f167dee4a49c..318930cbb80b6b 100644 --- a/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test +++ b/compiler-rt/test/profile/Linux/instrprof-correlation-mixed.test @@ -1,11 +1,10 @@ -// 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. +// Compiling with different 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 -profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp -c -o %t-main.debug.o // RUN: %clang_pgogen -o %t -mllvm -profile-correlate=binary -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-foo.cpp -c -o %t-foo.binary.o @@ -25,7 +24,7 @@ // 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. +// 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 correlation 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 diff --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h index 1b579e0ac2fd24..7670f1809125a6 100644 --- a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h +++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h @@ -36,21 +36,20 @@ class InstrProfCorrelator { /// correlate. enum ProfCorrelatorKind { NONE, DEBUG_INFO, BINARY }; - struct AtomicWarningCounter { - AtomicWarningCounter(uint64_t MaxWarnings) + struct WarningCounter { + WarningCounter(uint64_t MaxWarnings) : MaxWarnings(MaxWarnings), WarningCount(0){}; bool shouldEmitWarning(); - ~AtomicWarningCounter(); + ~WarningCounter(); private: const uint64_t MaxWarnings; - std::atomic<uint64_t> WarningCount; + uint64_t WarningCount; }; static llvm::Expected<std::unique_ptr<InstrProfCorrelator>> get(StringRef Filename, ProfCorrelatorKind FileKind, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter); + WarningCounter *WarnCounter); /// Construct a ProfileData vector used to correlate raw instrumentation data /// to their functions. @@ -107,16 +106,13 @@ class InstrProfCorrelator { const std::unique_ptr<Context> Ctx; 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) {} + WarningCounter *WarnCounter) + : Ctx(std::move(Ctx)), IsCorrelated(false), WarnCounter(WarnCounter), + Kind(K) {} std::string Names; /// True if correlation is already done. bool IsCorrelated; - std::mutex &CorrelateLock; - std::mutex &WarnLock; bool shouldEmitWarning(); @@ -141,10 +137,9 @@ class InstrProfCorrelator { private: static llvm::Expected<std::unique_ptr<InstrProfCorrelator>> get(std::unique_ptr<MemoryBuffer> Buffer, ProfCorrelatorKind FileKind, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter); + WarningCounter *WarnCounter); - AtomicWarningCounter *WarnCounter; + WarningCounter *WarnCounter; const InstrProfCorrelatorKind Kind; }; @@ -154,8 +149,7 @@ template <class IntPtrT> class InstrProfCorrelatorImpl : public InstrProfCorrelator { public: InstrProfCorrelatorImpl(std::unique_ptr<InstrProfCorrelator::Context> Ctx, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter); + WarningCounter *WarnCounter); static bool classof(const InstrProfCorrelator *C); /// Return a pointer to the underlying ProfileData vector that this class @@ -170,8 +164,7 @@ 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, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter); + WarningCounter *WarnCounter); protected: std::vector<RawInstrProf::ProfileData<IntPtrT>> Data; @@ -196,10 +189,8 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator { private: InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind, std::unique_ptr<InstrProfCorrelator::Context> Ctx, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter) - : InstrProfCorrelator(Kind, std::move(Ctx), CorrelateLock, WarnLock, - WarnCounter){}; + WarningCounter *WarnCounter) + : InstrProfCorrelator(Kind, std::move(Ctx), WarnCounter){}; llvm::DenseSet<IntPtrT> CounterOffsets; }; @@ -208,13 +199,10 @@ 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, - std::mutex &CorrelateLock, std::mutex &WarnLock, - InstrProfCorrelator::AtomicWarningCounter *WarnCounter) - : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx), CorrelateLock, - WarnLock, WarnCounter), + DwarfInstrProfCorrelator(std::unique_ptr<DWARFContext> DICtx, + std::unique_ptr<InstrProfCorrelator::Context> Ctx, + InstrProfCorrelator::WarningCounter *WarnCounter) + : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx), WarnCounter), DICtx(std::move(DICtx)) {} private: @@ -266,12 +254,9 @@ class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> { template <class IntPtrT> class BinaryInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> { public: - BinaryInstrProfCorrelator( - std::unique_ptr<InstrProfCorrelator::Context> Ctx, - std::mutex &CorrelateLock, std::mutex &WarnLock, - InstrProfCorrelator::AtomicWarningCounter *WarnCounter) - : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx), CorrelateLock, - WarnLock, WarnCounter) {} + BinaryInstrProfCorrelator(std::unique_ptr<InstrProfCorrelator::Context> Ctx, + InstrProfCorrelator::WarningCounter *WarnCounter) + : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx), WarnCounter) {} /// Return a pointer to the names string that this class constructs. const char *getNamesPointer() const { return this->Ctx.NameStart; } @@ -297,11 +282,8 @@ class InstrProfCorrelators { 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) + std::unique_ptr<InstrProfCorrelator::WarningCounter> WarnCounter) : CorrelatorMap(std::move(CorrelatorMap)), - CorrelateLock(std::move(CorrelateLock)), WarnLock(std::move(WarnLock)), WarnCounter(std::move(WarnCounter)) {} llvm::Expected<const InstrProfCorrelator *> @@ -313,9 +295,7 @@ class InstrProfCorrelators { 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; + std::unique_ptr<InstrProfCorrelator::WarningCounter> WarnCounter; }; } // end namespace llvm diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp index ff2488654b70a0..0c6025524a81a8 100644 --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -52,12 +52,11 @@ 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; +bool InstrProfCorrelator::WarningCounter::shouldEmitWarning() { + return MaxWarnings == 0 || WarningCount++ < MaxWarnings; } -InstrProfCorrelator::AtomicWarningCounter::~AtomicWarningCounter() { +InstrProfCorrelator::WarningCounter::~WarningCounter() { if (MaxWarnings > 0 && WarningCount > MaxWarnings) { WithColor::warning() << format("Suppressed %d additional warnings\n", WarningCount - MaxWarnings); @@ -105,8 +104,7 @@ InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer, llvm::Expected<std::unique_ptr<InstrProfCorrelator>> InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter) { + WarningCounter *WarnCounter) { if (FileKind == DEBUG_INFO) { auto DsymObjectsOrErr = object::MachOObjectFile::findDsymObjectMembers(Filename); @@ -125,16 +123,14 @@ InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind, if (auto Err = BufferOrErr.takeError()) return std::move(Err); - return get(std::move(*BufferOrErr), FileKind, CorrelateLock, WarnLock, - WarnCounter); + return get(std::move(*BufferOrErr), FileKind, 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, CorrelateLock, WarnLock, - WarnCounter); + return get(std::move(*BufferOrErr), FileKind, WarnCounter); } return make_error<InstrProfError>( instrprof_error::unable_to_correlate_profile, @@ -144,9 +140,8 @@ InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind, llvm::Expected<std::unique_ptr<InstrProfCorrelator>> InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer, - ProfCorrelatorKind FileKind, std::mutex &CorrelateLock, - std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter) { + ProfCorrelatorKind FileKind, + WarningCounter *WarnCounter) { auto BinOrErr = object::createBinary(*Buffer); if (auto Err = BinOrErr.takeError()) return std::move(Err); @@ -158,12 +153,10 @@ InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer, auto T = Obj->makeTriple(); if (T.isArch64Bit()) return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj, - FileKind, CorrelateLock, - WarnLock, WarnCounter); + FileKind, WarnCounter); if (T.isArch32Bit()) return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj, - FileKind, CorrelateLock, - WarnLock, WarnCounter); + FileKind, WarnCounter); } return make_error<InstrProfError>( instrprof_error::unable_to_correlate_profile, "not an object file"); @@ -187,17 +180,15 @@ namespace llvm { template <> InstrProfCorrelatorImpl<uint32_t>::InstrProfCorrelatorImpl( std::unique_ptr<InstrProfCorrelator::Context> Ctx, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter) + WarningCounter *WarnCounter) : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit, std::move(Ctx), - CorrelateLock, WarnLock, WarnCounter) {} + WarnCounter) {} template <> InstrProfCorrelatorImpl<uint64_t>::InstrProfCorrelatorImpl( std::unique_ptr<InstrProfCorrelator::Context> Ctx, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter) + WarningCounter *WarnCounter) : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit, std::move(Ctx), - CorrelateLock, WarnLock, WarnCounter) {} + WarnCounter) {} template <> bool InstrProfCorrelatorImpl<uint32_t>::classof(const InstrProfCorrelator *C) { return C->getKind() == InstrProfCorrelatorKind::CK_32Bit; @@ -214,22 +205,20 @@ llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>> InstrProfCorrelatorImpl<IntPtrT>::get( std::unique_ptr<InstrProfCorrelator::Context> Ctx, const object::ObjectFile &Obj, ProfCorrelatorKind FileKind, - std::mutex &CorrelateLock, std::mutex &WarnLock, - AtomicWarningCounter *WarnCounter) { + WarningCounter *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), CorrelateLock, WarnLock, - WarnCounter); + std::move(DICtx), std::move(Ctx), 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), CorrelateLock, WarnLock, WarnCounter); + return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx), + WarnCounter); return make_error<InstrProfError>( instrprof_error::unable_to_correlate_profile, "unsupported binary format (only ELF and COFF are supported)"); @@ -237,7 +226,6 @@ InstrProfCorrelatorImpl<IntPtrT>::get( template <class IntPtrT> Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData() { - std::lock_guard<std::mutex> Guard(this->CorrelateLock); if (IsCorrelated) return Error::success(); assert(Data.empty() && Names.empty()); @@ -397,7 +385,6 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( } if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) { if (this->shouldEmitWarning()) { - std::lock_guard<std::mutex> Guard(this->WarnLock); WithColor::warning() << "Incomplete DIE for function " << FunctionName << ": CFGHash=" << CFGHash << " CounterPtr=" << CounterPtr @@ -410,7 +397,6 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( uint64_t CountersEnd = this->Ctx->CountersSectionEnd; if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) { 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", @@ -420,7 +406,6 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( return; } 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())); @@ -483,7 +468,6 @@ void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( uint64_t CountersEnd = this->Ctx->CountersSectionEnd; if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) { 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", @@ -517,30 +501,27 @@ llvm::Expected<std::unique_ptr<InstrProfCorrelators>> InstrProfCorrelators::get( 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>(); + std::make_unique<InstrProfCorrelator::WarningCounter>(MaxWarnings); 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()) + 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; + bool Inserted = FileMap.try_emplace(BuildID, Input.first).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()); + continue; } + if (auto Err = Correlator->correlateProfileData()) + return Err; + CorrelatorMap.try_emplace(BuildID, std::move(Correlator)); } - return std::make_unique<InstrProfCorrelators>( - std::move(CorrelatorMap), std::move(CorrelateLock), std::move(WarnLock), - std::move(WarnCounter)); + return std::make_unique<InstrProfCorrelators>(std::move(CorrelatorMap), + std::move(WarnCounter)); } llvm::Expected<const InstrProfCorrelator *> @@ -551,7 +532,5 @@ InstrProfCorrelators::getCorrelator(object::BuildIDRef BuildID) const { 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/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 05a7f79bd6d72e..1a9dc07b070614 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -3076,14 +3076,11 @@ 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( + InstrProfCorrelator::WarningCounter WarnCounter( MaxDbgCorrelationWarnings); - std::mutex CorrelateLock; - std::mutex WarnLock; - if (auto Err = - InstrProfCorrelator::get(Filename, InstrProfCorrelator::DEBUG_INFO, - CorrelateLock, WarnLock, &WarnCounter) - .moveInto(Correlator)) + if (auto Err = InstrProfCorrelator::get( + Filename, InstrProfCorrelator::DEBUG_INFO, &WarnCounter) + .moveInto(Correlator)) exitWithError(std::move(Err), Filename); if (SFormat == ShowFormat::Yaml) { if (auto Err = Correlator->dumpYaml(OS)) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits