changeset 1904:016a3628c885

6994056: G1: when GC locker is active, extend the Eden instead of allocating into the old gen Summary: Allow the eden to the expanded up to a point when the GC locker is active. Reviewed-by: jwilhelm, johnc, ysr, jcoomes
author tonyp
date Tue, 07 Dec 2010 16:47:42 -0500
parents d9310331a29c
children 459fad165e5e
files src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp src/share/vm/runtime/globals.hpp
diffstat 6 files changed, 77 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Dec 02 13:20:39 2010 -0500
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Tue Dec 07 16:47:42 2010 -0500
@@ -619,15 +619,19 @@
 HeapWord*
 G1CollectedHeap::replace_cur_alloc_region_and_allocate(size_t word_size,
                                                        bool at_safepoint,
-                                                       bool do_dirtying) {
+                                                       bool do_dirtying,
+                                                       bool can_expand) {
   assert_heap_locked_or_at_safepoint();
   assert(_cur_alloc_region == NULL,
          "replace_cur_alloc_region_and_allocate() should only be called "
          "after retiring the previous current alloc region");
   assert(SafepointSynchronize::is_at_safepoint() == at_safepoint,
          "at_safepoint and is_at_safepoint() should be a tautology");
-
-  if (!g1_policy()->is_young_list_full()) {
+  assert(!can_expand || g1_policy()->can_expand_young_list(),
+         "we should not call this method with can_expand == true if "
+         "we are not allowed to expand the young gen");
+
+  if (can_expand || !g1_policy()->is_young_list_full()) {
     if (!at_safepoint) {
       // The cleanup operation might update _summary_bytes_used
       // concurrently with this method. So, right now, if we don't
@@ -738,11 +742,26 @@
     }
 
     if (GC_locker::is_active_and_needs_gc()) {
-      // We are locked out of GC because of the GC locker. Right now,
-      // we'll just stall until the GC locker-induced GC
-      // completes. This will be fixed in the near future by extending
-      // the eden while waiting for the GC locker to schedule the GC
-      // (see CR 6994056).
+      // We are locked out of GC because of the GC locker. We can
+      // allocate a new region only if we can expand the young gen.
+
+      if (g1_policy()->can_expand_young_list()) {
+        // Yes, we are allowed to expand the young gen. Let's try to
+        // allocate a new current alloc region.
+
+        HeapWord* result =
+          replace_cur_alloc_region_and_allocate(word_size,
+                                                false, /* at_safepoint */
+                                                true,  /* do_dirtying */
+                                                true   /* can_expand */);
+        if (result != NULL) {
+          assert_heap_not_locked();
+          return result;
+        }
+      }
+      // We could not expand the young gen further (or we could but we
+      // failed to allocate a new region). We'll stall until the GC
+      // locker forces a GC.
 
       // If this thread is not in a jni critical section, we stall
       // the requestor until the critical section has cleared and
@@ -950,7 +969,8 @@
            "at this point we should have no cur alloc region");
     return replace_cur_alloc_region_and_allocate(word_size,
                                                  true, /* at_safepoint */
-                                                 false /* do_dirtying */);
+                                                 false /* do_dirtying */,
+                                                 false /* can_expand */);
   } else {
     return attempt_allocation_humongous(word_size,
                                         true /* at_safepoint */);
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Thu Dec 02 13:20:39 2010 -0500
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Tue Dec 07 16:47:42 2010 -0500
@@ -496,12 +496,15 @@
   inline HeapWord* attempt_allocation(size_t word_size);
 
   // It assumes that the current alloc region has been retired and
-  // tries to allocate a new one. If it's successful, it performs
-  // the allocation out of the new current alloc region and updates
-  // _cur_alloc_region.
+  // tries to allocate a new one. If it's successful, it performs the
+  // allocation out of the new current alloc region and updates
+  // _cur_alloc_region. Normally, it would try to allocate a new
+  // region if the young gen is not full, unless can_expand is true in
+  // which case it would always try to allocate a new region.
   HeapWord* replace_cur_alloc_region_and_allocate(size_t word_size,
                                                   bool at_safepoint,
-                                                  bool do_dirtying);
+                                                  bool do_dirtying,
+                                                  bool can_expand);
 
   // The slow path when we are unable to allocate a new current alloc
   // region to satisfy an allocation request (i.e., when
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Thu Dec 02 13:20:39 2010 -0500
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Tue Dec 07 16:47:42 2010 -0500
@@ -119,8 +119,9 @@
 
   // Try to get a new region and allocate out of it
   HeapWord* result = replace_cur_alloc_region_and_allocate(word_size,
-                                                      false, /* at safepoint */
-                                                      true   /* do_dirtying */);
+                                                     false, /* at_safepoint */
+                                                     true,  /* do_dirtying */
+                                                     false  /* can_expand */);
   if (result != NULL) {
     assert_heap_not_locked();
     return result;
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Thu Dec 02 13:20:39 2010 -0500
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Tue Dec 07 16:47:42 2010 -0500
@@ -479,6 +479,7 @@
   // region before we need to do a collection again.
   size_t min_length = _g1->young_list()->length() + 1;
   _young_list_target_length = MAX2(_young_list_target_length, min_length);
+  calculate_max_gc_locker_expansion();
   calculate_survivors_policy();
 }
 
@@ -2301,6 +2302,21 @@
   };
 }
 
+void G1CollectorPolicy::calculate_max_gc_locker_expansion() {
+  size_t expansion_region_num = 0;
+  if (GCLockerEdenExpansionPercent > 0) {
+    double perc = (double) GCLockerEdenExpansionPercent / 100.0;
+    double expansion_region_num_d = perc * (double) _young_list_target_length;
+    // We use ceiling so that if expansion_region_num_d is > 0.0 (but
+    // less than 1.0) we'll get 1.
+    expansion_region_num = (size_t) ceil(expansion_region_num_d);
+  } else {
+    assert(expansion_region_num == 0, "sanity");
+  }
+  _young_list_max_length = _young_list_target_length + expansion_region_num;
+  assert(_young_list_target_length <= _young_list_max_length, "post-condition");
+}
+
 // Calculates survivor space parameters.
 void G1CollectorPolicy::calculate_survivors_policy()
 {
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp	Thu Dec 02 13:20:39 2010 -0500
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp	Tue Dec 07 16:47:42 2010 -0500
@@ -196,6 +196,10 @@
   size_t _young_list_target_length;
   size_t _young_list_fixed_length;
 
+  // The max number of regions we can extend the eden by while the GC
+  // locker is active. This should be >= _young_list_target_length;
+  size_t _young_list_max_length;
+
   size_t _young_cset_length;
   bool   _last_young_gc_full;
 
@@ -1113,13 +1117,22 @@
 
   bool is_young_list_full() {
     size_t young_list_length = _g1->young_list()->length();
-    size_t young_list_max_length = _young_list_target_length;
+    size_t young_list_target_length = _young_list_target_length;
+    if (G1FixedEdenSize) {
+      young_list_target_length -= _max_survivor_regions;
+    }
+    return young_list_length >= young_list_target_length;
+  }
+
+  bool can_expand_young_list() {
+    size_t young_list_length = _g1->young_list()->length();
+    size_t young_list_max_length = _young_list_max_length;
     if (G1FixedEdenSize) {
       young_list_max_length -= _max_survivor_regions;
     }
+    return young_list_length < young_list_max_length;
+  }
 
-    return young_list_length >= young_list_max_length;
-  }
   void update_region_num(bool young);
 
   bool in_young_gc_mode() {
@@ -1231,6 +1244,8 @@
     _survivors_age_table.merge_par(age_table);
   }
 
+  void calculate_max_gc_locker_expansion();
+
   // Calculates survivor space parameters.
   void calculate_survivors_policy();
 
--- a/src/share/vm/runtime/globals.hpp	Thu Dec 02 13:20:39 2010 -0500
+++ b/src/share/vm/runtime/globals.hpp	Tue Dec 07 16:47:42 2010 -0500
@@ -1403,6 +1403,10 @@
           "The exit of a JNI CS necessitating a scavenge also"              \
           " kicks off a bkgrd concurrent collection")                       \
                                                                             \
+  product(uintx, GCLockerEdenExpansionPercent, 5,                           \
+          "How much the GC can expand the eden by while the GC locker  "    \
+          "is active (as a percentage)")                                    \
+                                                                            \
   develop(bool, UseCMSAdaptiveFreeLists, true,                              \
           "Use Adaptive Free Lists in the CMS generation")                  \
                                                                             \