From 70fb7bb561db39e648d1732c60190c8c09c5b1c5 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Fri, 7 Oct 2022 09:27:40 -0700 Subject: [PATCH] [InstrProf][llvm-profdata] Dump profile correlation data as YAML Change the behavior of the `llvm-profdata show --debug-info=` command to dump a YAML file when using debug info correlation since it provides more information in a parseable format. Reviewed By: yozhu, phosek Differential Revision: https://reviews.llvm.org/D134770 --- .../Linux/instrprof-show-debug-info-correlation.c | 31 ++++++++++- .../include/llvm/ProfileData/InstrProfCorrelator.h | 32 ++++++++++- llvm/lib/ProfileData/InstrProfCorrelator.cpp | 65 ++++++++++++++++++++-- llvm/tools/llvm-profdata/llvm-profdata.cpp | 7 ++- 4 files changed, 122 insertions(+), 13 deletions(-) diff --git a/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c b/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c index d0ab3ac..a7ea54f 100644 --- a/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c +++ b/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c @@ -1,16 +1,41 @@ // RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %s // RUN: llvm-profdata show --debug-info=%t --detailed-summary --show-prof-sym-list | FileCheck %s +// RUN: llvm-profdata show --debug-info=%t --output-format=yaml | FileCheck %s --match-full-lines --check-prefix YAML // RUN: %clang_pgogen -o %t.no.dbg -mllvm --debug-info-correlate -mllvm --disable-vp=true %s // RUN: not llvm-profdata show --debug-info=%t.no.dbg 2>&1 | FileCheck %s --check-prefix NO-DBG // NO-DBG: unable to correlate profile: could not find any profile metadata in debug info +// CHECK: a +// YAML: Probes: +// YAML: - Function Name: a +// YAML: Linkage Name: a +// YAML: CFG Hash: 0x[[#%.1X,HASH:]] +// YAML: Counter Offset: 0x0 +// YAML: Num Counters: 1 +// YAML: File: [[FILE:'.*']] +// YAML: Line: [[@LINE+1]] void a() {} -void b() {} -int main() { return 0; } -// CHECK: a // CHECK: b +// YAML: - Function Name: b +// YAML: Linkage Name: b +// YAML: CFG Hash: 0x[[#%.1X,HASH:]] +// YAML: Counter Offset: 0x8 +// YAML: Num Counters: 1 +// YAML: File: [[FILE:'.*']] +// YAML: Line: [[@LINE+1]] +void b() {} + // CHECK: main +// YAML: - Function Name: main +// YAML: Linkage Name: main +// YAML: CFG Hash: 0x[[#%.1X,HASH:]] +// YAML: Counter Offset: 0x10 +// YAML: Num Counters: 1 +// YAML: File: [[FILE]] +// YAML: Line: [[@LINE+1]] +int main() { return 0; } + // CHECK: Counters section size: 0x18 bytes // CHECK: Found 3 functions diff --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h index 79995c8..0efd4ea 100644 --- a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h +++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h @@ -16,6 +16,7 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/YAMLTraits.h" #include namespace llvm { @@ -36,6 +37,9 @@ public: /// to their functions. virtual Error correlateProfileData() = 0; + /// Process debug info and dump the correlation data. + virtual Error dumpYaml(raw_ostream &OS) = 0; + /// Return the number of ProfileData elements. llvm::Optional getDataSize() const; @@ -69,7 +73,7 @@ protected: /// True if target and host have different endian orders. bool ShouldSwapBytes; }; - const std::unique_ptr Ctx; + const std::unique_ptr Ctx; InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr Ctx) : Ctx(std::move(Ctx)), Kind(K) {} @@ -77,6 +81,24 @@ protected: std::string Names; std::vector NamesVec; + struct Probe { + std::string FunctionName; + Optional LinkageName; + yaml::Hex64 CFGHash; + yaml::Hex64 CounterOffset; + uint32_t NumCounters; + Optional FilePath; + Optional LineNumber; + }; + + struct CorrelationData { + std::vector Probes; + }; + + friend struct yaml::MappingTraits; + friend struct yaml::SequenceElementTraits; + friend struct yaml::MappingTraits; + private: static llvm::Expected> get(std::unique_ptr Buffer); @@ -109,7 +131,10 @@ protected: std::vector> Data; Error correlateProfileData() override; - virtual void correlateProfileDataImpl() = 0; + virtual void correlateProfileDataImpl( + InstrProfCorrelator::CorrelationData *Data = nullptr) = 0; + + Error dumpYaml(raw_ostream &OS) override; void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset, IntPtrT FunctionPtr, uint32_t NumCounters); @@ -171,7 +196,8 @@ private: /// NULL /// NULL /// \endcode - void correlateProfileDataImpl() override; + void correlateProfileDataImpl( + InstrProfCorrelator::CorrelationData *Data = nullptr) override; }; } // end namespace llvm diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp index 4b8212c..6c460a5 100644 --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -155,6 +155,42 @@ Error InstrProfCorrelatorImpl::correlateProfileData() { return Result; } +template <> struct yaml::MappingTraits { + static void mapping(yaml::IO &io, + InstrProfCorrelator::CorrelationData &Data) { + io.mapRequired("Probes", Data.Probes); + } +}; + +template <> struct yaml::MappingTraits { + static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P) { + io.mapRequired("Function Name", P.FunctionName); + io.mapOptional("Linkage Name", P.LinkageName); + io.mapRequired("CFG Hash", P.CFGHash); + io.mapRequired("Counter Offset", P.CounterOffset); + io.mapRequired("Num Counters", P.NumCounters); + io.mapOptional("File", P.FilePath); + io.mapOptional("Line", P.LineNumber); + } +}; + +template <> struct yaml::SequenceElementTraits { + static const bool flow = false; +}; + +template +Error InstrProfCorrelatorImpl::dumpYaml(raw_ostream &OS) { + InstrProfCorrelator::CorrelationData Data; + correlateProfileDataImpl(&Data); + if (Data.Probes.empty()) + return make_error( + instrprof_error::unable_to_correlate_profile, + "could not find any profile metadata in debug info"); + yaml::Output YamlOS(OS); + YamlOS << Data; + return Error::success(); +} + template void InstrProfCorrelatorImpl::addProbe(StringRef FunctionName, uint64_t CFGHash, @@ -222,15 +258,16 @@ bool DwarfInstrProfCorrelator::isDIEOfProbe(const DWARFDie &Die) { } template -void DwarfInstrProfCorrelator::correlateProfileDataImpl() { +void DwarfInstrProfCorrelator::correlateProfileDataImpl( + InstrProfCorrelator::CorrelationData *Data) { auto maybeAddProbe = [&](DWARFDie Die) { if (!isDIEOfProbe(Die)) return; Optional FunctionName; Optional CFGHash; Optional CounterPtr = getLocation(Die); - auto FunctionPtr = - dwarf::toAddress(Die.getParent().find(dwarf::DW_AT_low_pc)); + auto FnDie = Die.getParent(); + auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc)); Optional NumCounters; for (const DWARFDie &Child : Die.children()) { if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation) @@ -283,8 +320,26 @@ void DwarfInstrProfCorrelator::correlateProfileDataImpl() { << "\n"); LLVM_DEBUG(Die.dump(dbgs())); } - this->addProbe(*FunctionName, *CFGHash, *CounterPtr - CountersStart, - FunctionPtr.value_or(0), *NumCounters); + IntPtrT CounterOffset = *CounterPtr - CountersStart; + if (Data) { + InstrProfCorrelator::Probe P; + P.FunctionName = *FunctionName; + if (auto Name = FnDie.getName(DINameKind::LinkageName)) + P.LinkageName = Name; + P.CFGHash = *CFGHash; + P.CounterOffset = CounterOffset; + P.NumCounters = *NumCounters; + auto FilePath = FnDie.getDeclFile( + DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath); + if (!FilePath.empty()) + P.FilePath = FilePath; + if (auto LineNumber = FnDie.getDeclLine()) + P.LineNumber = LineNumber; + Data->Probes.push_back(P); + } else { + this->addProbe(*FunctionName, *CFGHash, CounterOffset, + FunctionPtr.value_or(0), *NumCounters); + } }; for (auto &CU : DICtx->normal_units()) for (const auto &Entry : CU->dies()) diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 3fe91f4..95019c9 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -2703,11 +2703,14 @@ static int showDebugInfoCorrelation(const std::string &Filename, OutputFormat OFormat, raw_fd_ostream &OS) { if (OFormat == OutputFormat::Json) exitWithError("JSON output is not supported for debug info correlation"); - if (OFormat == OutputFormat::Yaml) - exitWithError("YAML output is not supported for debug info correlation"); std::unique_ptr Correlator; if (auto Err = InstrProfCorrelator::get(Filename).moveInto(Correlator)) exitWithError(std::move(Err), Filename); + if (OFormat == OutputFormat::Yaml) { + if (auto Err = Correlator->dumpYaml(OS)) + exitWithError(std::move(Err), Filename); + return 0; + } if (auto Err = Correlator->correlateProfileData()) exitWithError(std::move(Err), Filename); -- 2.7.4