[llvm-branch-commits] [llvm-branch] r134075 - in /llvm/branches/GSoC/adaptive-compilation: include/llvm/ExecutionEngine/ExecutionEngine.h lib/ExecutionEngine/ExecutionEngine.cpp lib/ExecutionEngine/JIT/JIT.cpp lib/ExecutionEngine/JIT/JIT.h tools/lli/lli.cpp
Eric Christopher
echristo at apple.com
Wed Jun 29 09:43:49 PDT 2011
Author: echristo
Date: Wed Jun 29 11:43:49 2011
New Revision: 134075
URL: http://llvm.org/viewvc/llvm-project?rev=134075&view=rev
Log:
First cut at adaptive compilation for the JIT.
Patch by Xin Tong!
Modified:
llvm/branches/GSoC/adaptive-compilation/include/llvm/ExecutionEngine/ExecutionEngine.h
llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/ExecutionEngine.cpp
llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.cpp
llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.h
llvm/branches/GSoC/adaptive-compilation/tools/lli/lli.cpp
Modified: llvm/branches/GSoC/adaptive-compilation/include/llvm/ExecutionEngine/ExecutionEngine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/branches/GSoC/adaptive-compilation/include/llvm/ExecutionEngine/ExecutionEngine.h?rev=134075&r1=134074&r2=134075&view=diff
==============================================================================
--- llvm/branches/GSoC/adaptive-compilation/include/llvm/ExecutionEngine/ExecutionEngine.h (original)
+++ llvm/branches/GSoC/adaptive-compilation/include/llvm/ExecutionEngine/ExecutionEngine.h Wed Jun 29 11:43:49 2011
@@ -102,6 +102,13 @@
/// The target data for the platform for which execution is being performed.
const TargetData *TD;
+ /// CompilingAdaptively - True when adaptive compilation is enabled.
+ bool CompilingAdaptively;
+
+ /// AdaptiveCompDebug - Print adaptive compilation debug information, this
+ /// includes name of functions that get compiled and recompiled.
+ bool AdaptiveCompDebug;
+
/// Whether lazy JIT compilation is enabled.
bool CompilingLazily;
@@ -363,6 +370,25 @@
bool isCompilingLazily() const {
return CompilingLazily;
}
+
+ /// EnableAdaptiveCompilation - When adaptive compilation is on. The JIT will choose
+ /// to compile a function with regard to the number of times the function is called
+ /// previously. i.e. The JIT will first compile a function at the lowest level of
+ /// optimization, but will choose to recompile it at a higher optimization if it is
+ /// called frequently
+ virtual void EnableAdaptiveCompilation(bool Enabled = true) {
+ CompilingAdaptively = Enabled;
+ }
+ virtual bool isCompilingAdaptively() const {
+ return CompilingAdaptively;
+ }
+ virtual void EnableAdaptiveCompilationDebug(bool Enabled = true) {
+ AdaptiveCompDebug = Enabled;
+ }
+ virtual bool isAdaptiveCompDebug() {
+ return AdaptiveCompDebug;
+ }
+
// Deprecated in favor of isCompilingLazily (to reduce double-negatives).
// Remove this in LLVM 2.8.
bool isLazyCompilationDisabled() const {
Modified: llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/ExecutionEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/ExecutionEngine.cpp?rev=134075&r1=134074&r2=134075&view=diff
==============================================================================
--- llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/ExecutionEngine.cpp (original)
+++ llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/ExecutionEngine.cpp Wed Jun 29 11:43:49 2011
@@ -60,6 +60,7 @@
ExceptionTableRegister(0),
ExceptionTableDeregister(0) {
CompilingLazily = false;
+ CompilingAdaptively = false;
GVCompilationDisabled = false;
SymbolSearchingDisabled = false;
Modules.push_back(M);
Modified: llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.cpp?rev=134075&r1=134074&r2=134075&view=diff
==============================================================================
--- llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.cpp (original)
+++ llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.cpp Wed Jun 29 11:43:49 2011
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "JIT.h"
+#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
@@ -267,6 +268,37 @@
}
}
+/// PopulateFunctionToCallCountMap - Find all the functions in the modules and allocate
+/// an invocation counter to it.
+void JITState::PopulateFunctionToCallCountMap(bool AdaptiveCompDebug) {
+
+ // Iterate over all functions in the module and initialize its
+ // recompilation metadata
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
+ if (!I->isDeclaration()) {
+ // Allocate an invocation counter for every function
+ FunctionToCallCountMap.insert(FunctionToCallCountMap.begin(),
+ std::pair<Function*, int*>(&*I, new int));
+
+ // Assign the initial compilation level for every function
+ FunctionToCompLevelMap.insert(FunctionToCompLevelMap.begin(),
+ std::pair<Function*, CodeGenOpt::Level>(&*I,
+ CodeGenOpt::None));
+
+ // Initialize the function as unJITted before
+ FunctionToJITTimeMap.insert(FunctionToJITTimeMap.begin(),
+ std::pair<Function*, bool>(&*I, true));
+ }
+ }
+
+ // Make sure to zero out every invocation counter
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
+ if (!I->isDeclaration()) {
+ *((int*) FunctionToCallCountMap.find(&*I)->second) = 0;
+ }
+ }
+}
+
JIT::JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji,
JITMemoryManager *JMM, CodeGenOpt::Level OptLevel, bool GVsWithCode)
: ExecutionEngine(M), TM(tm), TJI(tji), AllocateGVsWithCode(GVsWithCode),
@@ -283,7 +315,8 @@
// Add target data
MutexGuard locked(lock);
- FunctionPassManager &PM = jitstate->getPM(locked);
+ // Initialize the pass manager with the given optimization level
+ FunctionPassManager &PM = jitstate->getPM(locked, OptLevel);
PM.add(new TargetData(*TM.getTargetData()));
// Turn the machine code intermediate representation into bytes in memory that
@@ -314,6 +347,8 @@
// Initialize passes.
PM.doInitialization();
+ // Set the pass manager to initialized
+ jitstate->setPMInited(OptLevel);
}
JIT::~JIT() {
@@ -335,20 +370,18 @@
assert(!jitstate && "jitstate should be NULL if Modules vector is empty!");
jitstate = new JITState(M);
-
- FunctionPassManager &PM = jitstate->getPM(locked);
- PM.add(new TargetData(*TM.getTargetData()));
-
- // Turn the machine code intermediate representation into bytes in memory
- // that may be executed.
- if (TM.addPassesToEmitMachineCode(PM, *JCE, CodeGenOpt::Default)) {
- report_fatal_error("Target does not support machine code emission!");
+ // Only populate the function to call count when adaptive compilation is used
+ if (isCompilingAdaptively()) {
+ jitstate->PopulateFunctionToCallCountMap(isAdaptiveCompDebug());
}
- // Initialize passes.
- PM.doInitialization();
+ if (isCompilingAdaptively()) {
+ // Initialize all the pass managers
+ InitializeAllAvailPMs(locked);
+ } else {
+ InitializePM(locked, jitstate->getSingleInitJIT());
+ }
}
-
ExecutionEngine::addModule(M);
}
@@ -367,17 +400,16 @@
if (!jitstate && !Modules.empty()) {
jitstate = new JITState(Modules[0]);
- FunctionPassManager &PM = jitstate->getPM(locked);
- PM.add(new TargetData(*TM.getTargetData()));
-
- // Turn the machine code intermediate representation into bytes in memory
- // that may be executed.
- if (TM.addPassesToEmitMachineCode(PM, *JCE, CodeGenOpt::Default)) {
- report_fatal_error("Target does not support machine code emission!");
+ // Only populate the function to call count when adaptive compilation is used
+ if (isCompilingAdaptively()) {
+ jitstate->PopulateFunctionToCallCountMap(isAdaptiveCompDebug());
}
- // Initialize passes.
- PM.doInitialization();
+ if (isCompilingAdaptively()) {
+ InitializeAllAvailPMs(locked);
+ } else {
+ InitializePM(locked, jitstate->getSingleInitJIT());
+ }
}
return result;
}
@@ -637,7 +669,25 @@
void JIT::jitTheFunction(Function *F, const MutexGuard &locked) {
isAlreadyCodeGenerating = true;
- jitstate->getPM(locked).run(*F);
+ if (isCompilingAdaptively()) {
+ // This is the first time this function is compiled. Compile at
+ // CodeGenOpt::None
+ if (jitstate->isFirstTimeJITed(locked, F)) {
+ jitstate->getPM(locked, CodeGenOpt::None).run(*F);
+ } else {
+ // Compile with the next optimization level
+ CodeGenOpt::Level nextOptLevel = jitstate->getNextCompLevel(locked, F);
+ jitstate->setNextCompLevel(locked, F, nextOptLevel);
+
+ // Clear the invocation counter for the function
+ jitstate->setCounterForFunction(locked, F, 0);
+ jitstate->getPM(locked, nextOptLevel).run(*F);
+ }
+ } else {
+ // Adaptive compilation has not been enabled, there should only be one
+ // pass manager that is initialized. Get it and use it to compile the function
+ jitstate->getPM(locked, jitstate->getSingleInitJIT()).run(*F);
+ }
isAlreadyCodeGenerating = false;
// clear basic block addresses after this function is done
Modified: llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.h
URL: http://llvm.org/viewvc/llvm-project/llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.h?rev=134075&r1=134074&r2=134075&view=diff
==============================================================================
--- llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.h (original)
+++ llvm/branches/GSoC/adaptive-compilation/lib/ExecutionEngine/JIT/JIT.h Wed Jun 29 11:43:49 2011
@@ -17,6 +17,9 @@
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/PassManager.h"
#include "llvm/Support/ValueHandle.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MutexGuard.h"
namespace llvm {
@@ -29,18 +32,216 @@
class JITState {
private:
- FunctionPassManager PM; // Passes to compile a function
+
+ // JIT adaptive compilation. Different pass managers with different levels of
+ // optimizations
+ // Pass manager for passes to compile functions at CodeGen::OptLevel == NONE
+ bool PMOptNoneInited;
+ FunctionPassManager PMOptNone;
+
+ // Pass manager for passes to compile functions at CodeGen::OptLevel == LESS
+ bool PMOptLessInited;
+ FunctionPassManager PMOptLess;
+
+ // Pass manager for passes to compile functions at CodeGen::OptLevel == DEFAULT
+ bool PMOptDftInited;
+ FunctionPassManager PMOptDft;
+
+ // Pass manager for passes to compile functions at CodeGen::OptLevel == AGGRESSIVE
+ bool PMOptAggrInited;
+ FunctionPassManager PMOptAggr;
+
Module *M; // Module used to create the PM
/// PendingFunctions - Functions which have not been code generated yet, but
/// were called from a function being code generated.
std::vector<AssertingVH<Function> > PendingFunctions;
+ /// FunctionToCallCountMap - Function and the number of times it gets called from the time
+ /// it is compiled
+ std::map<Function*, int*> FunctionToCallCountMap;
+
+ /// FunctionToCompLevelMap - Function and the current compilation level map
+ std::map<Function*, CodeGenOpt::Level> FunctionToCompLevelMap;
+
+ /// FunctionToJITTimeMap - Function and whether it has been JITted before
+ std::map<Function*, bool> FunctionToJITTimeMap;
+
public:
- explicit JITState(Module *M) : PM(M), M(M) {}
- FunctionPassManager &getPM(const MutexGuard &L) {
- return PM;
+ /// Recompilation threshold for the adaptive compilation framework
+ enum JITReCompCount {
+ CompilationNone = 100, // Compile at -O0
+ CompilationLess = 1000, // Compile at -O1
+ CompilationDefault = 10000, // Compile at -O2
+ CompilationAggressive = 100000 // Compile at -O3
+ };
+
+ /// isPMInited - Return whether the pass manager with the given optimization level
+ /// is initialized
+ bool isPMInited(CodeGenOpt::Level OptLevel) {
+ switch (OptLevel) {
+ case CodeGenOpt::None :
+ return PMOptNoneInited;
+ case CodeGenOpt::Less:
+ return PMOptLessInited;
+ case CodeGenOpt::Default:
+ return PMOptDftInited;
+ case CodeGenOpt::Aggressive:
+ return PMOptNoneInited;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ /// setPMInited - Mark the pass manager with the given optimization level
+ /// as initialized
+ void setPMInited(CodeGenOpt::Level OptLevel) {
+ switch (OptLevel) {
+ case CodeGenOpt::None :
+ PMOptNoneInited = true;
+ break;
+ case CodeGenOpt::Less:
+ PMOptLessInited = true;
+ break;
+ case CodeGenOpt::Default:
+ PMOptDftInited = true;
+ break;
+ case CodeGenOpt::Aggressive:
+ PMOptAggrInited = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /// getSingleInitJIT - Return the optimization level associated with the one and
+ /// only one initialized pass manager. Panic if multiple pass managers are
+ /// initialized
+ CodeGenOpt::Level getSingleInitJIT() {
+ int InitedPMCount = 0;
+ CodeGenOpt::Level InitedOpt;
+
+ if (PMOptNoneInited) {
+ InitedPMCount ++;
+ InitedOpt = CodeGenOpt::None;
+ }
+ if (PMOptLessInited) {
+ InitedPMCount ++;
+ InitedOpt = CodeGenOpt::Less;
+ }
+ if (PMOptDftInited) {
+ InitedPMCount ++;
+ InitedOpt = CodeGenOpt::Default;
+ }
+ if (PMOptAggrInited) {
+ InitedPMCount ++;
+ InitedOpt = CodeGenOpt::Aggressive;
+ }
+ assert(InitedPMCount == 1 && "Invalid number of Pass Managers Initialized");
+ return InitedOpt;
+ }
+
+ /// getNextCompThrhold - Get the compilation threshold based on the
+ /// compilation level given
+ int getCompThreshold(CodeGenOpt::Level OptLevel) const {
+ switch (OptLevel) {
+ case CodeGenOpt::None :
+ return CompilationNone;
+ case CodeGenOpt::Less:
+ return CompilationLess;
+ case CodeGenOpt::Default:
+ return CompilationDefault;
+ case CodeGenOpt::Aggressive:
+ return CompilationAggressive;
+ default:
+ break;
+ }
+ return CompilationNone;
+ }
+
+ explicit JITState(Module *M)
+ : PMOptNoneInited(false), PMOptNone(M), PMOptLessInited(false), PMOptLess(M),
+ PMOptDftInited(false), PMOptDft(M), PMOptAggrInited(false), PMOptAggr(M),
+ M(M) {}
+
+ /// PopulateFunctionToCallCountMap - Find all the functions in the modules
+ /// and allocate an invocation counter to it
+ void PopulateFunctionToCallCountMap(bool AdaptiveCompDebug);
+
+ /// isFirstTimeJITed - Return true when this function has not been JITted
+ bool isFirstTimeJITed(const MutexGuard &L, Function *F) {
+ bool firstTime = FunctionToJITTimeMap.find(F)->second;
+ FunctionToJITTimeMap.find(F)->second = false;
+ return firstTime;
+ }
+
+ /// hasReachedAggrComp - Return true if the last compilation for the function
+ /// was an aggressive compilation
+ bool hasReachedAggrComp(const MutexGuard &L, Function *F) {
+ return FunctionToCompLevelMap.find(F)->second == CodeGenOpt::Aggressive;
+ }
+
+ /// getNextCompLevel - Return the next compilation for the function
+ CodeGenOpt::Level getNextCompLevel(const MutexGuard &L, Function *F) {
+ // Determine the next compilation level based on the current
+ // invocation counter
+ CodeGenOpt::Level nextCompLevel = CodeGenOpt::None;
+ CodeGenOpt::Level CurrentLevel = FunctionToCompLevelMap.find(F)->second;
+ switch (CurrentLevel) {
+ case CodeGenOpt::None :
+ nextCompLevel = CodeGenOpt::Less;
+ break;
+ case CodeGenOpt::Less :
+ nextCompLevel = CodeGenOpt::Default;
+ break;
+ case CodeGenOpt::Default :
+ nextCompLevel = CodeGenOpt::Aggressive;
+ break;
+ case CodeGenOpt::Aggressive :
+ nextCompLevel = CodeGenOpt::Aggressive;
+ break;
+ default :
+ assert(false && "Invalid compilation level given");
+ }
+ return nextCompLevel;
+ }
+
+ // setNextCompLevel - Set the next compilation level for the function
+ void setNextCompLevel(const MutexGuard &L, Function *F,
+ CodeGenOpt::Level nextCompLevel) {
+ FunctionToCompLevelMap.find(F)->second = nextCompLevel;
+ }
+
+ /// getCounterForFunction - Return the invocation counter address
+ /// for the given function
+ void *getCounterForFunction(const MutexGuard &L, Function *F) {
+ return FunctionToCallCountMap.find(F)->second;
+ }
+
+ /// setCounterForFunction - Set the invocation count for the given function
+ void setCounterForFunction(const MutexGuard &L, Function *F, int newCount) {
+ *((int *)FunctionToCallCountMap.find(F)->second) = newCount;
+ }
+
+ /// getPM - Return pass manager according to the level of the optimizations
+ /// specified. If no optimization level is specified, the pass manager with
+ /// CodeGenOpt::Default is returned
+ FunctionPassManager &getPM(const MutexGuard &L,
+ CodeGenOpt::Level OptLevel = CodeGenOpt::Default) {
+ switch(OptLevel) {
+ case CodeGenOpt::None :
+ return PMOptNone;
+ case CodeGenOpt::Less :
+ return PMOptLess;
+ case CodeGenOpt::Default :
+ return PMOptDft;
+ case CodeGenOpt::Aggressive :
+ return PMOptAggr;
+ default :
+ assert(false && "Invalid optimization level given");
+ }
}
Module *getModule() const { return M; }
@@ -116,6 +317,56 @@
virtual GenericValue runFunction(Function *F,
const std::vector<GenericValue> &ArgValues);
+ /// EnableAdaptiveCompilation - When adaptive compilation is on. The JIT will choose
+ /// to compile a function with regard to the number of times the function is called
+ /// previously. i.e. The JIT will first compile a function at the lowest level of
+ /// optimization, but will choose to recompile it at a higher optimization if it is
+ /// called frequently
+ virtual void EnableAdaptiveCompilation(bool Enabled = true) {
+ // Call the Execution Engine function first
+ ExecutionEngine::EnableAdaptiveCompilation(Enabled);
+
+ MutexGuard locked(lock);
+ // Then the adaptive compilation specific data structure needs
+ // to be initialized
+ InitializePM(locked, CodeGenOpt::None);
+ InitializePM(locked, CodeGenOpt::Less);
+ InitializePM(locked, CodeGenOpt::Default);
+ InitializePM(locked, CodeGenOpt::Aggressive);
+
+ jitstate->PopulateFunctionToCallCountMap(isAdaptiveCompDebug());
+ }
+
+ /// InitializePM - Initialize a pass manager with the given
+ /// optimization level
+ void InitializePM(MutexGuard &locked, CodeGenOpt::Level OptLevel) {
+
+ if (!jitstate->isPMInited(OptLevel)) {
+ // get the specified pass manager
+ FunctionPassManager &PM = jitstate->getPM(locked, OptLevel);
+ PM.add(new TargetData(*TM.getTargetData()));
+
+ // Turn the machine code intermediate representation into bytes in memory that
+ // may be executed.
+ if (TM.addPassesToEmitMachineCode(PM, *JCE, OptLevel)) {
+ report_fatal_error("Target does not support machine code emission!");
+ }
+ // Initialize passes.
+ PM.doInitialization();
+ jitstate->setPMInited(OptLevel);
+ }
+ }
+
+ /// InitializeAllAvailPMs - Initialize all the pass managers
+ /// in the jitstate
+ void InitializeAllAvailPMs(MutexGuard &locked) {
+ // Initialize all the pass managers available in the JITState
+ InitializePM(locked, CodeGenOpt::None);
+ InitializePM(locked, CodeGenOpt::Less);
+ InitializePM(locked, CodeGenOpt::Default);
+ InitializePM(locked, CodeGenOpt::Aggressive);
+ }
+
/// getPointerToNamedFunction - This method returns the address of the
/// specified function by using the dlsym function call. As such it is only
/// useful for resolving library symbols, not code generated symbols.
Modified: llvm/branches/GSoC/adaptive-compilation/tools/lli/lli.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/branches/GSoC/adaptive-compilation/tools/lli/lli.cpp?rev=134075&r1=134074&r2=134075&view=diff
==============================================================================
--- llvm/branches/GSoC/adaptive-compilation/tools/lli/lli.cpp (original)
+++ llvm/branches/GSoC/adaptive-compilation/tools/lli/lli.cpp Wed Jun 29 11:43:49 2011
@@ -56,6 +56,15 @@
cl::desc("Force interpretation: disable JIT"),
cl::init(false));
+ // Enable adaptive compilation (experimental).
+ cl::opt<bool> AdaptiveCompilation ("adaptive-comp",
+ cl::desc("Enable adaptive compilation"),
+ cl::init(false));
+ // Print adaptive compilation information. This includes the names of functions
+ // that get compiled and recompiled (experimental).
+ cl::opt<bool> AdaptiveCompilationDbg ("adaptive-comp-debug",
+ cl::desc("Enable adaptive compilation debug"),
+ cl::init(false));
cl::opt<bool> UseMCJIT(
"use-mcjit", cl::desc("Enable use of the MC-based JIT (if available)"),
cl::init(false));
@@ -199,6 +208,24 @@
exit(1);
}
+ // Enable adaptive compilation. Adaptive compilation can only be
+ // enabled when there is no optimization level given and JIT is
+ // chosen to execute the user program
+ if (AdaptiveCompilation) {
+ if (ForceInterpreter) {
+ errs() << "Adaptive compilation can not be enabled with interpreter.\n";
+ exit(1);
+ }
+ if (OptLevel != ' ') {
+ errs() << "Adaptive compilation can not be enabled with an optimization level given.\n";
+ exit(1);
+ }
+ EE->EnableAdaptiveCompilation(true);
+ if (AdaptiveCompilationDbg) {
+ EE->EnableAdaptiveCompilationDebug(true);
+ }
+ }
+
EE->RegisterJITEventListener(createOProfileJITEventListener());
EE->DisableLazyCompilation(NoLazyCompilation);
More information about the llvm-branch-commits
mailing list