| //===- llvm-prof.cpp - Read in and process llvmprof.out data files --------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This tools is meant for use with the various LLVM profiling instrumentation | |
| // passes. It reads in the data file produced by executing an instrumented | |
| // program, and outputs a nice report. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/InstrTypes.h" | |
| #include "llvm/LLVMContext.h" | |
| #include "llvm/Module.h" | |
| #include "llvm/PassManager.h" | |
| #include "llvm/Assembly/AssemblyAnnotationWriter.h" | |
| #include "llvm/Analysis/ProfileInfo.h" | |
| #include "llvm/Analysis/ProfileInfoLoader.h" | |
| #include "llvm/Analysis/Passes.h" | |
| #include "llvm/Bitcode/ReaderWriter.h" | |
| #include "llvm/Support/CommandLine.h" | |
| #include "llvm/Support/FormattedStream.h" | |
| #include "llvm/Support/ManagedStatic.h" | |
| #include "llvm/Support/MemoryBuffer.h" | |
| #include "llvm/Support/PrettyStackTrace.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include "llvm/Support/Format.h" | |
| #include "llvm/Support/Signals.h" | |
| #include "llvm/Support/system_error.h" | |
| #include <algorithm> | |
| #include <iomanip> | |
| #include <map> | |
| #include <set> | |
| using namespace llvm; | |
| namespace { | |
| cl::opt<std::string> | |
| BitcodeFile(cl::Positional, cl::desc("<program bitcode file>"), | |
| cl::Required); | |
| cl::opt<std::string> | |
| ProfileDataFile(cl::Positional, cl::desc("<llvmprof.out file>"), | |
| cl::Optional, cl::init("llvmprof.out")); | |
| cl::opt<bool> | |
| PrintAnnotatedLLVM("annotated-llvm", | |
| cl::desc("Print LLVM code with frequency annotations")); | |
| cl::alias PrintAnnotated2("A", cl::desc("Alias for --annotated-llvm"), | |
| cl::aliasopt(PrintAnnotatedLLVM)); | |
| cl::opt<bool> | |
| PrintAllCode("print-all-code", | |
| cl::desc("Print annotated code for the entire program")); | |
| } | |
| // PairSecondSort - A sorting predicate to sort by the second element of a pair. | |
| template<class T> | |
| struct PairSecondSortReverse | |
| : public std::binary_function<std::pair<T, double>, | |
| std::pair<T, double>, bool> { | |
| bool operator()(const std::pair<T, double> &LHS, | |
| const std::pair<T, double> &RHS) const { | |
| return LHS.second > RHS.second; | |
| } | |
| }; | |
| static double ignoreMissing(double w) { | |
| if (w == ProfileInfo::MissingValue) return 0; | |
| return w; | |
| } | |
| namespace { | |
| class ProfileAnnotator : public AssemblyAnnotationWriter { | |
| ProfileInfo &PI; | |
| public: | |
| ProfileAnnotator(ProfileInfo &pi) : PI(pi) {} | |
| virtual void emitFunctionAnnot(const Function *F, | |
| formatted_raw_ostream &OS) { | |
| double w = PI.getExecutionCount(F); | |
| if (w != ProfileInfo::MissingValue) { | |
| OS << ";;; %" << F->getName() << " called "<<(unsigned)w | |
| <<" times.\n;;;\n"; | |
| } | |
| } | |
| virtual void emitBasicBlockStartAnnot(const BasicBlock *BB, | |
| formatted_raw_ostream &OS) { | |
| double w = PI.getExecutionCount(BB); | |
| if (w != ProfileInfo::MissingValue) { | |
| if (w != 0) { | |
| OS << "\t;;; Basic block executed " << (unsigned)w << " times.\n"; | |
| } else { | |
| OS << "\t;;; Never executed!\n"; | |
| } | |
| } | |
| } | |
| virtual void emitBasicBlockEndAnnot(const BasicBlock *BB, | |
| formatted_raw_ostream &OS) { | |
| // Figure out how many times each successor executed. | |
| std::vector<std::pair<ProfileInfo::Edge, double> > SuccCounts; | |
| const TerminatorInst *TI = BB->getTerminator(); | |
| for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; ++s) { | |
| BasicBlock* Succ = TI->getSuccessor(s); | |
| double w = ignoreMissing(PI.getEdgeWeight(std::make_pair(BB, Succ))); | |
| if (w != 0) | |
| SuccCounts.push_back(std::make_pair(std::make_pair(BB, Succ), w)); | |
| } | |
| if (!SuccCounts.empty()) { | |
| OS << "\t;;; Out-edge counts:"; | |
| for (unsigned i = 0, e = SuccCounts.size(); i != e; ++i) | |
| OS << " [" << (SuccCounts[i]).second << " -> " | |
| << (SuccCounts[i]).first.second->getName() << "]"; | |
| OS << "\n"; | |
| } | |
| } | |
| }; | |
| } | |
| namespace { | |
| /// ProfileInfoPrinterPass - Helper pass to dump the profile information for | |
| /// a module. | |
| // | |
| // FIXME: This should move elsewhere. | |
| class ProfileInfoPrinterPass : public ModulePass { | |
| ProfileInfoLoader &PIL; | |
| public: | |
| static char ID; // Class identification, replacement for typeinfo. | |
| explicit ProfileInfoPrinterPass(ProfileInfoLoader &_PIL) | |
| : ModulePass(ID), PIL(_PIL) {} | |
| virtual void getAnalysisUsage(AnalysisUsage &AU) const { | |
| AU.setPreservesAll(); | |
| AU.addRequired<ProfileInfo>(); | |
| } | |
| bool runOnModule(Module &M); | |
| }; | |
| } | |
| char ProfileInfoPrinterPass::ID = 0; | |
| bool ProfileInfoPrinterPass::runOnModule(Module &M) { | |
| ProfileInfo &PI = getAnalysis<ProfileInfo>(); | |
| std::map<const Function *, unsigned> FuncFreqs; | |
| std::map<const BasicBlock*, unsigned> BlockFreqs; | |
| std::map<ProfileInfo::Edge, unsigned> EdgeFreqs; | |
| // Output a report. Eventually, there will be multiple reports selectable on | |
| // the command line, for now, just keep things simple. | |
| // Emit the most frequent function table... | |
| std::vector<std::pair<Function*, double> > FunctionCounts; | |
| std::vector<std::pair<BasicBlock*, double> > Counts; | |
| for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) { | |
| if (FI->isDeclaration()) continue; | |
| double w = ignoreMissing(PI.getExecutionCount(FI)); | |
| FunctionCounts.push_back(std::make_pair(FI, w)); | |
| for (Function::iterator BB = FI->begin(), BBE = FI->end(); | |
| BB != BBE; ++BB) { | |
| double w = ignoreMissing(PI.getExecutionCount(BB)); | |
| Counts.push_back(std::make_pair(BB, w)); | |
| } | |
| } | |
| // Sort by the frequency, backwards. | |
| sort(FunctionCounts.begin(), FunctionCounts.end(), | |
| PairSecondSortReverse<Function*>()); | |
| double TotalExecutions = 0; | |
| for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) | |
| TotalExecutions += FunctionCounts[i].second; | |
| outs() << "===" << std::string(73, '-') << "===\n" | |
| << "LLVM profiling output for execution"; | |
| if (PIL.getNumExecutions() != 1) outs() << "s"; | |
| outs() << ":\n"; | |
| for (unsigned i = 0, e = PIL.getNumExecutions(); i != e; ++i) { | |
| outs() << " "; | |
| if (e != 1) outs() << i+1 << ". "; | |
| outs() << PIL.getExecution(i) << "\n"; | |
| } | |
| outs() << "\n===" << std::string(73, '-') << "===\n"; | |
| outs() << "Function execution frequencies:\n\n"; | |
| // Print out the function frequencies... | |
| outs() << " ## Frequency\n"; | |
| for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) { | |
| if (FunctionCounts[i].second == 0) { | |
| outs() << "\n NOTE: " << e-i << " function" | |
| << (e-i-1 ? "s were" : " was") << " never executed!\n"; | |
| break; | |
| } | |
| outs() << format("%3d", i+1) << ". " | |
| << format("%5.2g", FunctionCounts[i].second) << "/" | |
| << format("%g", TotalExecutions) << " " | |
| << FunctionCounts[i].first->getNameStr() << "\n"; | |
| } | |
| std::set<Function*> FunctionsToPrint; | |
| TotalExecutions = 0; | |
| for (unsigned i = 0, e = Counts.size(); i != e; ++i) | |
| TotalExecutions += Counts[i].second; | |
| // Sort by the frequency, backwards. | |
| sort(Counts.begin(), Counts.end(), | |
| PairSecondSortReverse<BasicBlock*>()); | |
| outs() << "\n===" << std::string(73, '-') << "===\n"; | |
| outs() << "Top 20 most frequently executed basic blocks:\n\n"; | |
| // Print out the function frequencies... | |
| outs() <<" ## %% \tFrequency\n"; | |
| unsigned BlocksToPrint = Counts.size(); | |
| if (BlocksToPrint > 20) BlocksToPrint = 20; | |
| for (unsigned i = 0; i != BlocksToPrint; ++i) { | |
| if (Counts[i].second == 0) break; | |
| Function *F = Counts[i].first->getParent(); | |
| outs() << format("%3d", i+1) << ". " | |
| << format("%5g", Counts[i].second/(double)TotalExecutions*100) << "% " | |
| << format("%5.0f", Counts[i].second) << "/" | |
| << format("%g", TotalExecutions) << "\t" | |
| << F->getNameStr() << "() - " | |
| << Counts[i].first->getNameStr() << "\n"; | |
| FunctionsToPrint.insert(F); | |
| } | |
| if (PrintAnnotatedLLVM || PrintAllCode) { | |
| outs() << "\n===" << std::string(73, '-') << "===\n"; | |
| outs() << "Annotated LLVM code for the module:\n\n"; | |
| ProfileAnnotator PA(PI); | |
| if (FunctionsToPrint.empty() || PrintAllCode) | |
| M.print(outs(), &PA); | |
| else | |
| // Print just a subset of the functions. | |
| for (std::set<Function*>::iterator I = FunctionsToPrint.begin(), | |
| E = FunctionsToPrint.end(); I != E; ++I) | |
| (*I)->print(outs(), &PA); | |
| } | |
| return false; | |
| } | |
| int main(int argc, char **argv) { | |
| // Print a stack trace if we signal out. | |
| sys::PrintStackTraceOnErrorSignal(); | |
| PrettyStackTraceProgram X(argc, argv); | |
| LLVMContext &Context = getGlobalContext(); | |
| llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. | |
| cl::ParseCommandLineOptions(argc, argv, "llvm profile dump decoder\n"); | |
| // Read in the bitcode file... | |
| std::string ErrorMessage; | |
| OwningPtr<MemoryBuffer> Buffer; | |
| error_code ec; | |
| Module *M = 0; | |
| if (!(ec = MemoryBuffer::getFileOrSTDIN(BitcodeFile, Buffer))) { | |
| M = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); | |
| } else | |
| ErrorMessage = ec.message(); | |
| if (M == 0) { | |
| errs() << argv[0] << ": " << BitcodeFile << ": " | |
| << ErrorMessage << "\n"; | |
| return 1; | |
| } | |
| // Read the profiling information. This is redundant since we load it again | |
| // using the standard profile info provider pass, but for now this gives us | |
| // access to additional information not exposed via the ProfileInfo | |
| // interface. | |
| ProfileInfoLoader PIL(argv[0], ProfileDataFile, *M); | |
| // Run the printer pass. | |
| PassManager PassMgr; | |
| PassMgr.add(createProfileLoaderPass(ProfileDataFile)); | |
| PassMgr.add(new ProfileInfoPrinterPass(PIL)); | |
| PassMgr.run(*M); | |
| return 0; | |
| } |