1 /*
  2  * Copyright (c) 2003, 2019, 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/parallel/adjoiningGenerations.hpp"
 27 #include "gc/parallel/adjoiningGenerationsForHeteroHeap.hpp"
 28 #include "gc/parallel/adjoiningVirtualSpaces.hpp"
 29 #include "gc/parallel/generationSizer.hpp"
 30 #include "gc/parallel/parallelScavengeHeap.hpp"
 31 #include "logging/log.hpp"
 32 #include "logging/logStream.hpp"
 33 #include "memory/resourceArea.hpp"
 34 #include "utilities/align.hpp"
 35 #include "utilities/ostream.hpp"
 36 
 37 // If boundary moving is being used, create the young gen and old
 38 // gen with ASPSYoungGen and ASPSOldGen, respectively.  Revert to
 39 // the old behavior otherwise (with PSYoungGen and PSOldGen).
 40 
 41 AdjoiningGenerations::AdjoiningGenerations(ReservedSpace old_young_rs,
 42                                            GenerationSizer* policy,
 43                                            size_t alignment) :
 44   _virtual_spaces(new AdjoiningVirtualSpaces(old_young_rs, policy->min_old_size(),
 45                                              policy->min_young_size(), alignment)) {
 46   size_t init_low_byte_size = policy->initial_old_size();
 47   size_t min_low_byte_size = policy->min_old_size();
 48   size_t max_low_byte_size = policy->max_old_size();
 49   size_t init_high_byte_size = policy->initial_young_size();
 50   size_t min_high_byte_size = policy->min_young_size();
 51   size_t max_high_byte_size = policy->max_young_size();
 52 
 53   assert(min_low_byte_size <= init_low_byte_size &&
 54          init_low_byte_size <= max_low_byte_size, "Parameter check");
 55   assert(min_high_byte_size <= init_high_byte_size &&
 56          init_high_byte_size <= max_high_byte_size, "Parameter check");
 57   // Create the generations differently based on the option to
 58   // move the boundary.
 59   if (UseAdaptiveGCBoundary) {
 60     // Initialize the adjoining virtual spaces.  Then pass the
 61     // a virtual to each generation for initialization of the
 62     // generation.
 63 
 64     // Does the actual creation of the virtual spaces
 65     _virtual_spaces->initialize(max_low_byte_size,
 66                                 init_low_byte_size,
 67                                 init_high_byte_size);
 68 
 69     // Place the young gen at the high end.  Passes in the virtual space.
 70     _young_gen = new ASPSYoungGen(_virtual_spaces->high(),
 71                                   _virtual_spaces->high()->committed_size(),
 72                                   min_high_byte_size,
 73                                   _virtual_spaces->high_byte_size_limit());
 74 
 75     // Place the old gen at the low end. Passes in the virtual space.
 76     _old_gen = new ASPSOldGen(_virtual_spaces->low(),
 77                               _virtual_spaces->low()->committed_size(),
 78                               min_low_byte_size,
 79                               _virtual_spaces->low_byte_size_limit(),
 80                               "old", 1);
 81 
 82     young_gen()->initialize_work();
 83     assert(young_gen()->reserved().byte_size() <= young_gen()->gen_size_limit(),
 84      "Consistency check");
 85     assert(old_young_rs.size() >= young_gen()->gen_size_limit(),
 86      "Consistency check");
 87 
 88     old_gen()->initialize_work("old", 1);
 89     assert(old_gen()->reserved().byte_size() <= old_gen()->gen_size_limit(),
 90      "Consistency check");
 91     assert(old_young_rs.size() >= old_gen()->gen_size_limit(),
 92      "Consistency check");
 93   } else {
 94 
 95     // Layout the reserved space for the generations.
 96     // If OldGen is allocated on nv-dimm, we need to split the reservation (this is required for windows).
 97     ReservedSpace old_rs   =
 98       virtual_spaces()->reserved_space().first_part(max_low_byte_size, policy->is_hetero_heap() /* split */);
 99     ReservedSpace heap_rs  =
100       virtual_spaces()->reserved_space().last_part(max_low_byte_size);
101     ReservedSpace young_rs = heap_rs.first_part(max_high_byte_size);
102     assert(young_rs.size() == heap_rs.size(), "Didn't reserve all of the heap");
103 
104     // Create the generations.  Virtual spaces are not passed in.
105     _young_gen = new PSYoungGen(init_high_byte_size,
106                                 min_high_byte_size,
107                                 max_high_byte_size);
108     _old_gen = new PSOldGen(init_low_byte_size,
109                             min_low_byte_size,
110                             max_low_byte_size,
111                             "old", 1);
112 
113     // The virtual spaces are created by the initialization of the gens.
114     _young_gen->initialize(young_rs, alignment);
115     assert(young_gen()->gen_size_limit() == young_rs.size(),
116       "Consistency check");
117     _old_gen->initialize(old_rs, alignment, "old", 1);
118     assert(old_gen()->gen_size_limit() == old_rs.size(), "Consistency check");
119   }
120 }
121 
122 AdjoiningGenerations::AdjoiningGenerations(): _young_gen(NULL), _old_gen(NULL), _virtual_spaces(NULL) { }
123 
124 size_t AdjoiningGenerations::reserved_byte_size() {
125   return virtual_spaces()->reserved_space().size();
126 }
127 
128 void log_before_expansion(bool old, size_t expand_in_bytes, size_t change_in_bytes, size_t max_size) {
129   Log(gc, ergo, heap) log;
130   if (!log.is_debug()) {
131    return;
132   }
133   log.debug("Before expansion of %s gen with boundary move", old ? "old" : "young");
134   log.debug("  Requested change: " SIZE_FORMAT_HEX "  Attempted change: " SIZE_FORMAT_HEX,
135                         expand_in_bytes, change_in_bytes);
136   ResourceMark rm;
137   LogStream ls(log.debug());
138   ParallelScavengeHeap::heap()->print_on(&ls);
139   log.debug("  PS%sGen max size: " SIZE_FORMAT "K", old ? "Old" : "Young", max_size/K);
140 }
141 
142 void log_after_expansion(bool old, size_t max_size) {
143   Log(gc, ergo, heap) log;
144   if (!log.is_debug()) {
145    return;
146   }
147   log.debug("After expansion of %s gen with boundary move", old ? "old" : "young");
148   ResourceMark rm;
149   LogStream ls(log.debug());
150   ParallelScavengeHeap::heap()->print_on(&ls);
151   log.debug("  PS%sGen max size: " SIZE_FORMAT "K", old ? "Old" : "Young", max_size/K);
152 }
153 
154 // Make checks on the current sizes of the generations and
155 // the constraints on the sizes of the generations.  Push
156 // up the boundary within the constraints.  A partial
157 // push can occur.
158 void AdjoiningGenerations::request_old_gen_expansion(size_t expand_in_bytes) {
159   assert(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary, "runtime check");
160 
161   assert_lock_strong(ExpandHeap_lock);
162   assert_locked_or_safepoint(Heap_lock);
163 
164   // These sizes limit the amount the boundaries can move.  Effectively,
165   // the generation says how much it is willing to yield to the other
166   // generation.
167   const size_t young_gen_available = young_gen()->available_for_contraction();
168   const size_t old_gen_available = old_gen()->available_for_expansion();
169   const size_t alignment = virtual_spaces()->alignment();
170   size_t change_in_bytes = MIN3(young_gen_available,
171                                 old_gen_available,
172                                 align_up(expand_in_bytes, alignment));
173 
174   if (change_in_bytes == 0) {
175     return;
176   }
177 
178   log_before_expansion(true, expand_in_bytes, change_in_bytes, old_gen()->max_gen_size());
179 
180   // Move the boundary between the generations up (smaller young gen).
181   if (virtual_spaces()->adjust_boundary_up(change_in_bytes)) {
182     young_gen()->reset_after_change();
183     old_gen()->reset_after_change();
184   }
185 
186   // The total reserved for the generations should match the sum
187   // of the two even if the boundary is moving.
188   assert(reserved_byte_size() ==
189          old_gen()->max_gen_size() + young_gen()->max_size(),
190          "Space is missing");
191   young_gen()->space_invariants();
192   old_gen()->space_invariants();
193 
194   log_after_expansion(true, old_gen()->max_gen_size());
195 }
196 
197 // See comments on request_old_gen_expansion()
198 bool AdjoiningGenerations::request_young_gen_expansion(size_t expand_in_bytes) {
199   assert(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary, "runtime check");
200 
201   // If eden is not empty, the boundary can be moved but no advantage
202   // can be made of the move since eden cannot be moved.
203   if (!young_gen()->eden_space()->is_empty()) {
204     return false;
205   }
206 
207 
208   bool result = false;
209   const size_t young_gen_available = young_gen()->available_for_expansion();
210   const size_t old_gen_available = old_gen()->available_for_contraction();
211   const size_t alignment = virtual_spaces()->alignment();
212   size_t change_in_bytes = MIN3(young_gen_available,
213                                 old_gen_available,
214                                 align_up(expand_in_bytes, alignment));
215 
216   if (change_in_bytes == 0) {
217     return false;
218   }
219 
220   log_before_expansion(false, expand_in_bytes, change_in_bytes, young_gen()->max_size());
221 
222   // Move the boundary between the generations down (smaller old gen).
223   MutexLocker x(ExpandHeap_lock);
224   if (virtual_spaces()->adjust_boundary_down(change_in_bytes)) {
225     young_gen()->reset_after_change();
226     old_gen()->reset_after_change();
227     result = true;
228   }
229 
230   // The total reserved for the generations should match the sum
231   // of the two even if the boundary is moving.
232   assert(reserved_byte_size() ==
233          old_gen()->max_gen_size() + young_gen()->max_size(),
234          "Space is missing");
235   young_gen()->space_invariants();
236   old_gen()->space_invariants();
237 
238   log_after_expansion(false, young_gen()->max_size());
239 
240   return result;
241 }
242 
243 // Additional space is needed in the old generation.  Try to move the boundary
244 // up to meet the need.  Moves boundary up only
245 void AdjoiningGenerations::adjust_boundary_for_old_gen_needs(
246   size_t desired_free_space) {
247   assert(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary, "runtime check");
248 
249   // Stress testing.
250   if (PSAdaptiveSizePolicyResizeVirtualSpaceAlot == 1) {
251     MutexLocker x(ExpandHeap_lock);
252     request_old_gen_expansion(virtual_spaces()->alignment() * 3 / 2);
253   }
254 
255   // Expand only if the entire generation is already committed.
256   if (old_gen()->virtual_space()->uncommitted_size() == 0) {
257     if (old_gen()->free_in_bytes() < desired_free_space) {
258       MutexLocker x(ExpandHeap_lock);
259       request_old_gen_expansion(desired_free_space);
260     }
261   }
262 }
263 
264 // See comment on adjust_boundary_for_old_gen_needss().
265 // Adjust boundary down only.
266 void AdjoiningGenerations::adjust_boundary_for_young_gen_needs(size_t eden_size,
267     size_t survivor_size) {
268 
269   assert(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary, "runtime check");
270 
271   // Stress testing.
272   if (PSAdaptiveSizePolicyResizeVirtualSpaceAlot == 0) {
273     request_young_gen_expansion(virtual_spaces()->alignment() * 3 / 2);
274     eden_size = young_gen()->eden_space()->capacity_in_bytes();
275   }
276 
277   // Expand only if the entire generation is already committed.
278   if (young_gen()->virtual_space()->uncommitted_size() == 0) {
279     size_t desired_size = eden_size + 2 * survivor_size;
280     const size_t committed = young_gen()->virtual_space()->committed_size();
281     if (desired_size > committed) {
282       request_young_gen_expansion(desired_size - committed);
283     }
284   }
285 }
286 
287 AdjoiningGenerations* AdjoiningGenerations::create_adjoining_generations(ReservedSpace old_young_rs,
288                                                                          GenerationSizer* policy,
289                                                                          size_t alignment) {
290   if (policy->is_hetero_heap() && UseAdaptiveGCBoundary) {
291     return new AdjoiningGenerationsForHeteroHeap(old_young_rs, policy, alignment);
292   } else {
293     return new AdjoiningGenerations(old_young_rs, policy, alignment);
294   }
295 }