OSDN Git Service

Add weight to compiled/interpreter transitions.
authorNicolas Geoffray <ngeoffray@google.com>
Thu, 14 Apr 2016 14:00:33 +0000 (15:00 +0100)
committerNicolas Geoffray <ngeoffray@google.com>
Mon, 18 Apr 2016 08:25:37 +0000 (09:25 +0100)
Also:
- Cleanup logging.
- Check ArtMethod status before adding compilation requests.
- Don't request osr compilation if we know AddSamples does not come
  from a back edge.

Bug: 27865109

(cherry picked from commit 71cd50fb67fa48667b0ab59aa436a582c04ba43d)

Change-Id: Icbe89fe6cc495b113616391a8f257758d34b4b60

runtime/interpreter/interpreter.cc
runtime/interpreter/interpreter_common.cc
runtime/interpreter/interpreter_common.h
runtime/interpreter/interpreter_goto_table_impl.cc
runtime/interpreter/interpreter_switch_impl.cc
runtime/interpreter/mterp/mterp.cc
runtime/jit/jit.cc
runtime/jit/jit.h
runtime/jit/jit_code_cache.cc
runtime/jit/jit_code_cache.h

index a432782..97dbe5d 100644 (file)
@@ -292,7 +292,7 @@ static inline JValue Execute(Thread* self, const DexFile::CodeItem* code_item,
 
         // Pop the shadow frame before calling into compiled code.
         self->PopShadowFrame();
-        ArtInterpreterToCompiledCodeBridge(self, code_item, &shadow_frame, &result);
+        ArtInterpreterToCompiledCodeBridge(self, nullptr, code_item, &shadow_frame, &result);
         // Push the shadow frame back as the caller will expect it.
         self->PushShadowFrame(&shadow_frame);
 
@@ -535,6 +535,10 @@ JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* cod
     return JValue();
   }
 
+  jit::Jit* jit = Runtime::Current()->GetJit();
+  if (jit != nullptr) {
+    jit->NotifyCompiledCodeToInterpreterTransition(self, shadow_frame->GetMethod());
+  }
   return Execute(self, code_item, *shadow_frame, JValue());
 }
 
index 3453abc..12d70c5 100644 (file)
@@ -503,6 +503,7 @@ static inline bool DoCallCommon(ArtMethod* called_method,
                                 uint32_t vregC) ALWAYS_INLINE;
 
 void ArtInterpreterToCompiledCodeBridge(Thread* self,
+                                        ArtMethod* caller,
                                         const DexFile::CodeItem* code_item,
                                         ShadowFrame* shadow_frame,
                                         JValue* result)
@@ -530,6 +531,10 @@ void ArtInterpreterToCompiledCodeBridge(Thread* self,
   uint16_t arg_offset = (code_item == nullptr)
                             ? 0
                             : code_item->registers_size_ - code_item->ins_size_;
+  jit::Jit* jit = Runtime::Current()->GetJit();
+  if (jit != nullptr && caller != nullptr) {
+    jit->NotifyInterpreterToCompiledCodeTransition(self, caller);
+  }
   method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
                  (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
                  result, method->GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty());
@@ -726,7 +731,8 @@ static inline bool DoCallCommon(ArtMethod* called_method,
         target->GetEntryPointFromQuickCompiledCode())) {
       ArtInterpreterToInterpreterBridge(self, code_item, new_shadow_frame, result);
     } else {
-      ArtInterpreterToCompiledCodeBridge(self, code_item, new_shadow_frame, result);
+      ArtInterpreterToCompiledCodeBridge(
+          self, shadow_frame.GetMethod(), code_item, new_shadow_frame, result);
     }
   } else {
     UnstartedRuntime::Invoke(self, code_item, new_shadow_frame, result, first_dest_reg);
index fb98175..e5b89e2 100644 (file)
@@ -635,7 +635,7 @@ static inline bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instr
         jit->InvokeVirtualOrInterface(
             self, receiver, sf_method, shadow_frame.GetDexPC(), called_method);
       }
-      jit->AddSamples(self, sf_method, 1);
+      jit->AddSamples(self, sf_method, 1, /*with_backedges*/false);
     }
     // TODO: Remove the InvokeVirtualOrInterface instrumentation, as it was only used by the JIT.
     if (type == kVirtual || type == kInterface) {
@@ -681,7 +681,7 @@ static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
     if (jit != nullptr) {
       jit->InvokeVirtualOrInterface(
           self, receiver, shadow_frame.GetMethod(), shadow_frame.GetDexPC(), called_method);
-      jit->AddSamples(self, shadow_frame.GetMethod(), 1);
+      jit->AddSamples(self, shadow_frame.GetMethod(), 1, /*with_backedges*/false);
     }
     instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
     // TODO: Remove the InvokeVirtualOrInterface instrumentation, as it was only used by the JIT.
@@ -1001,8 +1001,11 @@ static inline bool IsBackwardBranch(int32_t branch_offset) {
   return branch_offset <= 0;
 }
 
-void ArtInterpreterToCompiledCodeBridge(Thread* self, const DexFile::CodeItem* code_item,
-                                        ShadowFrame* shadow_frame, JValue* result);
+void ArtInterpreterToCompiledCodeBridge(Thread* self,
+                                        ArtMethod* caller,
+                                        const DexFile::CodeItem* code_item,
+                                        ShadowFrame* shadow_frame,
+                                        JValue* result);
 
 // Explicitly instantiate all DoInvoke functions.
 #define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check)                      \
index c95af6f..13cfb98 100644 (file)
@@ -78,7 +78,7 @@ namespace interpreter {
 #define HOTNESS_UPDATE()                                                                       \
   do {                                                                                         \
     if (jit != nullptr) {                                                                      \
-      jit->AddSamples(self, method, 1);                                                        \
+      jit->AddSamples(self, method, 1, /*with_backedges*/ true);                               \
     }                                                                                          \
   } while (false)
 
index ca1d635..4323d4f 100644 (file)
@@ -89,7 +89,7 @@ namespace interpreter {
 #define HOTNESS_UPDATE()                                                                       \
   do {                                                                                         \
     if (jit != nullptr) {                                                                      \
-      jit->AddSamples(self, method, 1);                                                        \
+      jit->AddSamples(self, method, 1, /*with_backedges*/ true);                               \
     }                                                                                          \
   } while (false)
 
index e005589..bd1af04 100644 (file)
@@ -689,7 +689,7 @@ extern "C" int16_t MterpAddHotnessBatch(ArtMethod* method,
   jit::Jit* jit = Runtime::Current()->GetJit();
   if (jit != nullptr) {
     int16_t count = shadow_frame->GetCachedHotnessCountdown() - shadow_frame->GetHotnessCountdown();
-    jit->AddSamples(self, method, count);
+    jit->AddSamples(self, method, count, /*with_backedges*/ true);
   }
   return MterpSetUpHotnessCountdown(method, shadow_frame);
 }
@@ -702,7 +702,7 @@ extern "C" bool  MterpProfileBranch(Thread* self, ShadowFrame* shadow_frame, int
   uint32_t dex_pc = shadow_frame->GetDexPC();
   jit::Jit* jit = Runtime::Current()->GetJit();
   if ((jit != nullptr) && (offset <= 0)) {
-    jit->AddSamples(self, method, 1);
+    jit->AddSamples(self, method, 1, /*with_backedges*/ true);
   }
   int16_t countdown_value = MterpSetUpHotnessCountdown(method, shadow_frame);
   if (countdown_value == jit::kJitCheckForOSR) {
@@ -722,7 +722,7 @@ extern "C" bool MterpMaybeDoOnStackReplacement(Thread* self,
   jit::Jit* jit = Runtime::Current()->GetJit();
   if (offset <= 0) {
     // Keep updating hotness in case a compilation request was dropped.  Eventually it will retry.
-    jit->AddSamples(self, method, 1);
+    jit->AddSamples(self, method, 1, /*with_backedges*/ true);
   }
   // Assumes caller has already determined that an OSR check is appropriate.
   return jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
index 8f126bf..cad71a0 100644 (file)
@@ -97,8 +97,9 @@ JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& opt
       LOG(FATAL) << "Priority thread weight cannot be 0.";
     }
   } else {
-    jit_options->priority_thread_weight_ =
-        std::max(jit_options->compile_threshold_ / 2000, static_cast<size_t>(1));
+    jit_options->priority_thread_weight_ = std::max(
+        jit_options->warmup_threshold_ / Jit::kDefaultPriorityThreadWeightRatio,
+        static_cast<size_t>(1));
   }
 
   return jit_options;
@@ -159,6 +160,8 @@ Jit* Jit::Create(JitOptions* options, std::string* error_msg) {
   jit->warm_method_threshold_ = options->GetWarmupThreshold();
   jit->osr_method_threshold_ = options->GetOsrThreshold();
   jit->priority_thread_weight_ = options->GetPriorityThreadWeight();
+  jit->transition_weight_ = std::max(
+      jit->warm_method_threshold_ / kDefaultTransitionRatio, static_cast<size_t>(1));
 
   jit->CreateThreadPool();
 
@@ -245,8 +248,17 @@ bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) {
   if (!code_cache_->NotifyCompilationOf(method_to_compile, self, osr)) {
     return false;
   }
+
+  VLOG(jit) << "Compiling method "
+            << PrettyMethod(method_to_compile)
+            << " osr=" << std::boolalpha << osr;
   bool success = jit_compile_method_(jit_compiler_handle_, method_to_compile, self, osr);
   code_cache_->DoneCompiling(method_to_compile, self, osr);
+  if (!success) {
+    VLOG(jit) << "Failed to compile method "
+              << PrettyMethod(method_to_compile)
+              << " osr=" << std::boolalpha << osr;
+  }
   return success;
 }
 
@@ -525,15 +537,9 @@ class JitCompileTask FINAL : public Task {
   void Run(Thread* self) OVERRIDE {
     ScopedObjectAccess soa(self);
     if (kind_ == kCompile) {
-      VLOG(jit) << "JitCompileTask compiling method " << PrettyMethod(method_);
-      if (!Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr */ false)) {
-        VLOG(jit) << "Failed to compile method " << PrettyMethod(method_);
-      }
+      Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr */ false);
     } else if (kind_ == kCompileOsr) {
-      VLOG(jit) << "JitCompileTask compiling method osr " << PrettyMethod(method_);
-      if (!Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr */ true)) {
-        VLOG(jit) << "Failed to compile method osr " << PrettyMethod(method_);
-      }
+      Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr */ true);
     } else {
       DCHECK(kind_ == kAllocateProfile);
       if (ProfilingInfo::Create(self, method_, /* retry_allocation */ true)) {
@@ -554,7 +560,7 @@ class JitCompileTask FINAL : public Task {
   DISALLOW_IMPLICIT_CONSTRUCTORS(JitCompileTask);
 };
 
-void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count) {
+void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_backedges) {
   if (thread_pool_ == nullptr) {
     // Should only see this when shutting down.
     DCHECK(Runtime::Current()->IsShuttingDown(self));
@@ -578,7 +584,8 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count) {
   }
   int32_t new_count = starting_count + count;   // int32 here to avoid wrap-around;
   if (starting_count < warm_method_threshold_) {
-    if (new_count >= warm_method_threshold_) {
+    if ((new_count >= warm_method_threshold_) &&
+        (method->GetProfilingInfo(sizeof(void*)) == nullptr)) {
       bool success = ProfilingInfo::Create(self, method, /* retry_allocation */ false);
       if (success) {
         VLOG(jit) << "Start profiling " << PrettyMethod(method);
@@ -600,14 +607,19 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count) {
     // Avoid jumping more than one state at a time.
     new_count = std::min(new_count, hot_method_threshold_ - 1);
   } else if (starting_count < hot_method_threshold_) {
-    if (new_count >= hot_method_threshold_) {
+    if ((new_count >= hot_method_threshold_) &&
+        !code_cache_->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
       DCHECK(thread_pool_ != nullptr);
       thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile));
     }
     // Avoid jumping more than one state at a time.
     new_count = std::min(new_count, osr_method_threshold_ - 1);
   } else if (starting_count < osr_method_threshold_) {
-    if (new_count >= osr_method_threshold_) {
+    if (!with_backedges) {
+      // If the samples don't contain any back edge, we don't increment the hotness.
+      return;
+    }
+    if ((new_count >= osr_method_threshold_) &&  !code_cache_->IsOsrCompiled(method)) {
       DCHECK(thread_pool_ != nullptr);
       thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr));
     }
@@ -635,7 +647,7 @@ void Jit::MethodEntered(Thread* thread, ArtMethod* method) {
       !Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) {
     method->SetEntryPointFromQuickCompiledCode(profiling_info->GetSavedEntryPoint());
   } else {
-    AddSamples(thread, method, 1);
+    AddSamples(thread, method, 1, /* with_backedges */false);
   }
 }
 
index 4e2d1ab..8198c18 100644 (file)
@@ -43,6 +43,8 @@ class Jit {
  public:
   static constexpr bool kStressMode = kIsDebugBuild;
   static constexpr size_t kDefaultCompileThreshold = kStressMode ? 2 : 10000;
+  static constexpr size_t kDefaultPriorityThreadWeightRatio = 1000;
+  static constexpr size_t kDefaultTransitionRatio = 100;
 
   virtual ~Jit();
   static Jit* Create(JitOptions* options, std::string* error_msg);
@@ -92,7 +94,7 @@ class Jit {
   void MethodEntered(Thread* thread, ArtMethod* method)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  void AddSamples(Thread* self, ArtMethod* method, uint16_t samples)
+  void AddSamples(Thread* self, ArtMethod* method, uint16_t samples, bool with_backedges)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   void InvokeVirtualOrInterface(Thread* thread,
@@ -102,6 +104,16 @@ class Jit {
                                 ArtMethod* callee)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  void NotifyInterpreterToCompiledCodeTransition(Thread* self, ArtMethod* caller)
+      SHARED_REQUIRES(Locks::mutator_lock_) {
+    AddSamples(self, caller, transition_weight_, false);
+  }
+
+  void NotifyCompiledCodeToInterpreterTransition(Thread* self, ArtMethod* callee)
+      SHARED_REQUIRES(Locks::mutator_lock_) {
+    AddSamples(self, callee, transition_weight_, false);
+  }
+
   // Starts the profile saver if the config options allow profile recording.
   // The profile will be stored in the specified `filename` and will contain
   // information collected from the given `code_paths` (a set of dex locations).
@@ -173,6 +185,7 @@ class Jit {
   uint16_t warm_method_threshold_;
   uint16_t osr_method_threshold_;
   uint16_t priority_thread_weight_;
+  uint16_t transition_weight_;
   std::unique_ptr<ThreadPool> thread_pool_;
 
   DISALLOW_COPY_AND_ASSIGN(Jit);
index 820ae6a..1f3e08b 100644 (file)
@@ -366,7 +366,7 @@ uint8_t* JitCodeCache::CommitCodeInternal(Thread* self,
     }
     last_update_time_ns_.StoreRelease(NanoTime());
     VLOG(jit)
-        << "JIT added (osr = " << std::boolalpha << osr << std::noboolalpha << ") "
+        << "JIT added (osr=" << std::boolalpha << osr << std::noboolalpha << ") "
         << PrettyMethod(method) << "@" << method
         << " ccache_size=" << PrettySize(CodeCacheSizeLocked()) << ": "
         << " dcache_size=" << PrettySize(DataCacheSizeLocked()) << ": "
@@ -905,15 +905,18 @@ uint64_t JitCodeCache::GetLastUpdateTimeNs() const {
   return last_update_time_ns_.LoadAcquire();
 }
 
+bool JitCodeCache::IsOsrCompiled(ArtMethod* method) {
+  MutexLock mu(Thread::Current(), lock_);
+  return osr_code_map_.find(method) != osr_code_map_.end();
+}
+
 bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self, bool osr) {
   if (!osr && ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
-    VLOG(jit) << PrettyMethod(method) << " is already compiled";
     return false;
   }
 
   MutexLock mu(self, lock_);
   if (osr && (osr_code_map_.find(method) != osr_code_map_.end())) {
-    VLOG(jit) << PrettyMethod(method) << " is already osr compiled";
     return false;
   }
 
@@ -928,7 +931,6 @@ bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self, bool osr
   }
 
   if (info->IsMethodBeingCompiled(osr)) {
-    VLOG(jit) << PrettyMethod(method) << " is already being compiled";
     return false;
   }
 
index 9f18c70..f31cc51 100644 (file)
@@ -186,6 +186,8 @@ class JitCodeCache {
 
   void Dump(std::ostream& os) REQUIRES(!lock_);
 
+  bool IsOsrCompiled(ArtMethod* method) REQUIRES(!lock_);
+
  private:
   // Take ownership of maps.
   JitCodeCache(MemMap* code_map,