//===- llvm-prof.cpp - Read in and process llvmprof.out data files --------===// // // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and 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/Module.h" #include "llvm/Assembly/AsmAnnotationWriter.h" #include "llvm/Analysis/ProfileInfoLoader.h" #include "llvm/Bytecode/Reader.h" #include "Support/CommandLine.h" #include "llvm/System/Signals.h" #include #include #include #include using namespace llvm; namespace { cl::opt BytecodeFile(cl::Positional, cl::desc(""), cl::Required); cl::opt ProfileDataFile(cl::Positional, cl::desc(""), cl::Optional, cl::init("llvmprof.out")); cl::opt 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 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 struct PairSecondSortReverse : public std::binary_function, std::pair, bool> { bool operator()(const std::pair &LHS, const std::pair &RHS) const { return LHS.second > RHS.second; } }; namespace { class ProfileAnnotator : public AssemblyAnnotationWriter { std::map &FuncFreqs; std::map &BlockFreqs; std::map &EdgeFreqs; public: ProfileAnnotator(std::map &FF, std::map &BF, std::map &EF) : FuncFreqs(FF), BlockFreqs(BF), EdgeFreqs(EF) {} virtual void emitFunctionAnnot(const Function *F, std::ostream &OS) { OS << ";;; %" << F->getName() << " called " << FuncFreqs[F] << " times.\n;;;\n"; } virtual void emitBasicBlockStartAnnot(const BasicBlock *BB, std::ostream &OS) { if (BlockFreqs.empty()) return; if (unsigned Count = BlockFreqs[BB]) OS << "\t;;; Basic block executed " << Count << " times.\n"; else OS << "\t;;; Never executed!\n"; } virtual void emitBasicBlockEndAnnot(const BasicBlock *BB, std::ostream &OS){ if (EdgeFreqs.empty()) return; // Figure out how many times each successor executed. std::vector > SuccCounts; const TerminatorInst *TI = BB->getTerminator(); std::map::iterator I = EdgeFreqs.lower_bound(std::make_pair(const_cast(BB), 0U)); for (; I != EdgeFreqs.end() && I->first.first == BB; ++I) if (I->second) SuccCounts.push_back(std::make_pair(TI->getSuccessor(I->first.second), I->second)); 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->getName() << "]"; OS << "\n"; } } }; } int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, " llvm profile dump decoder\n"); sys::PrintStackTraceOnErrorSignal(); // Read in the bytecode file... std::string ErrorMessage; Module *M = ParseBytecodeFile(BytecodeFile, &ErrorMessage); if (M == 0) { std::cerr << argv[0] << ": " << BytecodeFile << ": " << ErrorMessage << "\n"; return 1; } // Read the profiling information ProfileInfoLoader PI(argv[0], ProfileDataFile, *M); std::map FuncFreqs; std::map BlockFreqs; std::map 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 > FunctionCounts; PI.getFunctionCounts(FunctionCounts); FuncFreqs.insert(FunctionCounts.begin(), FunctionCounts.end()); // Sort by the frequency, backwards. std::sort(FunctionCounts.begin(), FunctionCounts.end(), PairSecondSortReverse()); unsigned long long TotalExecutions = 0; for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) TotalExecutions += FunctionCounts[i].second; std::cout << "===" << std::string(73, '-') << "===\n" << "LLVM profiling output for execution"; if (PI.getNumExecutions() != 1) std::cout << "s"; std::cout << ":\n"; for (unsigned i = 0, e = PI.getNumExecutions(); i != e; ++i) { std::cout << " "; if (e != 1) std::cout << i+1 << ". "; std::cout << PI.getExecution(i) << "\n"; } std::cout << "\n===" << std::string(73, '-') << "===\n"; std::cout << "Function execution frequencies:\n\n"; // Print out the function frequencies... printf(" ## Frequency\n"); for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) { if (FunctionCounts[i].second == 0) { printf("\n NOTE: %d function%s never executed!\n", e-i, e-i-1 ? "s were" : " was"); break; } printf("%3d. %5u/%llu %s\n", i+1, FunctionCounts[i].second, TotalExecutions, FunctionCounts[i].first->getName().c_str()); } std::set FunctionsToPrint; // If we have block count information, print out the LLVM module with // frequency annotations. if (PI.hasAccurateBlockCounts()) { std::vector > Counts; PI.getBlockCounts(Counts); TotalExecutions = 0; for (unsigned i = 0, e = Counts.size(); i != e; ++i) TotalExecutions += Counts[i].second; // Sort by the frequency, backwards. std::sort(Counts.begin(), Counts.end(), PairSecondSortReverse()); std::cout << "\n===" << std::string(73, '-') << "===\n"; std::cout << "Top 20 most frequently executed basic blocks:\n\n"; // Print out the function frequencies... printf(" ## %%%% \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(); printf("%3d. %5.2f%% %5u/%llu\t%s() - %s\n", i+1, Counts[i].second/(double)TotalExecutions*100, Counts[i].second, TotalExecutions, F->getName().c_str(), Counts[i].first->getName().c_str()); FunctionsToPrint.insert(F); } BlockFreqs.insert(Counts.begin(), Counts.end()); } if (PI.hasAccurateEdgeCounts()) { std::vector > Counts; PI.getEdgeCounts(Counts); EdgeFreqs.insert(Counts.begin(), Counts.end()); } if (PrintAnnotatedLLVM || PrintAllCode) { std::cout << "\n===" << std::string(73, '-') << "===\n"; std::cout << "Annotated LLVM code for the module:\n\n"; ProfileAnnotator PA(FuncFreqs, BlockFreqs, EdgeFreqs); if (FunctionsToPrint.empty() || PrintAllCode) M->print(std::cout, &PA); else // Print just a subset of the functions... for (std::set::iterator I = FunctionsToPrint.begin(), E = FunctionsToPrint.end(); I != E; ++I) (*I)->print(std::cout, &PA); } return 0; }