From: Xinliang David Li Date: Mon, 23 Nov 2015 20:47:38 +0000 (+0000) Subject: [PGO] Add --text option for llvm-profdata show|merge commands X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=55f78334c142356bff6a35670e336fad1f11b62b [PGO] Add --text option for llvm-profdata show|merge commands The new option is similar to the SampleProfile dump option. - dump raw/indexed format into text profile format - merge the profile and output into text profile format. Note that Value Profiling data text format is not yet designed. That functionality will be added later. Differential Revision: http://reviews.llvm.org/D14894 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253913 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/CommandGuide/llvm-profdata.rst b/docs/CommandGuide/llvm-profdata.rst index 7053b7fa710..1d46fe75467 100644 --- a/docs/CommandGuide/llvm-profdata.rst +++ b/docs/CommandGuide/llvm-profdata.rst @@ -51,7 +51,17 @@ OPTIONS .. 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 @@ -121,6 +131,13 @@ OPTIONS Specify that the input profile is an instrumentation-based profile. +.. option:: -text + + Instruct the profile dumper to show profile counts in the text format of the + instrumentation-based profile data representation. By default, the profile + information is dumped in a more human readable form (also in text) with + annotations. + .. option:: -sample Specify that the input profile is a sample-based profile. diff --git a/include/llvm/ProfileData/InstrProfWriter.h b/include/llvm/ProfileData/InstrProfWriter.h index 5b122d69977..d026e08ec86 100644 --- a/include/llvm/ProfileData/InstrProfWriter.h +++ b/include/llvm/ProfileData/InstrProfWriter.h @@ -43,6 +43,11 @@ public: 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(); diff --git a/lib/ProfileData/InstrProfWriter.cpp b/lib/ProfileData/InstrProfWriter.cpp index 9c4d311f475..1c97b1ad0d3 100644 --- a/lib/ProfileData/InstrProfWriter.cpp +++ b/lib/ProfileData/InstrProfWriter.cpp @@ -171,6 +171,21 @@ void InstrProfWriter::write(raw_fd_ostream &OS) { 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 (uint64_t Count : Func.Counts) + OS << Count << "\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); diff --git a/test/tools/llvm-profdata/Inputs/basic.proftext b/test/tools/llvm-profdata/Inputs/basic.proftext new file mode 100644 index 00000000000..e8c4d82eef2 --- /dev/null +++ b/test/tools/llvm-profdata/Inputs/basic.proftext @@ -0,0 +1,40 @@ +foo +10 +2 +499500 +179900 + +main +16650 +4 +1 +1000 +1000000 +499500 + +foo2 +10 +2 +500500 +180100 + +foo +10 +2 +499500 +179900 + +main +16650 +4 +1 +1000 +1000000 +499500 + +foo2 +10 +2 +500500 +180100 + diff --git a/test/tools/llvm-profdata/text-dump.test b/test/tools/llvm-profdata/text-dump.test new file mode 100644 index 00000000000..94a78d9dbac --- /dev/null +++ b/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 %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 + + diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index 9669c7dfa45..10b6855233d 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -30,6 +30,8 @@ using namespace llvm; +enum ProfileFormat { PF_None = 0, PF_Text, PF_Binary, PF_GCC }; + static void exitWithError(const Twine &Message, StringRef Whence = "", StringRef Hint = "") { @@ -92,10 +94,14 @@ static void handleMergeWriterError(std::error_code &Error, } 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 +125,22 @@ static void mergeInstrProfile(const cl::list &Inputs, 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 +188,18 @@ static int merge_main(int argc, const char *argv[]) { 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 +208,8 @@ static int merge_main(int argc, const char *argv[]) { 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 +222,69 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, 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 (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 (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 (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 +319,9 @@ static int show_main(int argc, const char *argv[]) { cl::opt ShowCounts("counts", cl::init(false), cl::desc("Show counter values for shown functions")); + cl::opt TextFormat( + "text", 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 +347,14 @@ static int show_main(int argc, const char *argv[]) { 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);