Index: docs/CommandGuide/llvm-profdata.rst =================================================================== --- docs/CommandGuide/llvm-profdata.rst +++ docs/CommandGuide/llvm-profdata.rst @@ -51,7 +51,17 @@ .. option:: -instr (default) - Specify that the input profile is an instrumentation-based profile. + Specify that the input profile is an instrumentation-based profile. When + using instrumentation-based profiles, the format of the generated file + can be generated in one of the two ways: + + .. option:: -binary (default) + + Emit the profile using a binary encoding in indexed profile format. + + .. option:: -text + + Emit the profile in text format. .. option:: -sample @@ -119,7 +129,12 @@ .. option:: -instr (default) - Specify that the input profile is an instrumentation-based profile. + Specify that the input profile is an instrumentation-based profile. When + instrumentation-based profile is specified, the profile counters can be + dumped in more human readable form with annotations or dumped in text + profile format. To enable dumping in text-profile format, use + +.. option:: -text-format .. option:: -sample Index: include/llvm/ProfileData/InstrProfWriter.h =================================================================== --- include/llvm/ProfileData/InstrProfWriter.h +++ include/llvm/ProfileData/InstrProfWriter.h @@ -43,6 +43,11 @@ std::error_code addRecord(InstrProfRecord &&I); /// Write the profile to \c OS void write(raw_fd_ostream &OS); + /// Write the profile in text format to \c OS + void writeText(raw_fd_ostream &OS); + /// Write \c Record in text format to \c OS + static void writeRecordInText(const InstrProfRecord &Record, + raw_fd_ostream &OS); /// Write the profile, returning the raw data. For testing. std::unique_ptr writeBuffer(); Index: lib/ProfileData/InstrProfWriter.cpp =================================================================== --- lib/ProfileData/InstrProfWriter.cpp +++ lib/ProfileData/InstrProfWriter.cpp @@ -171,6 +171,21 @@ endian::Writer(OS).write(TableStart.second); } +void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func, + raw_fd_ostream &OS) { + OS << Func.Name << "\n" << Func.Hash << "\n" << Func.Counts.size() << "\n"; + for (size_t I = 0, E = Func.Counts.size(); I < E; ++I) + OS << Func.Counts[I] << "\n"; + + OS << "\n"; +} + +void InstrProfWriter::writeText(raw_fd_ostream &OS) { + for (const auto &I : FunctionData) + for (const auto &Func : I.getValue()) + writeRecordInText(Func.second, OS); +} + std::unique_ptr InstrProfWriter::writeBuffer() { std::string Data; llvm::raw_string_ostream OS(Data); Index: test/tools/llvm-profdata/Inputs/basic.proftext =================================================================== --- test/tools/llvm-profdata/Inputs/basic.proftext +++ test/tools/llvm-profdata/Inputs/basic.proftext @@ -0,0 +1,20 @@ +foo +10 +2 +499500 +179900 + +main +16650 +4 +1 +1000 +1000000 +499500 + +foo2 +10 +2 +500500 +180100 + Index: test/tools/llvm-profdata/text-dump.test =================================================================== --- test/tools/llvm-profdata/text-dump.test +++ test/tools/llvm-profdata/text-dump.test @@ -0,0 +1,21 @@ +Basic tests for testing text dump functions. + +RUN: llvm-profdata show --all-functions -counts --text-format %p/Inputs/basic.proftext > %t-basic.proftext1 +RUN: llvm-profdata merge -o %t-basic.proftext2 --text %p/Inputs/basic.proftext + +RUN: llvm-profdata merge -binary -o %t-basic.profdata1 %t-basic.proftext1 +RUN: llvm-profdata merge -o %t-basic.profdata2 %t-basic.proftext2 + +RUN: llvm-profdata show --all-functions -counts %t-basic.profdata1 > %t-basic.dump3 +RUN: llvm-profdata show --all-functions -counts %t-basic.profdata2 > %t-basic.dump4 + +RUN: llvm-profdata merge -text -o %t-basic.proftext5 %t-basic.profdata1 +RUN: llvm-profdata merge -text -o %t-basic.proftext6 %t-basic.profdata2 + +RUN: diff %t-basic.dump3 %t-basic.dump4 +RUN: diff %t-basic.proftext5 %t-basic.proftext6 + +RUN: not llvm-profdata merge -gcc -o %t-basic-profdata3 %t-basic.proftext2 2>&1 | FileCheck %s --check-prefix=UNKNOWN +UNKNOWN: Unknown + + Index: tools/llvm-profdata/llvm-profdata.cpp =================================================================== --- tools/llvm-profdata/llvm-profdata.cpp +++ tools/llvm-profdata/llvm-profdata.cpp @@ -30,8 +30,9 @@ using namespace llvm; -static void exitWithError(const Twine &Message, - StringRef Whence = "", +enum ProfileFormat { PF_None = 0, PF_Text, PF_Binary, PF_GCC }; + +static void exitWithError(const Twine &Message, StringRef Whence = "", StringRef Hint = "") { errs() << "error: "; if (!Whence.empty()) @@ -92,10 +93,14 @@ } static void mergeInstrProfile(const cl::list &Inputs, - StringRef OutputFilename) { + StringRef OutputFilename, + ProfileFormat OutputFormat) { if (OutputFilename.compare("-") == 0) exitWithError("Cannot write indexed profdata format to stdout."); + if (OutputFormat != PF_Binary && OutputFormat != PF_Text) + exitWithError("Unknown format is specified."); + std::error_code EC; raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None); if (EC) @@ -119,14 +124,22 @@ if (Reader->hasError()) exitWithErrorCode(Reader->getError(), Filename); } - Writer.write(Output); + if (OutputFormat == PF_Text) + Writer.writeText(Output); + else + Writer.write(Output); } +static sampleprof::SampleProfileFormat FormatMap[] = { + sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Binary, + sampleprof::SPF_GCC}; + static void mergeSampleProfile(const cl::list &Inputs, StringRef OutputFilename, - sampleprof::SampleProfileFormat OutputFormat) { + ProfileFormat OutputFormat) { using namespace sampleprof; - auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat); + auto WriterOrErr = + SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]); if (std::error_code EC = WriterOrErr.getError()) exitWithErrorCode(EC, OutputFilename); @@ -174,19 +187,18 @@ cl::values(clEnumVal(instr, "Instrumentation profile (default)"), clEnumVal(sample, "Sample profile"), clEnumValEnd)); - cl::opt OutputFormat( - cl::desc("Format of output profile (only meaningful with --sample)"), - cl::init(sampleprof::SPF_Binary), - cl::values(clEnumValN(sampleprof::SPF_Binary, "binary", - "Binary encoding (default)"), - clEnumValN(sampleprof::SPF_Text, "text", "Text encoding"), - clEnumValN(sampleprof::SPF_GCC, "gcc", "GCC encoding"), + cl::opt OutputFormat( + cl::desc("Format of output profile"), cl::init(PF_Binary), + cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), + clEnumValN(PF_Text, "text", "Text encoding"), + clEnumValN(PF_GCC, "gcc", + "GCC encoding (only meaningful for -sample)"), clEnumValEnd)); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); if (ProfileKind == instr) - mergeInstrProfile(Inputs, OutputFilename); + mergeInstrProfile(Inputs, OutputFilename, OutputFormat); else mergeSampleProfile(Inputs, OutputFilename, OutputFormat); @@ -195,7 +207,8 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, bool ShowIndirectCallTargets, bool ShowAllFunctions, - std::string ShowFunction, raw_fd_ostream &OS) { + std::string ShowFunction, bool TextFormat, + raw_fd_ostream &OS) { auto ReaderOrErr = InstrProfReader::create(Filename); if (std::error_code EC = ReaderOrErr.getError()) exitWithErrorCode(EC, Filename); @@ -208,53 +221,69 @@ ShowAllFunctions || (!ShowFunction.empty() && Func.Name.find(ShowFunction) != Func.Name.npos); + bool doTextFormatDump = (Show && ShowCounts && TextFormat); + + if (doTextFormatDump) { + InstrProfWriter::writeRecordInText(Func, OS); + continue; + } + ++TotalFunctions; assert(Func.Counts.size() > 0 && "function missing entry counter"); if (Func.Counts[0] > MaxFunctionCount) MaxFunctionCount = Func.Counts[0]; + for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) { + if (Func.Counts[I] > MaxBlockCount) + MaxBlockCount = Func.Counts[I]; + } + if (Show) { + if (!ShownFunctions) OS << "Counters:\n"; + ++ShownFunctions; OS << " " << Func.Name << ":\n" << " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n" << " Counters: " << Func.Counts.size() << "\n" << " Function count: " << Func.Counts[0] << "\n"; + if (ShowIndirectCallTargets) OS << " Indirect Call Site Count: " << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n"; - } - if (Show && ShowCounts) - OS << " Block counts: ["; - for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) { - if (Func.Counts[I] > MaxBlockCount) - MaxBlockCount = Func.Counts[I]; - if (Show && ShowCounts) - OS << (I == 1 ? "" : ", ") << Func.Counts[I]; - } - if (Show && ShowCounts) - OS << "]\n"; + if (ShowCounts) { + OS << " Block counts: ["; + for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) { + OS << (I == 1 ? "" : ", ") << Func.Counts[I]; + } + OS << "]\n"; + } - if (Show && ShowIndirectCallTargets) { - uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget); - OS << " Indirect Target Results: \n"; - for (size_t I = 0; I < NS; ++I) { - uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I); - std::unique_ptr VD = - Func.getValueForSite(IPVK_IndirectCallTarget, I); - for (uint32_t V = 0; V < NV; V++) { - OS << "\t[ " << I << ", "; - OS << (const char *)VD[V].Value << ", " << VD[V].Count << " ]\n"; + if (ShowIndirectCallTargets) { + uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget); + OS << " Indirect Target Results: \n"; + for (size_t I = 0; I < NS; ++I) { + uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I); + std::unique_ptr VD = + Func.getValueForSite(IPVK_IndirectCallTarget, I); + for (uint32_t V = 0; V < NV; V++) { + OS << "\t[ " << I << ", "; + OS << (const char *)VD[V].Value << ", " << VD[V].Count << " ]\n"; + } } } } } + if (Reader->hasError()) exitWithErrorCode(Reader->getError(), Filename); + if (ShowCounts && TextFormat) + return 0; + if (ShowAllFunctions || !ShowFunction.empty()) OS << "Functions shown: " << ShownFunctions << "\n"; OS << "Total functions: " << TotalFunctions << "\n"; @@ -289,6 +318,9 @@ cl::opt ShowCounts("counts", cl::init(false), cl::desc("Show counter values for shown functions")); + cl::opt TextFormat( + "text-format", cl::init(false), + cl::desc("Show instr profile data in text dump format")); cl::opt ShowIndirectCallTargets( "ic-targets", cl::init(false), cl::desc("Show indirect call site target values for shown functions")); @@ -314,14 +346,14 @@ std::error_code EC; raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); if (EC) - exitWithErrorCode(EC, OutputFilename); + exitWithErrorCode(EC, OutputFilename); if (ShowAllFunctions && !ShowFunction.empty()) errs() << "warning: -function argument ignored: showing all functions\n"; if (ProfileKind == instr) return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets, - ShowAllFunctions, ShowFunction, OS); + ShowAllFunctions, ShowFunction, TextFormat, OS); else return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, ShowFunction, OS);