aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2003-10-28 18:59:04 +0000
committerChris Lattner <sabre@nondot.org>2003-10-28 18:59:04 +0000
commitbaa2007fae24930d9a309b74c63c1d0286fb5b76 (patch)
treec5f21283dcab88e46c86b707a650d4e226a45014
parenta9a3028935e5b4fbcb9b25fc9fe4069fd3e46b09 (diff)
Initial checkin of profiling instrumentation pass. So far, despite the
file name, we only support function profiling. This will be fixed in the near future. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@9547 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/Instrumentation/BlockProfiling.cpp127
1 files changed, 127 insertions, 0 deletions
diff --git a/lib/Transforms/Instrumentation/BlockProfiling.cpp b/lib/Transforms/Instrumentation/BlockProfiling.cpp
new file mode 100644
index 0000000000..5986ed9d13
--- /dev/null
+++ b/lib/Transforms/Instrumentation/BlockProfiling.cpp
@@ -0,0 +1,127 @@
+//===- BlockProfiling.cpp - Insert counters for block profiling -----------===//
+//
+// 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 pass instruments the specified program with counters for basic block or
+// function profiling. This is the most basic form of profiling, which can tell
+// which blocks are hot, but cannot reliably detect hot paths through the CFG.
+// Block profiling counts the number of times each basic block executes, and
+// function profiling counts the number of times each function is called.
+//
+// Note that this implementation is very naive. Control equivalent regions of
+// the CFG should not require duplicate counters, but we do put duplicate
+// counters in.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Instructions.h"
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+
+namespace {
+ class FunctionProfiler : public Pass {
+ bool run(Module &M);
+
+ void insertInitializationCall(Function *MainFn, const char *FnName,
+ GlobalValue *Array);
+ };
+
+ RegisterOpt<FunctionProfiler> X("insert-function-profiling",
+ "Insert instrumentation for function profiling");
+}
+
+
+bool FunctionProfiler::run(Module &M) {
+ Function *Main = M.getMainFunction();
+ if (Main == 0) {
+ std::cerr << "WARNING: cannot insert function profiling into a module"
+ << " with no main function!\n";
+ return false; // No main, no instrumentation!
+ }
+
+ unsigned NumFunctions = 0;
+ for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
+ if (!I->isExternal())
+ ++NumFunctions;
+
+ const Type *ATy = ArrayType::get(Type::UIntTy, NumFunctions);
+ GlobalVariable *Counters =
+ new GlobalVariable(ATy, false, GlobalValue::InternalLinkage,
+ Constant::getNullValue(ATy), "FuncProfCounters", &M);
+
+ ConstantPointerRef *CounterCPR = ConstantPointerRef::get(Counters);
+ std::vector<Constant*> GEPIndices;
+ GEPIndices.resize(2);
+ GEPIndices[0] = Constant::getNullValue(Type::LongTy);
+
+ // Instrument all of the functions...
+ unsigned i = 0;
+ for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
+ if (!I->isExternal()) {
+ // Insert counter at the start of the function, but after any allocas.
+ BasicBlock *Entry = I->begin();
+ BasicBlock::iterator InsertPos = Entry->begin();
+ while (isa<AllocaInst>(InsertPos)) ++InsertPos;
+
+ GEPIndices[1] = ConstantSInt::get(Type::LongTy, i++);
+ Constant *ElementPtr =
+ ConstantExpr::getGetElementPtr(CounterCPR, GEPIndices);
+
+ Value *OldVal = new LoadInst(ElementPtr, "OldFuncCounter", InsertPos);
+ Value *NewVal = BinaryOperator::create(Instruction::Add, OldVal,
+ ConstantInt::get(Type::UIntTy, 1),
+ "NewFuncCounter", InsertPos);
+ new StoreInst(NewVal, ElementPtr, InsertPos);
+ }
+
+ // Add the initialization call to main.
+ insertInitializationCall(Main, "llvm_start_func_profiling", Counters);
+ return true;
+}
+
+void FunctionProfiler::insertInitializationCall(Function *MainFn,
+ const char *FnName,
+ GlobalValue *Array) {
+ const Type *ArgVTy = PointerType::get(PointerType::get(Type::SByteTy));
+ const Type *UIntPtr = PointerType::get(Type::UIntTy);
+ Module &M = *MainFn->getParent();
+ Function *InitFn = M.getOrInsertFunction(FnName, Type::VoidTy, Type::IntTy,
+ ArgVTy, UIntPtr, Type::UIntTy, 0);
+
+ // This could force argc and argv into programs that wouldn't otherwise have
+ // them, but instead we just pass null values in.
+ std::vector<Value*> Args(4);
+ Args[0] = Constant::getNullValue(Type::IntTy);
+ Args[1] = Constant::getNullValue(ArgVTy);
+
+ /* FIXME: We should pass in the command line arguments here! */
+ switch (MainFn->asize()) {
+ default:
+ case 2:
+ case 1:
+ case 0:
+ break;
+ }
+
+ ConstantPointerRef *ArrayCPR = ConstantPointerRef::get(Array);
+ std::vector<Constant*> GEPIndices(2, Constant::getNullValue(Type::LongTy));
+ Args[2] = ConstantExpr::getGetElementPtr(ArrayCPR, GEPIndices);
+
+ unsigned NumElements =
+ cast<ArrayType>(Array->getType()->getElementType())->getNumElements();
+ Args[3] = ConstantUInt::get(Type::UIntTy, NumElements);
+
+ // Skip over any allocas in the entry block.
+ BasicBlock *Entry = MainFn->begin();
+ BasicBlock::iterator InsertPos = Entry->begin();
+ while (isa<AllocaInst>(InsertPos)) ++InsertPos;
+
+ new CallInst(InitFn, Args, "", InsertPos);
+}