diff options
author | tstellar <tstellar@91177308-0d34-0410-b5e6-96231b3b80d8> | 2012-09-18 19:40:39 +0000 |
---|---|---|
committer | tstellar <tstellar@91177308-0d34-0410-b5e6-96231b3b80d8> | 2012-09-18 19:40:39 +0000 |
commit | 15d14cb83df480dd4aab6435873ca50254891a2d (patch) | |
tree | e5ef7d77a1e7703b625d5de82d50c26e4944cdc7 /tools/llvm-prof |
Create R600 Branch
git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/R600/@164161 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-prof')
-rw-r--r-- | tools/llvm-prof/CMakeLists.txt | 5 | ||||
-rw-r--r-- | tools/llvm-prof/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | tools/llvm-prof/Makefile | 17 | ||||
-rw-r--r-- | tools/llvm-prof/llvm-prof.cpp | 293 |
4 files changed, 337 insertions, 0 deletions
diff --git a/tools/llvm-prof/CMakeLists.txt b/tools/llvm-prof/CMakeLists.txt new file mode 100644 index 0000000000..442112bc88 --- /dev/null +++ b/tools/llvm-prof/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_LINK_COMPONENTS bitreader analysis) + +add_llvm_tool(llvm-prof + llvm-prof.cpp + ) diff --git a/tools/llvm-prof/LLVMBuild.txt b/tools/llvm-prof/LLVMBuild.txt new file mode 100644 index 0000000000..d59127cc26 --- /dev/null +++ b/tools/llvm-prof/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/llvm-prof/LLVMBuild.txt --------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-prof +parent = Tools +required_libraries = Analysis BitReader diff --git a/tools/llvm-prof/Makefile b/tools/llvm-prof/Makefile new file mode 100644 index 0000000000..f829786765 --- /dev/null +++ b/tools/llvm-prof/Makefile @@ -0,0 +1,17 @@ +##===- tools/llvm-prof/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-prof +LINK_COMPONENTS := bitreader analysis + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/llvm-prof/llvm-prof.cpp b/tools/llvm-prof/llvm-prof.cpp new file mode 100644 index 0000000000..81e9503abe --- /dev/null +++ b/tools/llvm-prof/llvm-prof.cpp @@ -0,0 +1,293 @@ +//===- 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->getName() << "\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->getName() << "() - " + << Counts[i].first->getName() << "\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); + + // Run the printer pass. + PassManager PassMgr; + PassMgr.add(createProfileLoaderPass(ProfileDataFile)); + PassMgr.add(new ProfileInfoPrinterPass(PIL)); + PassMgr.run(*M); + + return 0; +} |