From d5336ae269d86af133cb465e1b0dba38121f11c2 Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Sat, 1 Nov 2014 00:56:55 +0000 Subject: Add show and merge tools for sample PGO profiles. Summary: This patch extends the 'show' and 'merge' commands in llvm-profdata to handle sample PGO formats. Using the 'merge' command it is now possible to convert one sample PGO format to another. The only format that is currently not working is 'gcc'. I still need to implement support for it in lib/ProfileData. The changes in the sample profile support classes are needed for the merge operation. Reviewers: bogner Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D6065 llvm-svn: 221032 --- llvm/tools/llvm-profdata/llvm-profdata.cpp | 163 ++++++++++++++++++++++------- 1 file changed, 125 insertions(+), 38 deletions(-) (limited to 'llvm/tools/llvm-profdata/llvm-profdata.cpp') diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 3229d4da5d6..22acedc569a 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -14,6 +14,9 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/InstrProfWriter.h" +#include "llvm/ProfileData/SampleProfReader.h" +#include "llvm/ProfileData/SampleProfWriter.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" @@ -33,18 +36,9 @@ static void exitWithError(const Twine &Message, StringRef Whence = "") { ::exit(1); } -int merge_main(int argc, const char *argv[]) { - cl::list Inputs(cl::Positional, cl::Required, cl::OneOrMore, - cl::desc("")); - - cl::opt OutputFilename("output", cl::value_desc("output"), - cl::init("-"), cl::Required, - cl::desc("Output file")); - cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), - cl::aliasopt(OutputFilename)); - - cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); +enum ProfileKinds { instr, sample }; +void mergeInstrProfile(cl::list Inputs, StringRef OutputFilename) { if (OutputFilename.compare("-") == 0) exitWithError("Cannot write indexed profdata format to stdout."); @@ -67,50 +61,84 @@ int merge_main(int argc, const char *argv[]) { exitWithError(Reader->getError().message(), Filename); } Writer.write(Output); - - return 0; } -int show_main(int argc, const char *argv[]) { - cl::opt Filename(cl::Positional, cl::Required, - cl::desc("")); +void mergeSampleProfile(cl::list Inputs, StringRef OutputFilename, + sampleprof::SampleProfileFormat OutputFormat) { + using namespace sampleprof; + std::unique_ptr Writer; + if (std::error_code EC = SampleProfileWriter::create(OutputFilename.data(), + Writer, OutputFormat)) + exitWithError(EC.message(), OutputFilename); - cl::opt ShowCounts("counts", cl::init(false), - cl::desc("Show counter values for shown functions")); - cl::opt ShowAllFunctions("all-functions", cl::init(false), - cl::desc("Details for every function")); - cl::opt ShowFunction("function", - cl::desc("Details for matching functions")); + StringMap ProfileMap; + for (const auto &Filename : Inputs) { + std::unique_ptr Reader; + if (std::error_code EC = + SampleProfileReader::create(Filename, Reader, getGlobalContext())) + exitWithError(EC.message(), Filename); + + if (std::error_code EC = Reader->read()) + exitWithError(EC.message(), Filename); + + StringMap &Profiles = Reader->getProfiles(); + for (StringMap::iterator I = Profiles.begin(), + E = Profiles.end(); + I != E; ++I) { + StringRef FName = I->first(); + FunctionSamples &Samples = I->second; + ProfileMap[FName].merge(Samples); + } + } + Writer->write(ProfileMap); +} + +int merge_main(int argc, const char *argv[]) { + cl::list Inputs(cl::Positional, cl::Required, cl::OneOrMore, + cl::desc("")); cl::opt OutputFilename("output", cl::value_desc("output"), - cl::init("-"), + cl::init("-"), cl::Required, cl::desc("Output file")); cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), cl::aliasopt(OutputFilename)); + cl::opt ProfileKind( + cl::desc("Profile kind:"), cl::init(instr), + 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"), + clEnumValEnd)); - cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); + cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); + + if (ProfileKind == instr) + mergeInstrProfile(Inputs, OutputFilename); + else + mergeSampleProfile(Inputs, OutputFilename, OutputFormat); + + return 0; +} +int showInstrProfile(std::string Filename, bool ShowCounts, + bool ShowAllFunctions, std::string ShowFunction, + raw_fd_ostream &OS) { std::unique_ptr Reader; if (std::error_code EC = InstrProfReader::create(Filename, Reader)) exitWithError(EC.message(), Filename); - if (OutputFilename.empty()) - OutputFilename = "-"; - - std::error_code EC; - raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); - if (EC) - exitWithError(EC.message(), OutputFilename); - - if (ShowAllFunctions && !ShowFunction.empty()) - errs() << "warning: -function argument ignored: showing all functions\n"; - uint64_t MaxFunctionCount = 0, MaxBlockCount = 0; size_t ShownFunctions = 0, TotalFunctions = 0; for (const auto &Func : *Reader) { - bool Show = ShowAllFunctions || - (!ShowFunction.empty() && - Func.Name.find(ShowFunction) != Func.Name.npos); + bool Show = + ShowAllFunctions || (!ShowFunction.empty() && + Func.Name.find(ShowFunction) != Func.Name.npos); ++TotalFunctions; assert(Func.Counts.size() > 0 && "function missing entry counter"); @@ -150,6 +178,65 @@ int show_main(int argc, const char *argv[]) { return 0; } +int showSampleProfile(std::string Filename, bool ShowCounts, + bool ShowAllFunctions, std::string ShowFunction, + raw_fd_ostream &OS) { + using namespace sampleprof; + std::unique_ptr Reader; + if (std::error_code EC = + SampleProfileReader::create(Filename, Reader, getGlobalContext())) + exitWithError(EC.message(), Filename); + + Reader->read(); + if (ShowAllFunctions || ShowFunction.empty()) + Reader->dump(OS); + else + Reader->dumpFunctionProfile(ShowFunction, OS); + + return 0; +} + +int show_main(int argc, const char *argv[]) { + cl::opt Filename(cl::Positional, cl::Required, + cl::desc("")); + + cl::opt ShowCounts("counts", cl::init(false), + cl::desc("Show counter values for shown functions")); + cl::opt ShowAllFunctions("all-functions", cl::init(false), + cl::desc("Details for every function")); + cl::opt ShowFunction("function", + cl::desc("Details for matching functions")); + + cl::opt OutputFilename("output", cl::value_desc("output"), + cl::init("-"), cl::desc("Output file")); + cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), + cl::aliasopt(OutputFilename)); + cl::opt ProfileKind( + cl::desc("Profile kind:"), cl::init(instr), + cl::values(clEnumVal(instr, "Instrumentation profile (default)"), + clEnumVal(sample, "Sample profile"), clEnumValEnd)); + + cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); + + if (OutputFilename.empty()) + OutputFilename = "-"; + + std::error_code EC; + raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); + if (EC) + exitWithError(EC.message(), OutputFilename); + + if (ShowAllFunctions && !ShowFunction.empty()) + errs() << "warning: -function argument ignored: showing all functions\n"; + + if (ProfileKind == instr) + return showInstrProfile(Filename, ShowCounts, ShowAllFunctions, + ShowFunction, OS); + else + return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, + ShowFunction, OS); +} + int main(int argc, const char *argv[]) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); -- cgit v1.2.3