6557851: CMS: ergonomics defaults are not set with FLAG_SET_ERGO
authorjmasa
Sun, 02 Mar 2008 16:10:12 -0800
changeset 186 32e6c95f8d9b
parent 185 cda2a1eb4be5
child 187 970e734a656b
6557851: CMS: ergonomics defaults are not set with FLAG_SET_ERGO Summary: Default values set by cms ergonomics are set with FLAG_SET_DEFAULT so down stream the values look like the default values and affect how later parameters are set. Set these values with FLAG_SET_ERGO instead and adjust how later parameters are interpreted. Reviewed-by: iveresov, apetrusenko, pbk, ysr
hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp
hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp
hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp
hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp
hotspot/src/share/vm/memory/collectorPolicy.cpp
hotspot/src/share/vm/memory/collectorPolicy.hpp
hotspot/src/share/vm/runtime/arguments.cpp
hotspot/src/share/vm/runtime/globals.cpp
hotspot/src/share/vm/runtime/globals_extension.hpp
--- a/hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp	Sun Mar 02 16:10:12 2008 -0800
@@ -74,8 +74,8 @@
 #ifdef SHRINKS_AT_END_OF_EDEN
   size_t delta_in_survivor = 0;
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
-  const size_t space_alignment = heap->intra_generation_alignment();
-  const size_t gen_alignment = heap->generation_alignment();
+  const size_t space_alignment = heap->intra_heap_alignment();
+  const size_t gen_alignment = heap->object_heap_alignment();
 
   MutableSpace* space_shrinking = NULL;
   if (from_space()->end() > to_space()->end()) {
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp	Sun Mar 02 16:10:12 2008 -0800
@@ -86,7 +86,7 @@
   if (eden_space()->is_empty()) {
     // Respect the minimum size for eden and for the young gen as a whole.
     ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
-    const size_t eden_alignment = heap->intra_generation_alignment();
+    const size_t eden_alignment = heap->intra_heap_alignment();
     const size_t gen_alignment = heap->young_gen_alignment();
 
     assert(eden_space()->capacity_in_bytes() >= eden_alignment,
@@ -124,7 +124,7 @@
 // to_space can be.
 size_t ASPSYoungGen::available_to_live() {
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
-  const size_t alignment = heap->intra_generation_alignment();
+  const size_t alignment = heap->intra_heap_alignment();
 
   // Include any space that is committed but is not in eden.
   size_t available = pointer_delta(eden_space()->bottom(),
@@ -275,7 +275,7 @@
   assert(eden_start < from_start, "Cannot push into from_space");
 
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
-  const size_t alignment = heap->intra_generation_alignment();
+  const size_t alignment = heap->intra_heap_alignment();
 
   // Check whether from space is below to space
   if (from_start < to_start) {
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Sun Mar 02 16:10:12 2008 -0800
@@ -173,7 +173,7 @@
     new PSAdaptiveSizePolicy(eden_capacity,
                              initial_promo_size,
                              young_gen()->to_space()->capacity_in_bytes(),
-                             intra_generation_alignment(),
+                             intra_heap_alignment(),
                              max_gc_pause_sec,
                              max_gc_minor_pause_sec,
                              GCTimeRatio
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Sun Mar 02 16:10:12 2008 -0800
@@ -58,9 +58,9 @@
 
  public:
   ParallelScavengeHeap() : CollectedHeap() {
-    set_alignment(_perm_gen_alignment, intra_generation_alignment());
-    set_alignment(_young_gen_alignment, intra_generation_alignment());
-    set_alignment(_old_gen_alignment, intra_generation_alignment());
+    set_alignment(_perm_gen_alignment, intra_heap_alignment());
+    set_alignment(_young_gen_alignment, intra_heap_alignment());
+    set_alignment(_old_gen_alignment, intra_heap_alignment());
   }
 
   // For use by VM operations
@@ -92,14 +92,14 @@
 
   void post_initialize();
   void update_counters();
-
   // The alignment used for the various generations.
   size_t perm_gen_alignment()  const { return _perm_gen_alignment; }
   size_t young_gen_alignment() const { return _young_gen_alignment; }
   size_t old_gen_alignment()  const { return _old_gen_alignment; }
 
-  // The alignment used for eden and survivors within the young gen.
-  size_t intra_generation_alignment() const { return 64 * K; }
+  // The alignment used for eden and survivors within the young gen
+  // and for boundary between young gen and old gen.
+  size_t intra_heap_alignment() const { return 64 * K; }
 
   size_t capacity() const;
   size_t used() const;
@@ -217,6 +217,6 @@
 inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val)
 {
   assert(is_power_of_2((intptr_t)val), "must be a power of 2");
-  var = round_to(val, intra_generation_alignment());
+  var = round_to(val, intra_heap_alignment());
   return var;
 }
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Sun Mar 02 16:10:12 2008 -0800
@@ -88,7 +88,7 @@
 
   // Compute maximum space sizes for performance counters
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
-  size_t alignment = heap->intra_generation_alignment();
+  size_t alignment = heap->intra_heap_alignment();
   size_t size = _virtual_space->reserved_size();
 
   size_t max_survivor_size;
@@ -141,7 +141,7 @@
   assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
 
   // Compute sizes
-  size_t alignment = heap->intra_generation_alignment();
+  size_t alignment = heap->intra_heap_alignment();
   size_t size = _virtual_space->committed_size();
 
   size_t survivor_size = size / InitialSurvivorRatio;
@@ -192,7 +192,7 @@
 #ifndef PRODUCT
 void PSYoungGen::space_invariants() {
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
-  const size_t alignment = heap->intra_generation_alignment();
+  const size_t alignment = heap->intra_heap_alignment();
 
   // Currently, our eden size cannot shrink to zero
   guarantee(eden_space()->capacity_in_bytes() >= alignment, "eden too small");
@@ -392,7 +392,7 @@
   char* to_end     = (char*)to_space()->end();
 
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
-  const size_t alignment = heap->intra_generation_alignment();
+  const size_t alignment = heap->intra_heap_alignment();
   const bool maintain_minimum =
     (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size();
 
@@ -708,7 +708,7 @@
 size_t PSYoungGen::available_to_live() {
   size_t delta_in_survivor = 0;
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
-  const size_t space_alignment = heap->intra_generation_alignment();
+  const size_t space_alignment = heap->intra_heap_alignment();
   const size_t gen_alignment = heap->young_gen_alignment();
 
   MutableSpace* space_shrinking = NULL;
--- a/hotspot/src/share/vm/memory/collectorPolicy.cpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp	Sun Mar 02 16:10:12 2008 -0800
@@ -57,45 +57,51 @@
   // User inputs from -mx and ms are aligned
   _initial_heap_byte_size = align_size_up(Arguments::initial_heap_size(),
                                           min_alignment());
-  _min_heap_byte_size = align_size_up(Arguments::min_heap_size(),
-                                          min_alignment());
-  _max_heap_byte_size = align_size_up(MaxHeapSize, max_alignment());
+  set_min_heap_byte_size(align_size_up(Arguments::min_heap_size(),
+                                          min_alignment()));
+  set_max_heap_byte_size(align_size_up(MaxHeapSize, max_alignment()));
 
   // Check validity of heap parameters from launcher
-  if (_initial_heap_byte_size == 0) {
-    _initial_heap_byte_size = NewSize + OldSize;
+  if (initial_heap_byte_size() == 0) {
+    set_initial_heap_byte_size(NewSize + OldSize);
   } else {
-    Universe::check_alignment(_initial_heap_byte_size, min_alignment(),
+    Universe::check_alignment(initial_heap_byte_size(), min_alignment(),
                             "initial heap");
   }
-  if (_min_heap_byte_size == 0) {
-    _min_heap_byte_size = NewSize + OldSize;
+  if (min_heap_byte_size() == 0) {
+    set_min_heap_byte_size(NewSize + OldSize);
   } else {
-    Universe::check_alignment(_min_heap_byte_size, min_alignment(),
+    Universe::check_alignment(min_heap_byte_size(), min_alignment(),
                             "initial heap");
   }
 
   // Check heap parameter properties
-  if (_initial_heap_byte_size < M) {
+  if (initial_heap_byte_size() < M) {
     vm_exit_during_initialization("Too small initial heap");
   }
   // Check heap parameter properties
-  if (_min_heap_byte_size < M) {
+  if (min_heap_byte_size() < M) {
     vm_exit_during_initialization("Too small minimum heap");
   }
-  if (_initial_heap_byte_size <= NewSize) {
+  if (initial_heap_byte_size() <= NewSize) {
      // make sure there is at least some room in old space
     vm_exit_during_initialization("Too small initial heap for new size specified");
   }
-  if (_max_heap_byte_size < _min_heap_byte_size) {
+  if (max_heap_byte_size() < min_heap_byte_size()) {
     vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified");
   }
-  if (_initial_heap_byte_size < _min_heap_byte_size) {
+  if (initial_heap_byte_size() < min_heap_byte_size()) {
     vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified");
   }
-  if (_max_heap_byte_size < _initial_heap_byte_size) {
+  if (max_heap_byte_size() < initial_heap_byte_size()) {
     vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified");
   }
+
+  if (PrintGCDetails && Verbose) {
+    gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT "  Initial heap "
+      SIZE_FORMAT "  Maximum heap " SIZE_FORMAT,
+      min_heap_byte_size(), initial_heap_byte_size(), max_heap_byte_size());
+  }
 }
 
 void CollectorPolicy::initialize_perm_generation(PermGen::Name pgnm) {
@@ -128,10 +134,26 @@
 
 // GenCollectorPolicy methods.
 
+size_t GenCollectorPolicy::scale_by_NewRatio_aligned(size_t base_size) {
+  size_t x = base_size / (NewRatio+1);
+  size_t new_gen_size = x > min_alignment() ?
+                     align_size_down(x, min_alignment()) :
+                     min_alignment();
+  return new_gen_size;
+}
+
+size_t GenCollectorPolicy::bound_minus_alignment(size_t desired_size,
+                                                 size_t maximum_size) {
+  size_t alignment = min_alignment();
+  size_t max_minus = maximum_size - alignment;
+  return desired_size < max_minus ? desired_size : max_minus;
+}
+
+
 void GenCollectorPolicy::initialize_size_policy(size_t init_eden_size,
                                                 size_t init_promo_size,
                                                 size_t init_survivor_size) {
-  double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0;
+  const double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0;
   _size_policy = new AdaptiveSizePolicy(init_eden_size,
                                         init_promo_size,
                                         init_survivor_size,
@@ -210,74 +232,260 @@
   assert(MaxHeapSize % max_alignment() == 0, "maximum heap alignment");
 }
 
+// Values set on the command line win over any ergonomically
+// set command line parameters.
+// Ergonomic choice of parameters are done before this
+// method is called.  Values for command line parameters such as NewSize
+// and MaxNewSize feed those ergonomic choices into this method.
+// This method makes the final generation sizings consistent with
+// themselves and with overall heap sizings.
+// In the absence of explicitly set command line flags, policies
+// such as the use of NewRatio are used to size the generation.
 void GenCollectorPolicy::initialize_size_info() {
   CollectorPolicy::initialize_size_info();
 
-  // Minimum sizes of the generations may be different than
-  // the initial sizes.
-  if (!FLAG_IS_DEFAULT(NewSize)) {
-    _min_gen0_size = NewSize;
+  // min_alignment() is used for alignment within a generation.
+  // There is additional alignment done down stream for some
+  // collectors that sometimes causes unwanted rounding up of
+  // generations sizes.
+
+  // Determine maximum size of gen0
+
+  size_t max_new_size = 0;
+  if (FLAG_IS_CMDLINE(MaxNewSize)) {
+    if (MaxNewSize < min_alignment()) {
+      max_new_size = min_alignment();
+    } else if (MaxNewSize >= max_heap_byte_size()) {
+      max_new_size = align_size_down(max_heap_byte_size() - min_alignment(),
+                                     min_alignment());
+      warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or "
+        "greater than the entire heap (" SIZE_FORMAT "k).  A "
+        "new generation size of " SIZE_FORMAT "k will be used.",
+        MaxNewSize/K, max_heap_byte_size()/K, max_new_size/K);
+    } else {
+      max_new_size = align_size_down(MaxNewSize, min_alignment());
+    }
+
+  // The case for FLAG_IS_ERGO(MaxNewSize) could be treated
+  // specially at this point to just use an ergonomically set
+  // MaxNewSize to set max_new_size.  For cases with small
+  // heaps such a policy often did not work because the MaxNewSize
+  // was larger than the entire heap.  The interpretation given
+  // to ergonomically set flags is that the flags are set
+  // by different collectors for their own special needs but
+  // are not allowed to badly shape the heap.  This allows the
+  // different collectors to decide what's best for themselves
+  // without having to factor in the overall heap shape.  It
+  // can be the case in the future that the collectors would
+  // only make "wise" ergonomics choices and this policy could
+  // just accept those choices.  The choices currently made are
+  // not always "wise".
   } else {
-    _min_gen0_size = align_size_down(_min_heap_byte_size / (NewRatio+1),
-                                     min_alignment());
-    // We bound the minimum size by NewSize below (since it historically
+    max_new_size = scale_by_NewRatio_aligned(max_heap_byte_size());
+    // Bound the maximum size by NewSize below (since it historically
     // would have been NewSize and because the NewRatio calculation could
     // yield a size that is too small) and bound it by MaxNewSize above.
-    // This is not always best.  The NewSize calculated by CMS (which has
-    // a fixed minimum of 16m) can sometimes be "too" large.  Consider
-    // the case where -Xmx32m.  The CMS calculated NewSize would be about
-    // half the entire heap which seems too large.  But the counter
-    // example is seen when the client defaults for NewRatio are used.
-    // An initial young generation size of 640k was observed
-    // with -Xmx128m -XX:MaxNewSize=32m when NewSize was not used
-    // as a lower bound as with
-    // _min_gen0_size = MIN2(_min_gen0_size, MaxNewSize);
-    // and 640k seemed too small a young generation.
-    _min_gen0_size = MIN2(MAX2(_min_gen0_size, NewSize), MaxNewSize);
+    // Ergonomics plays here by previously calculating the desired
+    // NewSize and MaxNewSize.
+    max_new_size = MIN2(MAX2(max_new_size, NewSize), MaxNewSize);
+  }
+  assert(max_new_size > 0, "All paths should set max_new_size");
+
+  // Given the maximum gen0 size, determine the initial and
+  // minimum sizes.
+
+  if (max_heap_byte_size() == min_heap_byte_size()) {
+    // The maximum and minimum heap sizes are the same so
+    // the generations minimum and initial must be the
+    // same as its maximum.
+    set_min_gen0_size(max_new_size);
+    set_initial_gen0_size(max_new_size);
+    set_max_gen0_size(max_new_size);
+  } else {
+    size_t desired_new_size = 0;
+    if (!FLAG_IS_DEFAULT(NewSize)) {
+      // If NewSize is set ergonomically (for example by cms), it
+      // would make sense to use it.  If it is used, also use it
+      // to set the initial size.  Although there is no reason
+      // the minimum size and the initial size have to be the same,
+      // the current implementation gets into trouble during the calculation
+      // of the tenured generation sizes if they are different.
+      // Note that this makes the initial size and the minimum size
+      // generally small compared to the NewRatio calculation.
+      _min_gen0_size = NewSize;
+      desired_new_size = NewSize;
+      max_new_size = MAX2(max_new_size, NewSize);
+    } else {
+      // For the case where NewSize is the default, use NewRatio
+      // to size the minimum and initial generation sizes.
+      // Use the default NewSize as the floor for these values.  If
+      // NewRatio is overly large, the resulting sizes can be too
+      // small.
+      _min_gen0_size = MAX2(scale_by_NewRatio_aligned(min_heap_byte_size()),
+                          NewSize);
+      desired_new_size =
+        MAX2(scale_by_NewRatio_aligned(initial_heap_byte_size()),
+             NewSize);
+    }
+
+    assert(_min_gen0_size > 0, "Sanity check");
+    set_initial_gen0_size(desired_new_size);
+    set_max_gen0_size(max_new_size);
+
+    // At this point the desirable initial and minimum sizes have been
+    // determined without regard to the maximum sizes.
+
+    // Bound the sizes by the corresponding overall heap sizes.
+    set_min_gen0_size(
+      bound_minus_alignment(_min_gen0_size, min_heap_byte_size()));
+    set_initial_gen0_size(
+      bound_minus_alignment(_initial_gen0_size, initial_heap_byte_size()));
+    set_max_gen0_size(
+      bound_minus_alignment(_max_gen0_size, max_heap_byte_size()));
+
+    // At this point all three sizes have been checked against the
+    // maximum sizes but have not been checked for consistency
+    // amoung the three.
+
+    // Final check min <= initial <= max
+    set_min_gen0_size(MIN2(_min_gen0_size, _max_gen0_size));
+    set_initial_gen0_size(
+      MAX2(MIN2(_initial_gen0_size, _max_gen0_size), _min_gen0_size));
+    set_min_gen0_size(MIN2(_min_gen0_size, _initial_gen0_size));
   }
 
-  // Parameters are valid, compute area sizes.
-  size_t max_new_size = align_size_down(_max_heap_byte_size / (NewRatio+1),
-                                        min_alignment());
-  max_new_size = MIN2(MAX2(max_new_size, _min_gen0_size), MaxNewSize);
+  if (PrintGCDetails && Verbose) {
+    gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT "  Initial gen0 "
+      SIZE_FORMAT "  Maximum gen0 " SIZE_FORMAT,
+      min_gen0_size(), initial_gen0_size(), max_gen0_size());
+  }
+}
 
-  // desired_new_size is used to set the initial size.  The
-  // initial size must be greater than the minimum size.
-  size_t desired_new_size =
-    align_size_down(_initial_heap_byte_size / (NewRatio+1),
-                  min_alignment());
+// Call this method during the sizing of the gen1 to make
+// adjustments to gen0 because of gen1 sizing policy.  gen0 initially has
+// the most freedom in sizing because it is done before the
+// policy for gen1 is applied.  Once gen1 policies have been applied,
+// there may be conflicts in the shape of the heap and this method
+// is used to make the needed adjustments.  The application of the
+// policies could be more sophisticated (iterative for example) but
+// keeping it simple also seems a worthwhile goal.
+bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr,
+                                                     size_t* gen1_size_ptr,
+                                                     size_t heap_size,
+                                                     size_t min_gen0_size) {
+  bool result = false;
+  if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) {
+    if (((*gen0_size_ptr + OldSize) > heap_size) &&
+       (heap_size - min_gen0_size) >= min_alignment()) {
+      // Adjust gen0 down to accomodate OldSize
+      *gen0_size_ptr = heap_size - min_gen0_size;
+      *gen0_size_ptr =
+        MAX2((uintx)align_size_down(*gen0_size_ptr, min_alignment()),
+             min_alignment());
+      assert(*gen0_size_ptr > 0, "Min gen0 is too large");
+      result = true;
+    } else {
+      *gen1_size_ptr = heap_size - *gen0_size_ptr;
+      *gen1_size_ptr =
+        MAX2((uintx)align_size_down(*gen1_size_ptr, min_alignment()),
+                       min_alignment());
+    }
+  }
+  return result;
+}
 
-  size_t new_size = MIN2(MAX2(desired_new_size, _min_gen0_size), max_new_size);
-
-  _initial_gen0_size = new_size;
-  _max_gen0_size = max_new_size;
-}
+// Minimum sizes of the generations may be different than
+// the initial sizes.  An inconsistently is permitted here
+// in the total size that can be specified explicitly by
+// command line specification of OldSize and NewSize and
+// also a command line specification of -Xms.  Issue a warning
+// but allow the values to pass.
 
 void TwoGenerationCollectorPolicy::initialize_size_info() {
   GenCollectorPolicy::initialize_size_info();
 
-  // Minimum sizes of the generations may be different than
-  // the initial sizes.  An inconsistently is permitted here
-  // in the total size that can be specified explicitly by
-  // command line specification of OldSize and NewSize and
-  // also a command line specification of -Xms.  Issue a warning
-  // but allow the values to pass.
-  if (!FLAG_IS_DEFAULT(OldSize)) {
-    _min_gen1_size = OldSize;
+  // At this point the minimum, initial and maximum sizes
+  // of the overall heap and of gen0 have been determined.
+  // The maximum gen1 size can be determined from the maximum gen0
+  // and maximum heap size since not explicit flags exits
+  // for setting the gen1 maximum.
+  _max_gen1_size = max_heap_byte_size() - _max_gen0_size;
+  _max_gen1_size =
+    MAX2((uintx)align_size_down(_max_gen1_size, min_alignment()),
+         min_alignment());
+  // If no explicit command line flag has been set for the
+  // gen1 size, use what is left for gen1.
+  if (FLAG_IS_DEFAULT(OldSize) || FLAG_IS_ERGO(OldSize)) {
+    // The user has not specified any value or ergonomics
+    // has chosen a value (which may or may not be consistent
+    // with the overall heap size).  In either case make
+    // the minimum, maximum and initial sizes consistent
+    // with the gen0 sizes and the overall heap sizes.
+    assert(min_heap_byte_size() > _min_gen0_size,
+      "gen0 has an unexpected minimum size");
+    set_min_gen1_size(min_heap_byte_size() - min_gen0_size());
+    set_min_gen1_size(
+      MAX2((uintx)align_size_down(_min_gen1_size, min_alignment()),
+           min_alignment()));
+    set_initial_gen1_size(initial_heap_byte_size() - initial_gen0_size());
+    set_initial_gen1_size(
+      MAX2((uintx)align_size_down(_initial_gen1_size, min_alignment()),
+           min_alignment()));
+
+  } else {
+    // It's been explicitly set on the command line.  Use the
+    // OldSize and then determine the consequences.
+    set_min_gen1_size(OldSize);
+    set_initial_gen1_size(OldSize);
+
+    // If the user has explicitly set an OldSize that is inconsistent
+    // with other command line flags, issue a warning.
     // The generation minimums and the overall heap mimimum should
     // be within one heap alignment.
-    if ((_min_gen1_size + _min_gen0_size + max_alignment()) <
-         _min_heap_byte_size) {
+    if ((_min_gen1_size + _min_gen0_size + min_alignment()) <
+           min_heap_byte_size()) {
       warning("Inconsistency between minimum heap size and minimum "
-        "generation sizes: using min heap = " SIZE_FORMAT,
-        _min_heap_byte_size);
+          "generation sizes: using minimum heap = " SIZE_FORMAT,
+          min_heap_byte_size());
+    }
+    if ((OldSize > _max_gen1_size)) {
+      warning("Inconsistency between maximum heap size and maximum "
+          "generation sizes: using maximum heap = " SIZE_FORMAT
+          " -XX:OldSize flag is being ignored",
+          max_heap_byte_size());
+  }
+    // If there is an inconsistency between the OldSize and the minimum and/or
+    // initial size of gen0, since OldSize was explicitly set, OldSize wins.
+    if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size,
+                          min_heap_byte_size(), OldSize)) {
+      if (PrintGCDetails && Verbose) {
+        gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT "  Initial gen0 "
+              SIZE_FORMAT "  Maximum gen0 " SIZE_FORMAT,
+              min_gen0_size(), initial_gen0_size(), max_gen0_size());
+      }
     }
-  } else {
-    _min_gen1_size = _min_heap_byte_size - _min_gen0_size;
+    // Initial size
+    if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size,
+                         initial_heap_byte_size(), OldSize)) {
+      if (PrintGCDetails && Verbose) {
+        gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT "  Initial gen0 "
+          SIZE_FORMAT "  Maximum gen0 " SIZE_FORMAT,
+          min_gen0_size(), initial_gen0_size(), max_gen0_size());
+      }
+    }
   }
+  // Enforce the maximum gen1 size.
+  set_min_gen1_size(MIN2(_min_gen1_size, _max_gen1_size));
 
-  _initial_gen1_size = _initial_heap_byte_size - _initial_gen0_size;
-  _max_gen1_size = _max_heap_byte_size - _max_gen0_size;
+  // Check that min gen1 <= initial gen1 <= max gen1
+  set_initial_gen1_size(MAX2(_initial_gen1_size, _min_gen1_size));
+  set_initial_gen1_size(MIN2(_initial_gen1_size, _max_gen1_size));
+
+  if (PrintGCDetails && Verbose) {
+    gclog_or_tty->print_cr("Minimum gen1 " SIZE_FORMAT "  Initial gen1 "
+      SIZE_FORMAT "  Maximum gen1 " SIZE_FORMAT,
+      min_gen1_size(), initial_gen1_size(), max_gen1_size());
+  }
 }
 
 HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size,
--- a/hotspot/src/share/vm/memory/collectorPolicy.hpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/memory/collectorPolicy.hpp	Sun Mar 02 16:10:12 2008 -0800
@@ -82,8 +82,11 @@
   size_t max_alignment()                       { return _max_alignment; }
 
   size_t initial_heap_byte_size() { return _initial_heap_byte_size; }
+  void set_initial_heap_byte_size(size_t v) { _initial_heap_byte_size = v; }
   size_t max_heap_byte_size()     { return _max_heap_byte_size; }
+  void set_max_heap_byte_size(size_t v) { _max_heap_byte_size = v; }
   size_t min_heap_byte_size()     { return _min_heap_byte_size; }
+  void set_min_heap_byte_size(size_t v) { _min_heap_byte_size = v; }
 
   enum Name {
     CollectorPolicyKind,
@@ -182,8 +185,24 @@
   // compute max heap alignment
   size_t compute_max_alignment();
 
+ // Scale the base_size by NewRation according to
+ //     result = base_size / (NewRatio + 1)
+ // and align by min_alignment()
+ size_t scale_by_NewRatio_aligned(size_t base_size);
+
+ // Bound the value by the given maximum minus the
+ // min_alignment.
+ size_t bound_minus_alignment(size_t desired_size, size_t maximum_size);
 
  public:
+  // Accessors
+  size_t min_gen0_size() { return _min_gen0_size; }
+  void set_min_gen0_size(size_t v) { _min_gen0_size = v; }
+  size_t initial_gen0_size() { return _initial_gen0_size; }
+  void set_initial_gen0_size(size_t v) { _initial_gen0_size = v; }
+  size_t max_gen0_size() { return _max_gen0_size; }
+  void set_max_gen0_size(size_t v) { _max_gen0_size = v; }
+
   virtual int number_of_generations() = 0;
 
   virtual GenerationSpec **generations()       {
@@ -236,6 +255,14 @@
   void initialize_generations()                { ShouldNotReachHere(); }
 
  public:
+  // Accessors
+  size_t min_gen1_size() { return _min_gen1_size; }
+  void set_min_gen1_size(size_t v) { _min_gen1_size = v; }
+  size_t initial_gen1_size() { return _initial_gen1_size; }
+  void set_initial_gen1_size(size_t v) { _initial_gen1_size = v; }
+  size_t max_gen1_size() { return _max_gen1_size; }
+  void set_max_gen1_size(size_t v) { _max_gen1_size = v; }
+
   // Inherited methods
   TwoGenerationCollectorPolicy* as_two_generation_policy() { return this; }
 
@@ -246,6 +273,10 @@
   virtual CollectorPolicy::Name kind() {
     return CollectorPolicy::TwoGenerationCollectorPolicyKind;
   }
+
+  // Returns true is gen0 sizes were adjusted
+  bool adjust_gen0_sizes(size_t* gen0_size_ptr, size_t* gen1_size_ptr,
+                               size_t heap_size, size_t min_gen1_size);
 };
 
 class MarkSweepPolicy : public TwoGenerationCollectorPolicy {
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Sun Mar 02 16:10:12 2008 -0800
@@ -1000,7 +1000,7 @@
   intx tenuring_default;
   if (CMSUseOldDefaults) {  // old defaults: "old" as of 6.0
     if FLAG_IS_DEFAULT(CMSYoungGenPerWorker) {
-      FLAG_SET_DEFAULT(CMSYoungGenPerWorker, 4*M);
+      FLAG_SET_ERGO(intx, CMSYoungGenPerWorker, 4*M);
     }
     young_gen_per_worker = 4*M;
     new_ratio = (intx)15;
@@ -1025,16 +1025,20 @@
   // for "short" pauses ~ 4M*ParallelGCThreads
   if (FLAG_IS_DEFAULT(MaxNewSize)) {  // MaxNewSize not set at command-line
     if (!FLAG_IS_DEFAULT(NewSize)) {   // NewSize explicitly set at command-line
-      FLAG_SET_DEFAULT(MaxNewSize, MAX2(NewSize, preferred_max_new_size));
+      FLAG_SET_ERGO(uintx, MaxNewSize, MAX2(NewSize, preferred_max_new_size));
     } else {
-      FLAG_SET_DEFAULT(MaxNewSize, preferred_max_new_size);
+      FLAG_SET_ERGO(uintx, MaxNewSize, preferred_max_new_size);
     }
+    if(PrintGCDetails && Verbose) {
+      // Too early to use gclog_or_tty
+      tty->print_cr("Ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize);
+  }
   }
   // Unless explicitly requested otherwise, prefer a large
   // Old to Young gen size so as to shift the collection load
   // to the old generation concurrent collector
   if (FLAG_IS_DEFAULT(NewRatio)) {
-    FLAG_SET_DEFAULT(NewRatio, MAX2(NewRatio, new_ratio));
+    FLAG_SET_ERGO(intx, NewRatio, MAX2(NewRatio, new_ratio));
 
     size_t min_new  = align_size_up(ScaleForWordSize(min_new_default), os::vm_page_size());
     size_t prev_initial_size = initial_heap_size();
@@ -1052,19 +1056,34 @@
     size_t max_heap = align_size_down(MaxHeapSize,
                                       CardTableRS::ct_max_alignment_constraint());
 
+    if(PrintGCDetails && Verbose) {
+      // Too early to use gclog_or_tty
+      tty->print_cr("CMS set min_heap_size: " SIZE_FORMAT
+           " initial_heap_size:  " SIZE_FORMAT
+           " max_heap: " SIZE_FORMAT,
+           min_heap_size(), initial_heap_size(), max_heap);
+    }
     if (max_heap > min_new) {
       // Unless explicitly requested otherwise, make young gen
       // at least min_new, and at most preferred_max_new_size.
       if (FLAG_IS_DEFAULT(NewSize)) {
-        FLAG_SET_DEFAULT(NewSize, MAX2(NewSize, min_new));
-        FLAG_SET_DEFAULT(NewSize, MIN2(preferred_max_new_size, NewSize));
+        FLAG_SET_ERGO(uintx, NewSize, MAX2(NewSize, min_new));
+        FLAG_SET_ERGO(uintx, NewSize, MIN2(preferred_max_new_size, NewSize));
+        if(PrintGCDetails && Verbose) {
+          // Too early to use gclog_or_tty
+          tty->print_cr("Ergo set NewSize: " SIZE_FORMAT, NewSize);
+        }
       }
       // Unless explicitly requested otherwise, size old gen
       // so that it's at least 3X of NewSize to begin with;
       // later NewRatio will decide how it grows; see above.
       if (FLAG_IS_DEFAULT(OldSize)) {
         if (max_heap > NewSize) {
-          FLAG_SET_DEFAULT(OldSize, MIN2(3*NewSize,  max_heap - NewSize));
+          FLAG_SET_ERGO(uintx, OldSize, MIN2(3*NewSize,  max_heap - NewSize));
+          if(PrintGCDetails && Verbose) {
+            // Too early to use gclog_or_tty
+            tty->print_cr("Ergo set OldSize: " SIZE_FORMAT, OldSize);
+          }
         }
       }
     }
@@ -1073,14 +1092,14 @@
   // promote all objects surviving "tenuring_default" scavenges.
   if (FLAG_IS_DEFAULT(MaxTenuringThreshold) &&
       FLAG_IS_DEFAULT(SurvivorRatio)) {
-    FLAG_SET_DEFAULT(MaxTenuringThreshold, tenuring_default);
+    FLAG_SET_ERGO(intx, MaxTenuringThreshold, tenuring_default);
   }
   // If we decided above (or user explicitly requested)
   // `promote all' (via MaxTenuringThreshold := 0),
   // prefer minuscule survivor spaces so as not to waste
   // space for (non-existent) survivors
   if (FLAG_IS_DEFAULT(SurvivorRatio) && MaxTenuringThreshold == 0) {
-    FLAG_SET_DEFAULT(SurvivorRatio, MAX2((intx)1024, SurvivorRatio));
+    FLAG_SET_ERGO(intx, SurvivorRatio, MAX2((intx)1024, SurvivorRatio));
   }
   // If OldPLABSize is set and CMSParPromoteBlocksToClaim is not,
   // set CMSParPromoteBlocksToClaim equal to OldPLABSize.
@@ -1089,7 +1108,11 @@
   // See CR 6362902.
   if (!FLAG_IS_DEFAULT(OldPLABSize)) {
     if (FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim)) {
-      FLAG_SET_CMDLINE(uintx, CMSParPromoteBlocksToClaim, OldPLABSize);
+      // OldPLABSize is not the default value but CMSParPromoteBlocksToClaim
+      // is.  In this situtation let CMSParPromoteBlocksToClaim follow
+      // the value (either from the command line or ergonomics) of
+      // OldPLABSize.  Following OldPLABSize is an ergonomics decision.
+      FLAG_SET_ERGO(uintx, CMSParPromoteBlocksToClaim, OldPLABSize);
     }
     else {
       // OldPLABSize and CMSParPromoteBlocksToClaim are both set.
@@ -1211,12 +1234,13 @@
 
     if (UseParallelOldGC) {
       // Par compact uses lower default values since they are treated as
-      // minimums.
+      // minimums.  These are different defaults because of the different
+      // interpretation and are not ergonomically set.
       if (FLAG_IS_DEFAULT(MarkSweepDeadRatio)) {
-        MarkSweepDeadRatio = 1;
+        FLAG_SET_DEFAULT(MarkSweepDeadRatio, 1);
       }
       if (FLAG_IS_DEFAULT(PermMarkSweepDeadRatio)) {
-        PermMarkSweepDeadRatio = 5;
+        FLAG_SET_DEFAULT(PermMarkSweepDeadRatio, 5);
       }
     }
   }
@@ -2452,7 +2476,7 @@
     return JNI_EINVAL;
   }
 
-  if (UseParallelGC) {
+  if (UseParallelGC || UseParallelOldGC) {
     // Set some flags for ParallelGC if needed.
     set_parallel_gc_flags();
   } else if (UseConcMarkSweepGC) {
--- a/hotspot/src/share/vm/runtime/globals.cpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/runtime/globals.cpp	Sun Mar 02 16:10:12 2008 -0800
@@ -205,6 +205,18 @@
   return (f->origin == DEFAULT);
 }
 
+bool CommandLineFlagsEx::is_ergo(CommandLineFlag flag) {
+  assert((size_t)flag < Flag::numFlags, "bad command line flag index");
+  Flag* f = &Flag::flags[flag];
+  return (f->origin == ERGONOMIC);
+}
+
+bool CommandLineFlagsEx::is_cmdline(CommandLineFlag flag) {
+  assert((size_t)flag < Flag::numFlags, "bad command line flag index");
+  Flag* f = &Flag::flags[flag];
+  return (f->origin == COMMAND_LINE);
+}
+
 bool CommandLineFlags::wasSetOnCmdline(const char* name, bool* value) {
   Flag* result = Flag::find_flag((char*)name, strlen(name));
   if (result == NULL) return false;
--- a/hotspot/src/share/vm/runtime/globals_extension.hpp	Fri Feb 29 14:42:56 2008 -0800
+++ b/hotspot/src/share/vm/runtime/globals_extension.hpp	Sun Mar 02 16:10:12 2008 -0800
@@ -154,6 +154,8 @@
 } CommandLineFlagWithType;
 
 #define FLAG_IS_DEFAULT(name)         (CommandLineFlagsEx::is_default(FLAG_MEMBER(name)))
+#define FLAG_IS_ERGO(name)            (CommandLineFlagsEx::is_ergo(FLAG_MEMBER(name)))
+#define FLAG_IS_CMDLINE(name)         (CommandLineFlagsEx::is_cmdline(FLAG_MEMBER(name)))
 
 #define FLAG_SET_DEFAULT(name, value) ((name) = (value))
 
@@ -171,4 +173,6 @@
   static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, FlagValueOrigin origin);
 
   static bool is_default(CommandLineFlag flag);
+  static bool is_ergo(CommandLineFlag flag);
+  static bool is_cmdline(CommandLineFlag flag);
 };