hotspot/src/share/vm/runtime/sweeper.cpp
changeset 24442 4d4ae31dea26
parent 24424 2658d7834c6e
child 24445 518f34b4384e
--- a/hotspot/src/share/vm/runtime/sweeper.cpp	Tue May 13 11:25:17 2014 +0200
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp	Tue May 13 11:32:10 2014 -0700
@@ -573,37 +573,7 @@
       SWEEP(nm);
     }
   } else {
-    if (UseCodeCacheFlushing) {
-      if (!nm->is_locked_by_vm() && !nm->is_osr_method() && !nm->is_native_method()) {
-        // Do not make native methods and OSR-methods not-entrant
-        nm->dec_hotness_counter();
-        // Get the initial value of the hotness counter. This value depends on the
-        // ReservedCodeCacheSize
-        int reset_val = hotness_counter_reset_val();
-        int time_since_reset = reset_val - nm->hotness_counter();
-        double threshold = -reset_val + (CodeCache::reverse_free_ratio() * NmethodSweepActivity);
-        // The less free space in the code cache we have - the bigger reverse_free_ratio() is.
-        // I.e., 'threshold' increases with lower available space in the code cache and a higher
-        // NmethodSweepActivity. If the current hotness counter - which decreases from its initial
-        // value until it is reset by stack walking - is smaller than the computed threshold, the
-        // corresponding nmethod is considered for removal.
-        if ((NmethodSweepActivity > 0) && (nm->hotness_counter() < threshold) && (time_since_reset > 10)) {
-          // A method is marked as not-entrant if the method is
-          // 1) 'old enough': nm->hotness_counter() < threshold
-          // 2) The method was in_use for a minimum amount of time: (time_since_reset > 10)
-          //    The second condition is necessary if we are dealing with very small code cache
-          //    sizes (e.g., <10m) and the code cache size is too small to hold all hot methods.
-          //    The second condition ensures that methods are not immediately made not-entrant
-          //    after compilation.
-          nm->make_not_entrant();
-          // Code cache state change is tracked in make_not_entrant()
-          if (PrintMethodFlushing && Verbose) {
-            tty->print_cr("### Nmethod %d/" PTR_FORMAT "made not-entrant: hotness counter %d/%d threshold %f",
-                          nm->compile_id(), nm, nm->hotness_counter(), reset_val, threshold);
-          }
-        }
-      }
-    }
+    possibly_flush(nm);
     // Clean-up all inline caches that point to zombie/non-reentrant methods
     MutexLocker cl(CompiledIC_lock);
     nm->cleanup_inline_caches();
@@ -612,6 +582,88 @@
   return freed_memory;
 }
 
+
+void NMethodSweeper::possibly_flush(nmethod* nm) {
+  if (UseCodeCacheFlushing) {
+    if (!nm->is_locked_by_vm() && !nm->is_osr_method() && !nm->is_native_method()) {
+      bool make_not_entrant = false;
+
+      // Do not make native methods and OSR-methods not-entrant
+      nm->dec_hotness_counter();
+      // Get the initial value of the hotness counter. This value depends on the
+      // ReservedCodeCacheSize
+      int reset_val = hotness_counter_reset_val();
+      int time_since_reset = reset_val - nm->hotness_counter();
+      double threshold = -reset_val + (CodeCache::reverse_free_ratio() * NmethodSweepActivity);
+      // The less free space in the code cache we have - the bigger reverse_free_ratio() is.
+      // I.e., 'threshold' increases with lower available space in the code cache and a higher
+      // NmethodSweepActivity. If the current hotness counter - which decreases from its initial
+      // value until it is reset by stack walking - is smaller than the computed threshold, the
+      // corresponding nmethod is considered for removal.
+      if ((NmethodSweepActivity > 0) && (nm->hotness_counter() < threshold) && (time_since_reset > MinPassesBeforeFlush)) {
+        // A method is marked as not-entrant if the method is
+        // 1) 'old enough': nm->hotness_counter() < threshold
+        // 2) The method was in_use for a minimum amount of time: (time_since_reset > MinPassesBeforeFlush)
+        //    The second condition is necessary if we are dealing with very small code cache
+        //    sizes (e.g., <10m) and the code cache size is too small to hold all hot methods.
+        //    The second condition ensures that methods are not immediately made not-entrant
+        //    after compilation.
+        make_not_entrant = true;
+      }
+
+      // The stack-scanning low-cost detection may not see the method was used (which can happen for
+      // flat profiles). Check the age counter for possible data.
+      if (UseCodeAging && make_not_entrant && (nm->is_compiled_by_c2() || nm->is_compiled_by_c1())) {
+        MethodCounters* mc = nm->method()->method_counters();
+        if (mc != NULL) {
+          // Snapshot the value as it's changed concurrently
+          int age = mc->nmethod_age();
+          if (MethodCounters::is_nmethod_hot(age)) {
+            // The method has gone through flushing, and it became relatively hot that it deopted
+            // before we could take a look at it. Give it more time to appear in the stack traces,
+            // proportional to the number of deopts.
+            MethodData* md = nm->method()->method_data();
+            if (md != NULL && time_since_reset > (int)(MinPassesBeforeFlush * (md->tenure_traps() + 1))) {
+              // It's been long enough, we still haven't seen it on stack.
+              // Try to flush it, but enable counters the next time.
+              mc->reset_nmethod_age();
+            } else {
+              make_not_entrant = false;
+            }
+          } else if (MethodCounters::is_nmethod_warm(age)) {
+            // Method has counters enabled, and the method was used within
+            // previous MinPassesBeforeFlush sweeps. Reset the counter. Stay in the existing
+            // compiled state.
+            mc->reset_nmethod_age();
+            // delay the next check
+            nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val());
+            make_not_entrant = false;
+          } else if (MethodCounters::is_nmethod_age_unset(age)) {
+            // No counters were used before. Set the counters to the detection
+            // limit value. If the method is going to be used again it will be compiled
+            // with counters that we're going to use for analysis the the next time.
+            mc->reset_nmethod_age();
+          } else {
+            // Method was totally idle for 10 sweeps
+            // The counter already has the initial value, flush it and may be recompile
+            // later with counters
+          }
+        }
+      }
+
+      if (make_not_entrant) {
+        nm->make_not_entrant();
+
+        // Code cache state change is tracked in make_not_entrant()
+        if (PrintMethodFlushing && Verbose) {
+          tty->print_cr("### Nmethod %d/" PTR_FORMAT "made not-entrant: hotness counter %d/%d threshold %f",
+              nm->compile_id(), nm, nm->hotness_counter(), reset_val, threshold);
+        }
+      }
+    }
+  }
+}
+
 // Print out some state information about the current sweep and the
 // state of the code cache if it's requested.
 void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) {