X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-profdata%2Fllvm-profdata.cpp;h=10b6855233d5deeda91b09c2d445f5b251fa8062;hb=8061fe5c678f809e69acc199fe68dc5794601503;hp=3229d4da5d6f26ae70b8ffe0f89fba408cab2364;hpb=8c968628473c7de416e3f468fead20023f33107e;p=oota-llvm.git diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index 3229d4da5d6..10b6855233d 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -11,136 +11,279 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/InstrProfWriter.h" +#include "llvm/ProfileData/SampleProfReader.h" +#include "llvm/ProfileData/SampleProfWriter.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" 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()) errs() << Whence << ": "; errs() << Message << "\n"; + if (!Hint.empty()) + errs() << Hint << "\n"; ::exit(1); } -int merge_main(int argc, const char *argv[]) { - cl::list Inputs(cl::Positional, cl::Required, cl::OneOrMore, - cl::desc("")); +static void exitWithErrorCode(const std::error_code &Error, + StringRef Whence = "") { + if (Error.category() == instrprof_category()) { + instrprof_error instrError = static_cast(Error.value()); + if (instrError == instrprof_error::unrecognized_format) { + // Hint for common error of forgetting -sample for sample profiles. + exitWithError(Error.message(), Whence, + "Perhaps you forgot to use the -sample option?"); + } + } + exitWithError(Error.message(), Whence); +} - 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)); +namespace { + enum ProfileKinds { instr, sample }; +} - cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); +static void handleMergeWriterError(std::error_code &Error, + StringRef WhenceFile = "", + StringRef WhenceFunction = "", + bool ShowHint = true) +{ + if (!WhenceFile.empty()) + errs() << WhenceFile << ": "; + if (!WhenceFunction.empty()) + errs() << WhenceFunction << ": "; + errs() << Error.message() << "\n"; + + if (ShowHint) { + StringRef Hint = ""; + if (Error.category() == instrprof_category()) { + instrprof_error instrError = static_cast(Error.value()); + switch (instrError) { + case instrprof_error::hash_mismatch: + case instrprof_error::count_mismatch: + case instrprof_error::value_site_count_mismatch: + Hint = "Make sure that all profile data to be merged is generated " \ + "from the same binary."; + break; + default: + break; + } + } + + if (!Hint.empty()) + errs() << Hint << "\n"; + } +} +static void mergeInstrProfile(const cl::list &Inputs, + 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) - exitWithError(EC.message(), OutputFilename); + exitWithErrorCode(EC, OutputFilename); InstrProfWriter Writer; + SmallSet WriterErrorCodes; for (const auto &Filename : Inputs) { - std::unique_ptr Reader; - if (std::error_code ec = InstrProfReader::create(Filename, Reader)) - exitWithError(ec.message(), Filename); - - for (const auto &I : *Reader) - if (std::error_code EC = - Writer.addFunctionCounts(I.Name, I.Hash, I.Counts)) - errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n"; + auto ReaderOrErr = InstrProfReader::create(Filename); + if (std::error_code ec = ReaderOrErr.getError()) + exitWithErrorCode(ec, Filename); + + auto Reader = std::move(ReaderOrErr.get()); + for (auto &I : *Reader) { + if (std::error_code EC = Writer.addRecord(std::move(I))) { + // Only show hint the first time an error occurs. + bool firstTime = WriterErrorCodes.insert(EC).second; + handleMergeWriterError(EC, Filename, I.Name, firstTime); + } + } if (Reader->hasError()) - exitWithError(Reader->getError().message(), Filename); + exitWithErrorCode(Reader->getError(), Filename); } - Writer.write(Output); - - return 0; + if (OutputFormat == PF_Text) + Writer.writeText(Output); + else + Writer.write(Output); } -int show_main(int argc, const char *argv[]) { - cl::opt Filename(cl::Positional, cl::Required, - cl::desc("")); +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, + ProfileFormat OutputFormat) { + using namespace sampleprof; + auto WriterOrErr = + SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]); + if (std::error_code EC = WriterOrErr.getError()) + exitWithErrorCode(EC, OutputFilename); + + auto Writer = std::move(WriterOrErr.get()); + StringMap ProfileMap; + SmallVector, 5> Readers; + for (const auto &Filename : Inputs) { + auto ReaderOrErr = + SampleProfileReader::create(Filename, getGlobalContext()); + if (std::error_code EC = ReaderOrErr.getError()) + exitWithErrorCode(EC, Filename); + + // We need to keep the readers around until after all the files are + // read so that we do not lose the function names stored in each + // reader's memory. The function names are needed to write out the + // merged profile map. + Readers.push_back(std::move(ReaderOrErr.get())); + const auto Reader = Readers.back().get(); + if (std::error_code EC = Reader->read()) + exitWithErrorCode(EC, 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); +} - 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")); +static 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"), 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 summary\n"); - - std::unique_ptr Reader; - if (std::error_code EC = InstrProfReader::create(Filename, Reader)) - exitWithError(EC.message(), Filename); + cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); - if (OutputFilename.empty()) - OutputFilename = "-"; + if (ProfileKind == instr) + mergeInstrProfile(Inputs, OutputFilename, OutputFormat); + else + mergeSampleProfile(Inputs, OutputFilename, OutputFormat); - std::error_code EC; - raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); - if (EC) - exitWithError(EC.message(), OutputFilename); + return 0; +} - if (ShowAllFunctions && !ShowFunction.empty()) - errs() << "warning: -function argument ignored: showing all functions\n"; +static int showInstrProfile(std::string Filename, bool ShowCounts, + bool ShowIndirectCallTargets, bool ShowAllFunctions, + std::string ShowFunction, bool TextFormat, + raw_fd_ostream &OS) { + auto ReaderOrErr = InstrProfReader::create(Filename); + if (std::error_code EC = ReaderOrErr.getError()) + exitWithErrorCode(EC, Filename); + auto Reader = std::move(ReaderOrErr.get()); 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); + + 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 (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 (ShowIndirectCallTargets) + OS << " Indirect Call Site Count: " + << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\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 (Show && ShowCounts) - OS << "]\n"; } + if (Reader->hasError()) - exitWithError(Reader->getError().message(), Filename); + exitWithErrorCode(Reader->getError(), Filename); + + if (ShowCounts && TextFormat) + return 0; if (ShowAllFunctions || !ShowFunction.empty()) OS << "Functions shown: " << ShownFunctions << "\n"; @@ -150,6 +293,73 @@ int show_main(int argc, const char *argv[]) { return 0; } +static int showSampleProfile(std::string Filename, bool ShowCounts, + bool ShowAllFunctions, std::string ShowFunction, + raw_fd_ostream &OS) { + using namespace sampleprof; + auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext()); + if (std::error_code EC = ReaderOrErr.getError()) + exitWithErrorCode(EC, Filename); + + auto Reader = std::move(ReaderOrErr.get()); + if (std::error_code EC = Reader->read()) + exitWithErrorCode(EC, Filename); + + if (ShowAllFunctions || ShowFunction.empty()) + Reader->dump(OS); + else + Reader->dumpFunctionProfile(ShowFunction, OS); + + return 0; +} + +static 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 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")); + 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) + 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, TextFormat, 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();