1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "gc/shared/genArguments.hpp"
  27 #include "gc/shared/genSettings.hpp"
  28 #include "logging/log.hpp"
  29 #include "runtime/globals_extension.hpp"
  30 #include "runtime/java.hpp"
  31 #include "utilities/align.hpp"
  32 #include "utilities/globalDefinitions.hpp"
  33 
  34 static size_t young_gen_size_lower_bound(const GenSettings& s) {
  35   // The young generation must be aligned and have room for eden + two survivors
  36   return align_up(3 * s._space_alignment, s._gen_alignment);
  37 }
  38 
  39 static size_t old_gen_size_lower_bound(const GenSettings& s) {
  40   return align_up(s._space_alignment, s._gen_alignment);
  41 }
  42 
  43 static size_t scale_by_NewRatio_aligned(size_t base_size, size_t alignment) {
  44   return align_down_bounded(base_size / (NewRatio + 1), alignment);
  45 }
  46 
  47 static size_t bound_minus_alignment(size_t desired_size,
  48                                     size_t maximum_size,
  49                                     size_t alignment) {
  50   size_t max_minus = maximum_size - alignment;
  51   return desired_size < max_minus ? desired_size : max_minus;
  52 }
  53 
  54 void GenArguments::initialize_heap_flags(GenSettings& s) {
  55   GCArguments::initialize_heap_flags(s);
  56 
  57   assert(s._gen_alignment != 0, "Generation alignment not set up properly");
  58   assert(s._heap_alignment >= s._gen_alignment,
  59          "heap_alignment: " SIZE_FORMAT " less than gen_alignment: " SIZE_FORMAT,
  60          s._heap_alignment, s._gen_alignment);
  61   assert(s._gen_alignment % s._space_alignment == 0,
  62          "gen_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT,
  63          s._gen_alignment, s._space_alignment);
  64   assert(s._heap_alignment % s._gen_alignment == 0,
  65          "heap_alignment: " SIZE_FORMAT " not aligned by gen_alignment: " SIZE_FORMAT,
  66          s._heap_alignment, s._gen_alignment);
  67 
  68   // All generational heaps have a young gen; handle those flags here
  69 
  70   // Make sure the heap is large enough for two generations
  71   size_t smallest_new_size = young_gen_size_lower_bound(s);
  72   size_t smallest_heap_size = align_up(smallest_new_size + old_gen_size_lower_bound(s),
  73                                        s._heap_alignment);
  74   if (MaxHeapSize < smallest_heap_size) {
  75     FLAG_SET_ERGO(size_t, MaxHeapSize, smallest_heap_size);
  76     s._max_heap_byte_size = MaxHeapSize;
  77   }
  78   // If needed, synchronize _min_heap_byte size and _initial_heap_byte_size
  79   if (s._min_heap_byte_size < smallest_heap_size) {
  80     s._min_heap_byte_size = smallest_heap_size;
  81     if (InitialHeapSize < s._min_heap_byte_size) {
  82       FLAG_SET_ERGO(size_t, InitialHeapSize, smallest_heap_size);
  83       s._initial_heap_byte_size = smallest_heap_size;
  84     }
  85   }
  86 
  87   // Make sure NewSize allows an old generation to fit even if set on the command line
  88   if (FLAG_IS_CMDLINE(NewSize) && NewSize >= s._initial_heap_byte_size) {
  89     log_warning(gc, ergo)("NewSize was set larger than initial heap size, will use initial heap size.");
  90     FLAG_SET_ERGO(size_t, NewSize, bound_minus_alignment(NewSize, s._initial_heap_byte_size, s._gen_alignment));
  91   }
  92 
  93   // Now take the actual NewSize into account. We will silently increase NewSize
  94   // if the user specified a smaller or unaligned value.
  95   size_t bounded_new_size = bound_minus_alignment(NewSize, MaxHeapSize, s._gen_alignment);
  96   bounded_new_size = MAX2(smallest_new_size, align_down(bounded_new_size, s._gen_alignment));
  97   if (bounded_new_size != NewSize) {
  98     FLAG_SET_ERGO(size_t, NewSize, bounded_new_size);
  99   }
 100   s._min_young_size = smallest_new_size;
 101   s._initial_young_size = NewSize;
 102 
 103   if (!FLAG_IS_DEFAULT(MaxNewSize)) {
 104     if (MaxNewSize >= MaxHeapSize) {
 105       // Make sure there is room for an old generation
 106       size_t smaller_max_new_size = MaxHeapSize - s._gen_alignment;
 107       if (FLAG_IS_CMDLINE(MaxNewSize)) {
 108         log_warning(gc, ergo)("MaxNewSize (" SIZE_FORMAT "k) is equal to or greater than the entire "
 109                               "heap (" SIZE_FORMAT "k).  A new max generation size of " SIZE_FORMAT "k will be used.",
 110                               MaxNewSize/K, MaxHeapSize/K, smaller_max_new_size/K);
 111       }
 112       FLAG_SET_ERGO(size_t, MaxNewSize, smaller_max_new_size);
 113       if (NewSize > MaxNewSize) {
 114         FLAG_SET_ERGO(size_t, NewSize, MaxNewSize);
 115         s._initial_young_size = NewSize;
 116       }
 117     } else if (MaxNewSize < s._initial_young_size) {
 118       FLAG_SET_ERGO(size_t, MaxNewSize, s._initial_young_size);
 119     } else if (!is_aligned(MaxNewSize, s._gen_alignment)) {
 120       FLAG_SET_ERGO(size_t, MaxNewSize, align_down(MaxNewSize, s._gen_alignment));
 121     }
 122     s._max_young_size = MaxNewSize;
 123   }
 124 
 125   if (NewSize > MaxNewSize) {
 126     // At this point this should only happen if the user specifies a large NewSize and/or
 127     // a small (but not too small) MaxNewSize.
 128     if (FLAG_IS_CMDLINE(MaxNewSize)) {
 129       log_warning(gc, ergo)("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). "
 130                             "A new max generation size of " SIZE_FORMAT "k will be used.",
 131                             NewSize/K, MaxNewSize/K, NewSize/K);
 132     }
 133     FLAG_SET_ERGO(size_t, MaxNewSize, NewSize);
 134     s._max_young_size = MaxNewSize;
 135   }
 136 
 137   if (SurvivorRatio < 1 || NewRatio < 1) {
 138     vm_exit_during_initialization("Invalid young gen ratio specified");
 139   }
 140 
 141   if (OldSize < old_gen_size_lower_bound(s)) {
 142     FLAG_SET_ERGO(size_t, OldSize, old_gen_size_lower_bound(s));
 143   }
 144   if (!is_aligned(OldSize, s._gen_alignment)) {
 145     FLAG_SET_ERGO(size_t, OldSize, align_down(OldSize, s._gen_alignment));
 146   }
 147 
 148   if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(MaxHeapSize)) {
 149     // NewRatio will be used later to set the young generation size so we use
 150     // it to calculate how big the heap should be based on the requested OldSize
 151     // and NewRatio.
 152     assert(NewRatio > 0, "NewRatio should have been set up earlier");
 153     size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1);
 154 
 155     calculated_heapsize = align_up(calculated_heapsize, s._heap_alignment);
 156     FLAG_SET_ERGO(size_t, MaxHeapSize, calculated_heapsize);
 157     s._max_heap_byte_size = MaxHeapSize;
 158     FLAG_SET_ERGO(size_t, InitialHeapSize, calculated_heapsize);
 159     s._initial_heap_byte_size = InitialHeapSize;
 160   }
 161 
 162   // Adjust NewSize and OldSize or MaxHeapSize to match each other
 163   if (NewSize + OldSize > MaxHeapSize) {
 164     if (FLAG_IS_CMDLINE(MaxHeapSize)) {
 165       // Somebody has set a maximum heap size with the intention that we should not
 166       // exceed it. Adjust New/OldSize as necessary.
 167       size_t calculated_size = NewSize + OldSize;
 168       double shrink_factor = (double) MaxHeapSize / calculated_size;
 169       size_t smaller_new_size = align_down((size_t)(NewSize * shrink_factor), s._gen_alignment);
 170       FLAG_SET_ERGO(size_t, NewSize, MAX2(young_gen_size_lower_bound(s), smaller_new_size));
 171       s._initial_young_size = NewSize;
 172 
 173       // OldSize is already aligned because above we aligned MaxHeapSize to
 174       // _heap_alignment, and we just made sure that NewSize is aligned to
 175       // _gen_alignment. In initialize_flags() we verified that _heap_alignment
 176       // is a multiple of _gen_alignment.
 177       FLAG_SET_ERGO(size_t, OldSize, MaxHeapSize - NewSize);
 178     } else {
 179       FLAG_SET_ERGO(size_t, MaxHeapSize, align_up(NewSize + OldSize, s._heap_alignment));
 180       s._max_heap_byte_size = MaxHeapSize;
 181     }
 182   }
 183 
 184   // Update NewSize, if possible, to avoid sizing the young gen too small when only
 185   // OldSize is set on the command line.
 186   if (FLAG_IS_CMDLINE(OldSize) && !FLAG_IS_CMDLINE(NewSize)) {
 187     if (OldSize < s._initial_heap_byte_size) {
 188       size_t new_size = s._initial_heap_byte_size - OldSize;
 189       // Need to compare against the flag value for max since _max_young_size
 190       // might not have been set yet.
 191       if (new_size >= s._min_young_size && new_size <= MaxNewSize) {
 192         FLAG_SET_ERGO(size_t, NewSize, new_size);
 193         s._initial_young_size = NewSize;
 194       }
 195     }
 196   }
 197 
 198   always_do_update_barrier = UseConcMarkSweepGC;
 199 
 200   DEBUG_ONLY(assert_flags(s);)
 201 
 202   GenArguments::initialize_size_info(s);
 203 }
 204 
 205 // Values set on the command line win over any ergonomically
 206 // set command line parameters.
 207 // Ergonomic choice of parameters are done before this
 208 // method is called.  Values for command line parameters such as NewSize
 209 // and MaxNewSize feed those ergonomic choices into this method.
 210 // This method makes the final generation sizings consistent with
 211 // themselves and with overall heap sizings.
 212 // In the absence of explicitly set command line flags, policies
 213 // such as the use of NewRatio are used to size the generation.
 214 
 215 // Minimum sizes of the generations may be different than
 216 // the initial sizes.  An inconsistency is permitted here
 217 // in the total size that can be specified explicitly by
 218 // command line specification of OldSize and NewSize and
 219 // also a command line specification of -Xms.  Issue a warning
 220 // but allow the values to pass.
 221 void GenArguments::initialize_size_info(GenSettings& s) {
 222   GCArguments::initialize_size_info(s);
 223 
 224   s._initial_young_size = NewSize;
 225   s._max_young_size = MaxNewSize;
 226   s._initial_old_size = OldSize;
 227 
 228   // Determine maximum size of the young generation.
 229 
 230   if (FLAG_IS_DEFAULT(MaxNewSize)) {
 231     s._max_young_size = scale_by_NewRatio_aligned(s._max_heap_byte_size, s._gen_alignment);
 232     // Bound the maximum size by NewSize below (since it historically
 233     // would have been NewSize and because the NewRatio calculation could
 234     // yield a size that is too small) and bound it by MaxNewSize above.
 235     // Ergonomics plays here by previously calculating the desired
 236     // NewSize and MaxNewSize.
 237     s._max_young_size = MIN2(MAX2(s._max_young_size, s._initial_young_size), MaxNewSize);
 238   }
 239 
 240   // Given the maximum young size, determine the initial and
 241   // minimum young sizes.
 242 
 243   if (s._max_heap_byte_size == s._initial_heap_byte_size) {
 244     // The maximum and initial heap sizes are the same so the generation's
 245     // initial size must be the same as it maximum size. Use NewSize as the
 246     // size if set on command line.
 247     s._max_young_size = FLAG_IS_CMDLINE(NewSize) ? NewSize : s._max_young_size;
 248     s._initial_young_size = s._max_young_size;
 249 
 250     // Also update the minimum size if min == initial == max.
 251     if (s._max_heap_byte_size == s._min_heap_byte_size) {
 252       s._min_young_size = s._max_young_size;
 253     }
 254   } else {
 255     if (FLAG_IS_CMDLINE(NewSize)) {
 256       // If NewSize is set on the command line, we should use it as
 257       // the initial size, but make sure it is within the heap bounds.
 258       s._initial_young_size =
 259         MIN2(s._max_young_size, bound_minus_alignment(NewSize, s._initial_heap_byte_size, s._gen_alignment));
 260       s._min_young_size = bound_minus_alignment(s._initial_young_size, s._min_heap_byte_size, s._gen_alignment);
 261     } else {
 262       // For the case where NewSize is not set on the command line, use
 263       // NewRatio to size the initial generation size. Use the current
 264       // NewSize as the floor, because if NewRatio is overly large, the resulting
 265       // size can be too small.
 266       s._initial_young_size =
 267         MIN2(s._max_young_size, MAX2(scale_by_NewRatio_aligned(s._initial_heap_byte_size, s._gen_alignment), NewSize));
 268     }
 269   }
 270 
 271   log_trace(gc, heap)("1: Minimum young " SIZE_FORMAT "  Initial young " SIZE_FORMAT "  Maximum young " SIZE_FORMAT,
 272                       s._min_young_size, s._initial_young_size, s._max_young_size);
 273 
 274   // At this point the minimum, initial and maximum sizes
 275   // of the overall heap and of the young generation have been determined.
 276   // The maximum old size can be determined from the maximum young
 277   // and maximum heap size since no explicit flags exist
 278   // for setting the old generation maximum.
 279   s._max_old_size = MAX2(s._max_heap_byte_size - s._max_young_size, s._gen_alignment);
 280 
 281   // If no explicit command line flag has been set for the
 282   // old generation size, use what is left.
 283   if (!FLAG_IS_CMDLINE(OldSize)) {
 284     // The user has not specified any value but the ergonomics
 285     // may have chosen a value (which may or may not be consistent
 286     // with the overall heap size).  In either case make
 287     // the minimum, maximum and initial sizes consistent
 288     // with the young sizes and the overall heap sizes.
 289     s._min_old_size = s._gen_alignment;
 290     s._initial_old_size = MIN2(s._max_old_size, MAX2(s._initial_heap_byte_size - s._initial_young_size, s._min_old_size));
 291     // _max_old_size has already been made consistent above.
 292   } else {
 293     // OldSize has been explicitly set on the command line. Use it
 294     // for the initial size but make sure the minimum allow a young
 295     // generation to fit as well.
 296     // If the user has explicitly set an OldSize that is inconsistent
 297     // with other command line flags, issue a warning.
 298     // The generation minimums and the overall heap minimum should
 299     // be within one generation alignment.
 300     if (s._initial_old_size > s._max_old_size) {
 301       log_warning(gc, ergo)("Inconsistency between maximum heap size and maximum "
 302                             "generation sizes: using maximum heap = " SIZE_FORMAT
 303                             ", -XX:OldSize flag is being ignored",
 304                             s._max_heap_byte_size);
 305       s._initial_old_size = s._max_old_size;
 306     }
 307 
 308     s._min_old_size = MIN2(s._initial_old_size, s._min_heap_byte_size - s._min_young_size);
 309   }
 310 
 311   // The initial generation sizes should match the initial heap size,
 312   // if not issue a warning and resize the generations. This behavior
 313   // differs from JDK8 where the generation sizes have higher priority
 314   // than the initial heap size.
 315   if ((s._initial_old_size + s._initial_young_size) != s._initial_heap_byte_size) {
 316     log_warning(gc, ergo)("Inconsistency between generation sizes and heap size, resizing "
 317                           "the generations to fit the heap.");
 318 
 319     size_t desired_young_size = s._initial_heap_byte_size - s._initial_old_size;
 320     if (s._initial_heap_byte_size < s._initial_old_size) {
 321       // Old want all memory, use minimum for young and rest for old
 322       s._initial_young_size = s._min_young_size;
 323       s._initial_old_size = s._initial_heap_byte_size - s._min_young_size;
 324     } else if (desired_young_size > s._max_young_size) {
 325       // Need to increase both young and old generation
 326       s._initial_young_size = s._max_young_size;
 327       s._initial_old_size = s._initial_heap_byte_size - s._max_young_size;
 328     } else if (desired_young_size < s._min_young_size) {
 329       // Need to decrease both young and old generation
 330       s._initial_young_size = s._min_young_size;
 331       s._initial_old_size = s._initial_heap_byte_size - s._min_young_size;
 332     } else {
 333       // The young generation boundaries allow us to only update the
 334       // young generation.
 335       s._initial_young_size = desired_young_size;
 336     }
 337 
 338     log_trace(gc, heap)("2: Minimum young " SIZE_FORMAT "  Initial young " SIZE_FORMAT "  Maximum young " SIZE_FORMAT,
 339                     s._min_young_size, s._initial_young_size, s._max_young_size);
 340   }
 341 
 342   // Write back to flags if necessary.
 343   if (NewSize != s._initial_young_size) {
 344     FLAG_SET_ERGO(size_t, NewSize, s._initial_young_size);
 345   }
 346 
 347   if (MaxNewSize != s._max_young_size) {
 348     FLAG_SET_ERGO(size_t, MaxNewSize, s._max_young_size);
 349   }
 350 
 351   if (OldSize != s._initial_old_size) {
 352     FLAG_SET_ERGO(size_t, OldSize, s._initial_old_size);
 353   }
 354 
 355   log_trace(gc, heap)("Minimum old " SIZE_FORMAT "  Initial old " SIZE_FORMAT "  Maximum old " SIZE_FORMAT,
 356                   s._min_old_size, s._initial_old_size, s._max_old_size);
 357 
 358   DEBUG_ONLY(assert_size_info(s);)
 359 }
 360 
 361 #ifdef ASSERT
 362 void GenArguments::assert_flags(const GenSettings& s) {
 363   GCArguments::assert_flags(s);
 364   assert(NewSize >= s._min_young_size, "Ergonomics decided on a too small young gen size");
 365   assert(NewSize <= MaxNewSize, "Ergonomics decided on incompatible initial and maximum young gen sizes");
 366   assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young gen and heap sizes");
 367   assert(NewSize % s._gen_alignment == 0, "NewSize alignment");
 368   assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize % s._gen_alignment == 0, "MaxNewSize alignment");
 369   assert(OldSize + NewSize <= MaxHeapSize, "Ergonomics decided on incompatible generation and heap sizes");
 370   assert(OldSize % s._gen_alignment == 0, "OldSize alignment");
 371 }
 372 
 373 void GenArguments::assert_size_info(const GenSettings& s) {
 374   GCArguments::assert_size_info(s);
 375   // GenArguments::initialize_size_info may update the MaxNewSize
 376   assert(MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young and heap sizes");
 377   assert(NewSize == s._initial_young_size, "Discrepancy between NewSize flag and local storage");
 378   assert(MaxNewSize == s._max_young_size, "Discrepancy between MaxNewSize flag and local storage");
 379   assert(OldSize == s._initial_old_size, "Discrepancy between OldSize flag and local storage");
 380   assert(s._min_young_size <= s._initial_young_size, "Ergonomics decided on incompatible minimum and initial young gen sizes");
 381   assert(s._initial_young_size <= s._max_young_size, "Ergonomics decided on incompatible initial and maximum young gen sizes");
 382   assert(s._min_young_size % s._gen_alignment == 0, "_min_young_size alignment");
 383   assert(s._initial_young_size % s._gen_alignment == 0, "_initial_young_size alignment");
 384   assert(s._max_young_size % s._gen_alignment == 0, "_max_young_size alignment");
 385   assert(s._min_young_size <= bound_minus_alignment(s._min_young_size, s._min_heap_byte_size, s._gen_alignment),
 386       "Ergonomics made minimum young generation larger than minimum heap");
 387   assert(s._initial_young_size <=  bound_minus_alignment(s._initial_young_size, s._initial_heap_byte_size, s._gen_alignment),
 388       "Ergonomics made initial young generation larger than initial heap");
 389   assert(s._max_young_size <= bound_minus_alignment(s._max_young_size, s._max_heap_byte_size, s._gen_alignment),
 390       "Ergonomics made maximum young generation lager than maximum heap");
 391   assert(s._min_old_size <= s._initial_old_size, "Ergonomics decided on incompatible minimum and initial old gen sizes");
 392   assert(s._initial_old_size <= s._max_old_size, "Ergonomics decided on incompatible initial and maximum old gen sizes");
 393   assert(s._max_old_size % s._gen_alignment == 0, "_max_old_size alignment");
 394   assert(s._initial_old_size % s._gen_alignment == 0, "_initial_old_size alignment");
 395   assert(s._max_heap_byte_size <= (s._max_young_size + s._max_old_size), "Total maximum heap sizes must be sum of generation maximum sizes");
 396   assert(s._min_young_size + s._min_old_size <= s._min_heap_byte_size, "Minimum generation sizes exceed minimum heap size");
 397   assert(s._initial_young_size + s._initial_old_size == s._initial_heap_byte_size, "Initial generation sizes should match initial heap size");
 398   assert(s._max_young_size + s._max_old_size == s._max_heap_byte_size, "Maximum generation sizes should match maximum heap size");
 399 }
 400 #endif // ASSERT