[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