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 new file mode 100644 --- /dev/null +++ b/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c @@ -0,0 +1,16 @@ +// 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: %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 + +void a() {} +void b() {} +int main() { return 0; } + +// CHECK: a +// CHECK: b +// CHECK: main +// CHECK: Counters section size: 0x18 bytes +// CHECK: Found 3 functions diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -529,6 +529,12 @@ /// Return the name section data. inline StringRef getNameData() const { return Data; } + + /// Dump the symbols in this table. + void dumpNames(raw_ostream &OS) const { + for (StringRef S : NameTab.keys()) + OS << S << "\n"; + } }; Error InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) { diff --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h --- a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h +++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h @@ -35,6 +35,20 @@ /// to their functions. virtual Error correlateProfileData() = 0; + /// Return the number of ProfileData elements. + llvm::Optional getDataSize() const; + + /// Return a pointer to the names string that this class constructs. + const char *getNamesPointer() const { return Names.c_str(); } + + /// Return the number of bytes in the names string. + size_t getNamesSize() const { return Names.size(); } + + /// Return the size of the counters section in bytes. + uint64_t getCountersSectionSize() const { + return Ctx->CountersSectionEnd - Ctx->CountersSectionStart; + } + static const char *FunctionNameAttributeName; static const char *CFGHashAttributeName; static const char *NumCountersAttributeName; @@ -59,6 +73,9 @@ InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr Ctx) : Ctx(std::move(Ctx)), Kind(K) {} + std::string Names; + std::vector NamesVec; + private: static llvm::Expected> get(std::unique_ptr Buffer); @@ -83,19 +100,12 @@ /// Return the number of ProfileData elements. size_t getDataSize() const { return Data.size(); } - /// Return a pointer to the names string that this class constructs. - const char *getNamesPointer() const { return Names.c_str(); } - - /// Return the number of bytes in the names string. - size_t getNamesSize() const { return Names.size(); } - static llvm::Expected>> get(std::unique_ptr Ctx, const object::ObjectFile &Obj); protected: std::vector> Data; - std::string Names; Error correlateProfileData() override; virtual void correlateProfileDataImpl() = 0; @@ -107,7 +117,6 @@ InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind, std::unique_ptr Ctx) : InstrProfCorrelator(Kind, std::move(Ctx)){}; - std::vector NamesVec; llvm::DenseSet CounterOffsets; // Byte-swap the value if necessary. diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -88,6 +88,15 @@ instrprof_error::unable_to_correlate_profile, "not an object file"); } +Optional InstrProfCorrelator::getDataSize() const { + if (auto *C = dyn_cast>(this)) { + return C->getDataSize(); + } else if (auto *C = dyn_cast>(this)) { + return C->getDataSize(); + } + return {}; +} + namespace llvm { template <> diff --git a/llvm/test/tools/llvm-profdata/errors.test b/llvm/test/tools/llvm-profdata/errors.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-profdata/errors.test @@ -0,0 +1,8 @@ +RUN: not llvm-profdata show 2>&1 | FileCheck %s --check-prefix SHOW-REQ +SHOW-REQ: the positional argument '' is required unless '--debug-info' is provided + +RUN: not llvm-profdata show file -o file 2>&1 | FileCheck %s --check-prefix SHOW-OUT +SHOW-OUT: Input file name cannot be the same as the output file name! + +RUN: not llvm-profdata 2>&1 | FileCheck %s --check-prefix EMPTY +EMPTY: No command specified! diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -2486,9 +2486,35 @@ return 0; } +static int showDebugInfoCorrelation(const std::string &Filename, + bool ShowDetailedSummary, + bool ShowProfileSymbolList, + raw_fd_ostream &OS) { + std::unique_ptr Correlator; + if (auto Err = InstrProfCorrelator::get(Filename).moveInto(Correlator)) + exitWithError(std::move(Err), Filename); + if (auto Err = Correlator->correlateProfileData()) + exitWithError(std::move(Err), Filename); + + InstrProfSymtab Symtab; + if (auto Err = Symtab.create( + StringRef(Correlator->getNamesPointer(), Correlator->getNamesSize()))) + exitWithError(std::move(Err), Filename); + + if (ShowProfileSymbolList) + Symtab.dumpNames(OS); + // TODO: Read "Profile Data Type" from debug info to compute and show how many + // counters the section holds. + if (ShowDetailedSummary) + OS << "Counters section size: 0x" + << Twine::utohexstr(Correlator->getCountersSectionSize()) << " bytes\n"; + OS << "Found " << Correlator->getDataSize() << " functions\n"; + + return 0; +} + static int show_main(int argc, const char *argv[]) { - cl::opt Filename(cl::Positional, cl::Required, - cl::desc("")); + cl::opt Filename(cl::Positional, cl::desc("")); cl::opt ShowCounts("counts", cl::init(false), cl::desc("Show counter values for shown functions")); @@ -2549,9 +2575,18 @@ "extbinary format")); cl::opt ShowBinaryIds("binary-ids", cl::init(false), cl::desc("Show binary ids in the profile. ")); + cl::opt DebugInfoFilename( + "debug-info", cl::init(""), + cl::desc("Read and extract profile metadata from debug info and show " + "the functions it found.")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); + if (Filename.empty() && DebugInfoFilename.empty()) + exitWithError( + "the positional argument '' is required unless '--" + + DebugInfoFilename.ArgStr + "' is provided"); + if (Filename == OutputFilename) { errs() << sys::path::filename(argv[0]) << ": Input file name cannot be the same as the output file name!\n"; @@ -2566,6 +2601,10 @@ if (ShowAllFunctions && !ShowFunction.empty()) WithColor::warning() << "-function argument ignored: showing all functions\n"; + if (!DebugInfoFilename.empty()) + return showDebugInfoCorrelation(DebugInfoFilename, ShowDetailedSummary, + ShowProfileSymbolList, OS); + if (ProfileKind == instr) return showInstrProfile( Filename, ShowCounts, TopNFunctions, ShowIndirectCallTargets,