diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-profile-mismatch.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-profile-mismatch.ll --- a/llvm/test/Transforms/SampleProfile/pseudo-probe-profile-mismatch.ll +++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-profile-mismatch.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck %s --input-file %t ; RUN: FileCheck %s --input-file %t.ll -check-prefix=CHECK-MD ; RUN: llc < %t.ll -filetype=obj -o %t.obj -; RUN: llvm-objdump --section-headers %t.obj | FileCheck %s --check-prefix=CHECK-OBJ +; RUN: llvm-objdump --llvm-stats %t.obj | FileCheck %s --check-prefix=CHECK-OBJ ; CHECK: (1/3) of functions' profile are invalid and (10/50) of samples are discarded due to function hash mismatch. ; CHECK: (2/3) of callsites' profile are invalid and (20/30) of samples are discarded due to callsite location mismatch. diff --git a/llvm/tools/llvm-objdump/ObjdumpOpts.td b/llvm/tools/llvm-objdump/ObjdumpOpts.td --- a/llvm/tools/llvm-objdump/ObjdumpOpts.td +++ b/llvm/tools/llvm-objdump/ObjdumpOpts.td @@ -214,6 +214,9 @@ def : Flag<["-"], "u">, Alias, HelpText<"Alias for --unwind-info">; +def llvm_stats : Flag<["--"], "llvm-stats">, + HelpText<"Display the content of .llvm_stats section">; + def wide : Flag<["--"], "wide">, HelpText<"Ignored for compatibility with GNU objdump">; def : Flag<["-"], "w">, Alias; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -58,6 +58,7 @@ extern bool SymbolTable; extern std::string TripleName; extern bool UnwindInfo; +extern bool LLVMStats; extern StringSet<> FoundSectionSet; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -68,6 +68,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/Base64.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" @@ -77,6 +78,7 @@ #include "llvm/Support/GraphWriter.h" #include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/StringSaver.h" @@ -225,6 +227,7 @@ static bool DynamicSymbolTable; std::string objdump::TripleName; bool objdump::UnwindInfo; +bool objdump::LLVMStats; static bool Wide; std::string objdump::Prefix; uint32_t objdump::PrefixStrip; @@ -2568,6 +2571,61 @@ "for COFF and MachO object files.\n"; } +static void printLLVMStats(const ObjectFile *O) { + Optional LLVMStatsSec; + + for (const SectionRef &Section : O->sections()) { + Expected SecNameOrErr = Section.getName(); + if (!SecNameOrErr) { + consumeError(SecNameOrErr.takeError()); + continue; + } + if (*SecNameOrErr == ".llvm_stats") + LLVMStatsSec = Section; + } + + outs() << "\nLLVM STATISTICS:\n"; + + if (!LLVMStatsSec) { + reportWarning("no .llvm_stats section in the object file", + O->getFileName()); + return; + } + + StringRef Contents = + unwrapOrError(LLVMStatsSec->getContents(), O->getFileName()); + + uint32_t KeyPadding = 40; + outs() << left_justify("KEY", KeyPadding) << " VALUE\n"; + + const uint8_t *Data = reinterpret_cast(Contents.data()); + const uint8_t *End = Data + Contents.size(); + + auto ReadString = [&]() { + unsigned NumBytesRead = 0; + uint64_t Size = decodeULEB128(Data, &NumBytesRead); + if ((Data + NumBytesRead > End) || (Data + NumBytesRead + Size > End)) { + reportError(O->getFileName(), "Error when decoding .llvm_stats section"); + } + Data += NumBytesRead; + StringRef Str(reinterpret_cast(Data), Size); + Data += Size; + return Str; + }; + + while (Data < End) { + StringRef Key = ReadString(); + StringRef ValInput = ReadString(); + + std::vector ValOutput; + if (auto Err = decodeBase64(ValInput, ValOutput)) + reportError(std::move(Err), O->getFileName()); + std::string Value(ValOutput.begin(), ValOutput.end()); + + outs() << left_justify(Key, KeyPadding) << " " << Value << "\n"; + } +} + /// Dump the raw contents of the __clangast section so the output can be piped /// into llvm-bcanalyzer. static void printRawClangAST(const ObjectFile *Obj) { @@ -2815,6 +2873,8 @@ disassembleObject(O, Relocations); if (UnwindInfo) printUnwindInfo(O); + if (LLVMStats) + printLLVMStats(O); // Mach-O specific options: if (ExportsTrie) @@ -3046,6 +3106,7 @@ DynamicSymbolTable = InputArgs.hasArg(OBJDUMP_dynamic_syms); TripleName = InputArgs.getLastArgValue(OBJDUMP_triple_EQ).str(); UnwindInfo = InputArgs.hasArg(OBJDUMP_unwind_info); + LLVMStats = InputArgs.hasArg(OBJDUMP_llvm_stats); Wide = InputArgs.hasArg(OBJDUMP_wide); Prefix = InputArgs.getLastArgValue(OBJDUMP_prefix).str(); parseIntArg(InputArgs, OBJDUMP_prefix_strip, PrefixStrip); @@ -3214,7 +3275,8 @@ if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null && !DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST && !Relocations && !SectionHeaders && !SectionContents && !SymbolTable && - !DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading && + !DynamicSymbolTable && !UnwindInfo && !LLVMStats && !FaultMapSection && + !Offloading && !(MachOOpt && (Bind || DataInCode || ChainedFixups || DyldInfo || DylibId || DylibsUsed || ExportsTrie || FirstPrivateHeader ||