1 /*
2 * Copyright Amazon.com Inc. 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
27 #include "gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp"
28 #include "gc/shenandoah/shenandoahCollectionSet.hpp"
29 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
30 #include "gc/shenandoah/shenandoahGenerationalHeap.hpp"
31 #include "gc/shenandoah/shenandoahOldGeneration.hpp"
32 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
33 #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
34 #include "logging/log.hpp"
35 #include "utilities/quickSort.hpp"
36
37 uint ShenandoahOldHeuristics::NOT_FOUND = -1U;
38
39 // sort by increasing live (so least live comes first)
40 int ShenandoahOldHeuristics::compare_by_live(RegionData a, RegionData b) {
41 if (a.get_livedata() < b.get_livedata()) {
42 return -1;
43 } else if (a.get_livedata() > b.get_livedata()) {
44 return 1;
45 } else {
46 return 0;
47 }
48 }
49
50 // sort by increasing index
51 int ShenandoahOldHeuristics::compare_by_index(RegionData a, RegionData b) {
52 if (a.get_region()->index() < b.get_region()->index()) {
53 return -1;
54 } else if (a.get_region()->index() > b.get_region()->index()) {
55 return 1;
56 } else {
57 // quicksort may compare to self during search for pivot
58 return 0;
59 }
60 }
61
62 ShenandoahOldHeuristics::ShenandoahOldHeuristics(ShenandoahOldGeneration* generation, ShenandoahGenerationalHeap* gen_heap) :
63 ShenandoahHeuristics(generation),
64 _heap(gen_heap),
65 _first_pinned_candidate(NOT_FOUND),
66 _last_old_collection_candidate(0),
67 _next_old_collection_candidate(0),
68 _last_old_region(0),
69 _live_bytes_in_unprocessed_candidates(0),
70 _old_generation(generation),
71 _cannot_expand_trigger(false),
72 _fragmentation_trigger(false),
73 _growth_trigger(false),
74 _fragmentation_density(0.0),
75 _fragmentation_first_old_region(0),
76 _fragmentation_last_old_region(0)
77 {
78 }
79
80 bool ShenandoahOldHeuristics::prime_collection_set(ShenandoahCollectionSet* collection_set) {
81 if (unprocessed_old_collection_candidates() == 0) {
82 return false;
83 }
84
85 if (_old_generation->is_preparing_for_mark()) {
86 // We have unprocessed old collection candidates, but the heuristic has given up on evacuating them.
87 // This is most likely because they were _all_ pinned at the time of the last mixed evacuation (and
88 // this in turn is most likely because there are just one or two candidate regions remaining).
89 log_info(gc, ergo)("Remaining " UINT32_FORMAT " old regions are being coalesced and filled", unprocessed_old_collection_candidates());
90 return false;
91 }
92
93 _first_pinned_candidate = NOT_FOUND;
94
95 uint included_old_regions = 0;
96 size_t evacuated_old_bytes = 0;
97 size_t collected_old_bytes = 0;
98
99 // If a region is put into the collection set, then this region's free (not yet used) bytes are no longer
100 // "available" to hold the results of other evacuations. This may cause a decrease in the remaining amount
101 // of memory that can still be evacuated. We address this by reducing the evacuation budget by the amount
102 // of live memory in that region and by the amount of unallocated memory in that region if the evacuation
103 // budget is constrained by availability of free memory.
104 const size_t old_evacuation_reserve = _old_generation->get_evacuation_reserve();
105 const size_t old_evacuation_budget = (size_t) ((double) old_evacuation_reserve / ShenandoahOldEvacWaste);
106 size_t unfragmented_available = _old_generation->free_unaffiliated_regions() * ShenandoahHeapRegion::region_size_bytes();
107 size_t fragmented_available;
108 size_t excess_fragmented_available;
109
110 if (unfragmented_available > old_evacuation_budget) {
111 unfragmented_available = old_evacuation_budget;
112 fragmented_available = 0;
113 excess_fragmented_available = 0;
114 } else {
115 assert(_old_generation->available() >= old_evacuation_budget, "Cannot budget more than is available");
116 fragmented_available = _old_generation->available() - unfragmented_available;
117 assert(fragmented_available + unfragmented_available >= old_evacuation_budget, "Budgets do not add up");
118 if (fragmented_available + unfragmented_available > old_evacuation_budget) {
119 excess_fragmented_available = (fragmented_available + unfragmented_available) - old_evacuation_budget;
120 fragmented_available -= excess_fragmented_available;
121 }
122 }
123
124 size_t remaining_old_evacuation_budget = old_evacuation_budget;
125 log_debug(gc)("Choose old regions for mixed collection: old evacuation budget: " SIZE_FORMAT "%s, candidates: %u",
126 byte_size_in_proper_unit(old_evacuation_budget), proper_unit_for_byte_size(old_evacuation_budget),
127 unprocessed_old_collection_candidates());
128
129 size_t lost_evacuation_capacity = 0;
130
131 // The number of old-gen regions that were selected as candidates for collection at the end of the most recent old-gen
132 // concurrent marking phase and have not yet been collected is represented by unprocessed_old_collection_candidates().
133 // Candidate regions are ordered according to increasing amount of live data. If there is not sufficient room to
134 // evacuate region N, then there is no need to even consider evacuating region N+1.
135 while (unprocessed_old_collection_candidates() > 0) {
136 // Old collection candidates are sorted in order of decreasing garbage contained therein.
137 ShenandoahHeapRegion* r = next_old_collection_candidate();
138 if (r == nullptr) {
139 break;
140 }
141 assert(r->is_regular(), "There should be no humongous regions in the set of mixed-evac candidates");
142
143 // If region r is evacuated to fragmented memory (to free memory within a partially used region), then we need
144 // to decrease the capacity of the fragmented memory by the scaled loss.
145
146 size_t live_data_for_evacuation = r->get_live_data_bytes();
147 size_t lost_available = r->free();
148
149 if ((lost_available > 0) && (excess_fragmented_available > 0)) {
150 if (lost_available < excess_fragmented_available) {
151 excess_fragmented_available -= lost_available;
152 lost_evacuation_capacity -= lost_available;
153 lost_available = 0;
154 } else {
155 lost_available -= excess_fragmented_available;
156 lost_evacuation_capacity -= excess_fragmented_available;
157 excess_fragmented_available = 0;
158 }
159 }
160 size_t scaled_loss = (size_t) ((double) lost_available / ShenandoahOldEvacWaste);
161 if ((lost_available > 0) && (fragmented_available > 0)) {
162 if (scaled_loss + live_data_for_evacuation < fragmented_available) {
163 fragmented_available -= scaled_loss;
164 scaled_loss = 0;
165 } else {
166 // We will have to allocate this region's evacuation memory from unfragmented memory, so don't bother
167 // to decrement scaled_loss
168 }
169 }
170 if (scaled_loss > 0) {
171 // We were not able to account for the lost free memory within fragmented memory, so we need to take this
172 // allocation out of unfragmented memory. Unfragmented memory does not need to account for loss of free.
173 if (live_data_for_evacuation > unfragmented_available) {
174 // There is not room to evacuate this region or any that come after it in within the candidates array.
175 break;
176 } else {
177 unfragmented_available -= live_data_for_evacuation;
178 }
179 } else {
180 // Since scaled_loss == 0, we have accounted for the loss of free memory, so we can allocate from either
181 // fragmented or unfragmented available memory. Use up the fragmented memory budget first.
182 size_t evacuation_need = live_data_for_evacuation;
183
184 if (evacuation_need > fragmented_available) {
185 evacuation_need -= fragmented_available;
186 fragmented_available = 0;
187 } else {
188 fragmented_available -= evacuation_need;
189 evacuation_need = 0;
190 }
191 if (evacuation_need > unfragmented_available) {
192 // There is not room to evacuate this region or any that come after it in within the candidates array.
193 break;
194 } else {
195 unfragmented_available -= evacuation_need;
196 // dead code: evacuation_need == 0;
197 }
198 }
199 collection_set->add_region(r);
200 included_old_regions++;
201 evacuated_old_bytes += live_data_for_evacuation;
202 collected_old_bytes += r->garbage();
203 consume_old_collection_candidate();
204 }
205
206 if (_first_pinned_candidate != NOT_FOUND) {
207 // Need to deal with pinned regions
208 slide_pinned_regions_to_front();
209 }
210 decrease_unprocessed_old_collection_candidates_live_memory(evacuated_old_bytes);
211 if (included_old_regions > 0) {
212 log_info(gc, ergo)("Old-gen piggyback evac (" UINT32_FORMAT " regions, evacuating " PROPERFMT ", reclaiming: " PROPERFMT ")",
213 included_old_regions, PROPERFMTARGS(evacuated_old_bytes), PROPERFMTARGS(collected_old_bytes));
214 }
215
216 if (unprocessed_old_collection_candidates() == 0) {
217 // We have added the last of our collection candidates to a mixed collection.
218 // Any triggers that occurred during mixed evacuations may no longer be valid. They can retrigger if appropriate.
219 clear_triggers();
220
221 _old_generation->complete_mixed_evacuations();
222 } else if (included_old_regions == 0) {
223 // We have candidates, but none were included for evacuation - are they all pinned?
224 // or did we just not have enough room for any of them in this collection set?
225 // We don't want a region with a stuck pin to prevent subsequent old collections, so
226 // if they are all pinned we transition to a state that will allow us to make these uncollected
227 // (pinned) regions parsable.
228 if (all_candidates_are_pinned()) {
229 log_info(gc, ergo)("All candidate regions " UINT32_FORMAT " are pinned", unprocessed_old_collection_candidates());
230 _old_generation->abandon_mixed_evacuations();
231 } else {
232 log_info(gc, ergo)("No regions selected for mixed collection. "
233 "Old evacuation budget: " PROPERFMT ", Remaining evacuation budget: " PROPERFMT
234 ", Lost capacity: " PROPERFMT
235 ", Next candidate: " UINT32_FORMAT ", Last candidate: " UINT32_FORMAT,
236 PROPERFMTARGS(old_evacuation_reserve),
237 PROPERFMTARGS(remaining_old_evacuation_budget),
238 PROPERFMTARGS(lost_evacuation_capacity),
239 _next_old_collection_candidate, _last_old_collection_candidate);
240 }
241 }
242
243 return (included_old_regions > 0);
244 }
245
246 bool ShenandoahOldHeuristics::all_candidates_are_pinned() {
247 #ifdef ASSERT
248 if (uint(os::random()) % 100 < ShenandoahCoalesceChance) {
249 return true;
250 }
251 #endif
252
253 for (uint i = _next_old_collection_candidate; i < _last_old_collection_candidate; ++i) {
254 ShenandoahHeapRegion* region = _region_data[i].get_region();
255 if (!region->is_pinned()) {
256 return false;
257 }
258 }
259 return true;
260 }
261
262 void ShenandoahOldHeuristics::slide_pinned_regions_to_front() {
263 // Find the first unpinned region to the left of the next region that
264 // will be added to the collection set. These regions will have been
265 // added to the cset, so we can use them to hold pointers to regions
266 // that were pinned when the cset was chosen.
267 // [ r p r p p p r r ]
268 // ^ ^ ^
269 // | | | pointer to next region to add to a mixed collection is here.
270 // | | first r to the left should be in the collection set now.
271 // | first pinned region, we don't need to look past this
272 uint write_index = NOT_FOUND;
273 for (uint search = _next_old_collection_candidate - 1; search > _first_pinned_candidate; --search) {
274 ShenandoahHeapRegion* region = _region_data[search].get_region();
275 if (!region->is_pinned()) {
276 write_index = search;
277 assert(region->is_cset(), "Expected unpinned region to be added to the collection set.");
278 break;
279 }
280 }
281
282 // If we could not find an unpinned region, it means there are no slots available
283 // to move up the pinned regions. In this case, we just reset our next index in the
284 // hopes that some of these regions will become unpinned before the next mixed
285 // collection. We may want to bailout of here instead, as it should be quite
286 // rare to have so many pinned regions and may indicate something is wrong.
287 if (write_index == NOT_FOUND) {
288 assert(_first_pinned_candidate != NOT_FOUND, "Should only be here if there are pinned regions.");
289 _next_old_collection_candidate = _first_pinned_candidate;
290 return;
291 }
292
293 // Find pinned regions to the left and move their pointer into a slot
294 // that was pointing at a region that has been added to the cset (or was pointing
295 // to a pinned region that we've already moved up). We are done when the leftmost
296 // pinned region has been slid up.
297 // [ r p r x p p p r ]
298 // ^ ^
299 // | | next region for mixed collections
300 // | Write pointer is here. We know this region is already in the cset
301 // | so we can clobber it with the next pinned region we find.
302 for (int32_t search = (int32_t)write_index - 1; search >= (int32_t)_first_pinned_candidate; --search) {
303 RegionData& skipped = _region_data[search];
304 if (skipped.get_region()->is_pinned()) {
305 RegionData& available_slot = _region_data[write_index];
306 available_slot.set_region_and_livedata(skipped.get_region(), skipped.get_livedata());
307 --write_index;
308 }
309 }
310
311 // Update to read from the leftmost pinned region. Plus one here because we decremented
312 // the write index to hold the next found pinned region. We are just moving it back now
313 // to point to the first pinned region.
314 _next_old_collection_candidate = write_index + 1;
315 }
316
317 void ShenandoahOldHeuristics::prepare_for_old_collections() {
318 ShenandoahHeap* heap = ShenandoahHeap::heap();
319
320 const size_t num_regions = heap->num_regions();
321 size_t cand_idx = 0;
322 size_t immediate_garbage = 0;
323 size_t immediate_regions = 0;
324 size_t live_data = 0;
325
326 RegionData* candidates = _region_data;
327 for (size_t i = 0; i < num_regions; i++) {
328 ShenandoahHeapRegion* region = heap->get_region(i);
329 if (!region->is_old()) {
330 continue;
331 }
332
333 size_t garbage = region->garbage();
334 size_t live_bytes = region->get_live_data_bytes();
335 live_data += live_bytes;
336
337 if (region->is_regular() || region->is_regular_pinned()) {
338 // Only place regular or pinned regions with live data into the candidate set.
339 // Pinned regions cannot be evacuated, but we are not actually choosing candidates
340 // for the collection set here. That happens later during the next young GC cycle,
341 // by which time, the pinned region may no longer be pinned.
342 if (!region->has_live()) {
343 assert(!region->is_pinned(), "Pinned region should have live (pinned) objects.");
344 region->make_trash_immediate();
345 immediate_regions++;
346 immediate_garbage += garbage;
347 } else {
348 region->begin_preemptible_coalesce_and_fill();
349 candidates[cand_idx].set_region_and_livedata(region, live_bytes);
350 cand_idx++;
351 }
352 } else if (region->is_humongous_start()) {
353 // This will handle humongous start regions whether they are also pinned, or not.
354 // If they are pinned, we expect them to hold live data, so they will not be
355 // turned into immediate garbage.
356 if (!region->has_live()) {
357 assert(!region->is_pinned(), "Pinned region should have live (pinned) objects.");
358 // The humongous object is dead, we can just return this region and the continuations
359 // immediately to the freeset - no evacuations are necessary here. The continuations
360 // will be made into trash by this method, so they'll be skipped by the 'is_regular'
361 // check above, but we still need to count the start region.
362 immediate_regions++;
363 immediate_garbage += garbage;
364 size_t region_count = heap->trash_humongous_region_at(region);
365 log_debug(gc)("Trashed " SIZE_FORMAT " regions for humongous object.", region_count);
366 }
367 } else if (region->is_trash()) {
368 // Count humongous objects made into trash here.
369 immediate_regions++;
370 immediate_garbage += garbage;
371 }
372 }
373
374 _old_generation->set_live_bytes_after_last_mark(live_data);
375
376 // Unlike young, we are more interested in efficiently packing OLD-gen than in reclaiming garbage first. We sort by live-data.
377 // Some regular regions may have been promoted in place with no garbage but also with very little live data. When we "compact"
378 // old-gen, we want to pack these underutilized regions together so we can have more unaffiliated (unfragmented) free regions
379 // in old-gen.
380
381 QuickSort::sort<RegionData>(candidates, cand_idx, compare_by_live, false);
382
383 const size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes();
384
385 // The convention is to collect regions that have more than this amount of garbage.
386 const size_t garbage_threshold = region_size_bytes * ShenandoahOldGarbageThreshold / 100;
387
388 // Enlightened interpretation: collect regions that have less than this amount of live.
389 const size_t live_threshold = region_size_bytes - garbage_threshold;
390
391 _last_old_region = (uint)cand_idx;
392 _last_old_collection_candidate = (uint)cand_idx;
393 _next_old_collection_candidate = 0;
394
395 size_t unfragmented = 0;
396 size_t candidates_garbage = 0;
397
398 for (size_t i = 0; i < cand_idx; i++) {
399 size_t live = candidates[i].get_livedata();
400 if (live > live_threshold) {
401 // Candidates are sorted in increasing order of live data, so no regions after this will be below the threshold.
402 _last_old_collection_candidate = (uint)i;
403 break;
404 }
405 ShenandoahHeapRegion* r = candidates[i].get_region();
406 size_t region_garbage = r->garbage();
407 size_t region_free = r->free();
408 candidates_garbage += region_garbage;
409 unfragmented += region_free;
410 }
411
412 // defrag_count represents regions that are placed into the old collection set in order to defragment the memory
413 // that we try to "reserve" for humongous allocations.
414 size_t defrag_count = 0;
415 size_t total_uncollected_old_regions = _last_old_region - _last_old_collection_candidate;
416
417 if (cand_idx > _last_old_collection_candidate) {
418 // Above, we have added into the set of mixed-evacuation candidates all old-gen regions for which the live memory
419 // that they contain is below a particular old-garbage threshold. Regions that were not selected for the collection
420 // set hold enough live memory that it is not considered efficient (by "garbage-first standards") to compact these
421 // at the current time.
422 //
423 // However, if any of these regions that were rejected from the collection set reside within areas of memory that
424 // might interfere with future humongous allocation requests, we will prioritize them for evacuation at this time.
425 // Humongous allocations target the bottom of the heap. We want old-gen regions to congregate at the top of the
426 // heap.
427 //
428 // Sort the regions that were initially rejected from the collection set in order of index. This allows us to
429 // focus our attention on the regions that have low index value (i.e. the old-gen regions at the bottom of the heap).
430 QuickSort::sort<RegionData>(candidates + _last_old_collection_candidate, cand_idx - _last_old_collection_candidate,
431 compare_by_index, false);
432
433 const size_t first_unselected_old_region = candidates[_last_old_collection_candidate].get_region()->index();
434 const size_t last_unselected_old_region = candidates[cand_idx - 1].get_region()->index();
435 size_t span_of_uncollected_regions = 1 + last_unselected_old_region - first_unselected_old_region;
436
437 // Add no more than 1/8 of the existing old-gen regions to the set of mixed evacuation candidates.
438 const int MAX_FRACTION_OF_HUMONGOUS_DEFRAG_REGIONS = 8;
439 const size_t bound_on_additional_regions = cand_idx / MAX_FRACTION_OF_HUMONGOUS_DEFRAG_REGIONS;
440
441 // The heuristic old_is_fragmented trigger may be seeking to achieve up to 75% density. Allow ourselves to overshoot
442 // that target (at 7/8) so we will not have to do another defragmenting old collection right away.
443 while ((defrag_count < bound_on_additional_regions) &&
444 (total_uncollected_old_regions < 7 * span_of_uncollected_regions / 8)) {
445 ShenandoahHeapRegion* r = candidates[_last_old_collection_candidate].get_region();
446 assert(r->is_regular() || r->is_regular_pinned(), "Region " SIZE_FORMAT " has wrong state for collection: %s",
447 r->index(), ShenandoahHeapRegion::region_state_to_string(r->state()));
448 const size_t region_garbage = r->garbage();
449 const size_t region_free = r->free();
450 candidates_garbage += region_garbage;
451 unfragmented += region_free;
452 defrag_count++;
453 _last_old_collection_candidate++;
454
455 // We now have one fewer uncollected regions, and our uncollected span shrinks because we have removed its first region.
456 total_uncollected_old_regions--;
457 span_of_uncollected_regions =
458 1 + last_unselected_old_region - candidates[_last_old_collection_candidate].get_region()->index();
459 }
460 }
461
462 // Note that we do not coalesce and fill occupied humongous regions
463 // HR: humongous regions, RR: regular regions, CF: coalesce and fill regions
464 const size_t collectable_garbage = immediate_garbage + candidates_garbage;
465 const size_t old_candidates = _last_old_collection_candidate;
466 const size_t mixed_evac_live = old_candidates * region_size_bytes - (candidates_garbage + unfragmented);
467 set_unprocessed_old_collection_candidates_live_memory(mixed_evac_live);
468
469 log_info(gc, ergo)("Old-Gen Collectable Garbage: " PROPERFMT " consolidated with free: " PROPERFMT ", over " SIZE_FORMAT " regions",
470 PROPERFMTARGS(collectable_garbage), PROPERFMTARGS(unfragmented), old_candidates);
471 log_info(gc, ergo)("Old-Gen Immediate Garbage: " PROPERFMT " over " SIZE_FORMAT " regions",
472 PROPERFMTARGS(immediate_garbage), immediate_regions);
473 log_info(gc, ergo)("Old regions selected for defragmentation: " SIZE_FORMAT, defrag_count);
474 log_info(gc, ergo)("Old regions not selected: " SIZE_FORMAT, total_uncollected_old_regions);
475
476 if (unprocessed_old_collection_candidates() > 0) {
477 _old_generation->transition_to(ShenandoahOldGeneration::EVACUATING);
478 } else if (has_coalesce_and_fill_candidates()) {
479 _old_generation->transition_to(ShenandoahOldGeneration::FILLING);
480 } else {
481 _old_generation->transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
482 }
483 }
484
485 size_t ShenandoahOldHeuristics::unprocessed_old_collection_candidates_live_memory() const {
486 return _live_bytes_in_unprocessed_candidates;
487 }
488
489 void ShenandoahOldHeuristics::set_unprocessed_old_collection_candidates_live_memory(size_t initial_live) {
490 _live_bytes_in_unprocessed_candidates = initial_live;
491 }
492
493 void ShenandoahOldHeuristics::decrease_unprocessed_old_collection_candidates_live_memory(size_t evacuated_live) {
494 assert(evacuated_live <= _live_bytes_in_unprocessed_candidates, "Cannot evacuate more than was present");
495 _live_bytes_in_unprocessed_candidates -= evacuated_live;
496 }
497
498 // Used by unit test: test_shenandoahOldHeuristic.cpp
499 uint ShenandoahOldHeuristics::last_old_collection_candidate_index() const {
500 return _last_old_collection_candidate;
501 }
502
503 uint ShenandoahOldHeuristics::unprocessed_old_collection_candidates() const {
504 return _last_old_collection_candidate - _next_old_collection_candidate;
505 }
506
507 ShenandoahHeapRegion* ShenandoahOldHeuristics::next_old_collection_candidate() {
508 while (_next_old_collection_candidate < _last_old_collection_candidate) {
509 ShenandoahHeapRegion* next = _region_data[_next_old_collection_candidate].get_region();
510 if (!next->is_pinned()) {
511 return next;
512 } else {
513 assert(next->is_pinned(), "sanity");
514 if (_first_pinned_candidate == NOT_FOUND) {
515 _first_pinned_candidate = _next_old_collection_candidate;
516 }
517 }
518
519 _next_old_collection_candidate++;
520 }
521 return nullptr;
522 }
523
524 void ShenandoahOldHeuristics::consume_old_collection_candidate() {
525 _next_old_collection_candidate++;
526 }
527
528 unsigned int ShenandoahOldHeuristics::get_coalesce_and_fill_candidates(ShenandoahHeapRegion** buffer) {
529 uint end = _last_old_region;
530 uint index = _next_old_collection_candidate;
531 while (index < end) {
532 *buffer++ = _region_data[index++].get_region();
533 }
534 return (_last_old_region - _next_old_collection_candidate);
535 }
536
537 void ShenandoahOldHeuristics::abandon_collection_candidates() {
538 _last_old_collection_candidate = 0;
539 _next_old_collection_candidate = 0;
540 _last_old_region = 0;
541 }
542
543 void ShenandoahOldHeuristics::record_cycle_end() {
544 this->ShenandoahHeuristics::record_cycle_end();
545 clear_triggers();
546 }
547
548 void ShenandoahOldHeuristics::clear_triggers() {
549 // Clear any triggers that were set during mixed evacuations. Conditions may be different now that this phase has finished.
550 _cannot_expand_trigger = false;
551 _fragmentation_trigger = false;
552 _growth_trigger = false;
553 }
554
555 // This triggers old-gen collection if the number of regions "dedicated" to old generation is much larger than
556 // is required to represent the memory currently used within the old generation. This trigger looks specifically
557 // at density of the old-gen spanned region. A different mechanism triggers old-gen GC if the total number of
558 // old-gen regions (regardless of how close the regions are to one another) grows beyond an anticipated growth target.
559 void ShenandoahOldHeuristics::set_trigger_if_old_is_fragmented(size_t first_old_region, size_t last_old_region,
560 size_t old_region_count, size_t num_regions) {
561 if (ShenandoahGenerationalHumongousReserve > 0) {
562 // Our intent is to pack old-gen memory into the highest-numbered regions of the heap. Count all memory
563 // above first_old_region as the "span" of old generation.
564 size_t old_region_span = (first_old_region <= last_old_region)? (num_regions - first_old_region): 0;
565 // Given that memory at the bottom of the heap is reserved to represent humongous objects, the number of
566 // regions that old_gen is "allowed" to consume is less than the total heap size. The restriction on allowed
567 // span is not strictly enforced. This is a heuristic designed to reduce the likelihood that a humongous
568 // allocation request will require a STW full GC.
569 size_t allowed_old_gen_span = num_regions - (ShenandoahGenerationalHumongousReserve * num_regions) / 100;
570
571 size_t old_available = _old_generation->available() / HeapWordSize;
572 size_t region_size_words = ShenandoahHeapRegion::region_size_words();
573 size_t old_unaffiliated_available = _old_generation->free_unaffiliated_regions() * region_size_words;
574 assert(old_available >= old_unaffiliated_available, "sanity");
575 size_t old_fragmented_available = old_available - old_unaffiliated_available;
576
577 size_t old_words_consumed = old_region_count * region_size_words - old_fragmented_available;
578 size_t old_words_spanned = old_region_span * region_size_words;
579 double old_density = ((double) old_words_consumed) / old_words_spanned;
580
581 double old_span_percent = ((double) old_region_span) / allowed_old_gen_span;
582 if (old_span_percent > 0.50) {
583 // Squaring old_span_percent in the denominator below allows more aggressive triggering when we are
584 // above desired maximum span and less aggressive triggering when we are far below the desired maximum span.
585 double old_span_percent_squared = old_span_percent * old_span_percent;
586 if (old_density / old_span_percent_squared < 0.75) {
587 // We trigger old defragmentation, for example, if:
588 // old_span_percent is 110% and old_density is below 90.8%, or
589 // old_span_percent is 100% and old_density is below 75.0%, or
590 // old_span_percent is 90% and old_density is below 60.8%, or
591 // old_span_percent is 80% and old_density is below 48.0%, or
592 // old_span_percent is 70% and old_density is below 36.8%, or
593 // old_span_percent is 60% and old_density is below 27.0%, or
594 // old_span_percent is 50% and old_density is below 18.8%.
595
596 // Set the fragmentation trigger and related attributes
597 _fragmentation_trigger = true;
598 _fragmentation_density = old_density;
599 _fragmentation_first_old_region = first_old_region;
600 _fragmentation_last_old_region = last_old_region;
601 }
602 }
603 }
604 }
605
606 void ShenandoahOldHeuristics::set_trigger_if_old_is_overgrown() {
607 size_t old_used = _old_generation->used() + _old_generation->get_humongous_waste();
608 size_t trigger_threshold = _old_generation->usage_trigger_threshold();
609 // Detects unsigned arithmetic underflow
610 assert(old_used <= _heap->capacity(),
611 "Old used (" SIZE_FORMAT ", " SIZE_FORMAT") must not be more than heap capacity (" SIZE_FORMAT ")",
612 _old_generation->used(), _old_generation->get_humongous_waste(), _heap->capacity());
613 if (old_used > trigger_threshold) {
614 _growth_trigger = true;
615 }
616 }
617
618 void ShenandoahOldHeuristics::evaluate_triggers(size_t first_old_region, size_t last_old_region,
619 size_t old_region_count, size_t num_regions) {
620 set_trigger_if_old_is_fragmented(first_old_region, last_old_region, old_region_count, num_regions);
621 set_trigger_if_old_is_overgrown();
622 }
623
624 bool ShenandoahOldHeuristics::should_resume_old_cycle() {
625 // If we are preparing to mark old, or if we are already marking old, then try to continue that work.
626 if (_old_generation->is_concurrent_mark_in_progress()) {
627 assert(_old_generation->state() == ShenandoahOldGeneration::MARKING, "Unexpected old gen state: %s", _old_generation->state_name());
628 log_trigger("Resume marking old");
629 return true;
630 }
631
632 if (_old_generation->is_preparing_for_mark()) {
633 assert(_old_generation->state() == ShenandoahOldGeneration::FILLING, "Unexpected old gen state: %s", _old_generation->state_name());
634 log_trigger("Resume preparing to mark old");
635 return true;
636 }
637
638 return false;
639 }
640
641 bool ShenandoahOldHeuristics::should_start_gc() {
642
643 const ShenandoahHeap* heap = ShenandoahHeap::heap();
644 if (_old_generation->is_doing_mixed_evacuations()) {
645 // Do not try to start an old cycle if we are waiting for old regions to be evacuated (we need
646 // a young cycle for this). Note that the young heuristic has a feature to expedite old evacuations.
647 // Future refinement: under certain circumstances, we might be more sophisticated about this choice.
648 // For example, we could choose to abandon the previous old collection before it has completed evacuations.
649 log_debug(gc)("Not starting an old cycle because we are waiting for mixed evacuations");
650 return false;
651 }
652
653 if (_cannot_expand_trigger) {
654 const size_t old_gen_capacity = _old_generation->max_capacity();
655 const size_t heap_capacity = heap->capacity();
656 const double percent = percent_of(old_gen_capacity, heap_capacity);
657 log_trigger("Expansion failure, current size: " SIZE_FORMAT "%s which is %.1f%% of total heap size",
658 byte_size_in_proper_unit(old_gen_capacity), proper_unit_for_byte_size(old_gen_capacity), percent);
659 return true;
660 }
661
662 if (_fragmentation_trigger) {
663 const size_t used = _old_generation->used();
664 const size_t used_regions_size = _old_generation->used_regions_size();
665
666 // used_regions includes humongous regions
667 const size_t used_regions = _old_generation->used_regions();
668 assert(used_regions_size > used_regions, "Cannot have more used than used regions");
669
670 size_t first_old_region, last_old_region;
671 double density;
672 get_fragmentation_trigger_reason_for_log_message(density, first_old_region, last_old_region);
673 const size_t span_of_old_regions = (last_old_region >= first_old_region)? last_old_region + 1 - first_old_region: 0;
674 const size_t fragmented_free = used_regions_size - used;
675
676 log_trigger("Old has become fragmented: "
677 SIZE_FORMAT "%s available bytes spread between range spanned from "
678 SIZE_FORMAT " to " SIZE_FORMAT " (" SIZE_FORMAT "), density: %.1f%%",
679 byte_size_in_proper_unit(fragmented_free), proper_unit_for_byte_size(fragmented_free),
680 first_old_region, last_old_region, span_of_old_regions, density * 100);
681 return true;
682 }
683
684 if (_growth_trigger) {
685 // Growth may be falsely triggered during mixed evacuations, before the mixed-evacuation candidates have been
686 // evacuated. Before acting on a false trigger, we check to confirm the trigger condition is still satisfied.
687 const size_t current_usage = _old_generation->used() + _old_generation->get_humongous_waste();
688 const size_t trigger_threshold = _old_generation->usage_trigger_threshold();
689 const size_t heap_size = heap->capacity();
690 const size_t ignore_threshold = (ShenandoahIgnoreOldGrowthBelowPercentage * heap_size) / 100;
691 size_t consecutive_young_cycles;
692 if ((current_usage < ignore_threshold) &&
693 ((consecutive_young_cycles = heap->shenandoah_policy()->consecutive_young_gc_count())
694 < ShenandoahDoNotIgnoreGrowthAfterYoungCycles)) {
695 log_debug(gc)("Ignoring Trigger: Old has overgrown: usage (" SIZE_FORMAT "%s) is below threshold ("
696 SIZE_FORMAT "%s) after " SIZE_FORMAT " consecutive completed young GCs",
697 byte_size_in_proper_unit(current_usage), proper_unit_for_byte_size(current_usage),
698 byte_size_in_proper_unit(ignore_threshold), proper_unit_for_byte_size(ignore_threshold),
699 consecutive_young_cycles);
700 _growth_trigger = false;
701 } else if (current_usage > trigger_threshold) {
702 const size_t live_at_previous_old = _old_generation->get_live_bytes_after_last_mark();
703 const double percent_growth = percent_of(current_usage - live_at_previous_old, live_at_previous_old);
704 log_trigger("Old has overgrown, live at end of previous OLD marking: "
705 SIZE_FORMAT "%s, current usage: " SIZE_FORMAT "%s, percent growth: %.1f%%",
706 byte_size_in_proper_unit(live_at_previous_old), proper_unit_for_byte_size(live_at_previous_old),
707 byte_size_in_proper_unit(current_usage), proper_unit_for_byte_size(current_usage), percent_growth);
708 return true;
709 } else {
710 // Mixed evacuations have decreased current_usage such that old-growth trigger is no longer relevant.
711 _growth_trigger = false;
712 }
713 }
714
715 // Otherwise, defer to inherited heuristic for gc trigger.
716 return this->ShenandoahHeuristics::should_start_gc();
717 }
718
719 void ShenandoahOldHeuristics::record_success_concurrent() {
720 // Forget any triggers that occurred while OLD GC was ongoing. If we really need to start another, it will retrigger.
721 clear_triggers();
722 this->ShenandoahHeuristics::record_success_concurrent();
723 }
724
725 void ShenandoahOldHeuristics::record_success_degenerated() {
726 // Forget any triggers that occurred while OLD GC was ongoing. If we really need to start another, it will retrigger.
727 clear_triggers();
728 this->ShenandoahHeuristics::record_success_degenerated();
729 }
730
731 void ShenandoahOldHeuristics::record_success_full() {
732 // Forget any triggers that occurred while OLD GC was ongoing. If we really need to start another, it will retrigger.
733 clear_triggers();
734 this->ShenandoahHeuristics::record_success_full();
735 }
736
737 const char* ShenandoahOldHeuristics::name() {
738 return "Old";
739 }
740
741 bool ShenandoahOldHeuristics::is_diagnostic() {
742 return false;
743 }
744
745 bool ShenandoahOldHeuristics::is_experimental() {
746 return true;
747 }
748
749 void ShenandoahOldHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* set,
750 ShenandoahHeuristics::RegionData* data,
751 size_t data_size, size_t free) {
752 ShouldNotReachHere();
753 }