35 NumberSeq _allocation_rate_bytes; 36 NumberSeq _reclamation_rate_bytes; 37 38 size_t _bytes_allocated_since_CM; 39 size_t _bytes_reclaimed_this_cycle; 40 41 protected: 42 typedef struct { 43 size_t region_number; 44 size_t garbage; 45 } RegionGarbage; 46 47 static int compare_by_garbage(RegionGarbage a, RegionGarbage b) { 48 if (a.garbage > b.garbage) 49 return -1; 50 else if (b.garbage < a.garbage) 51 return 1; 52 else return 0; 53 } 54 55 RegionGarbage* _region_garbage; 56 size_t _region_garbage_size; 57 58 size_t _bytes_allocated_start_CM; 59 size_t _bytes_allocated_during_CM; 60 61 size_t _bytes_allocated_after_last_gc; 62 63 uint _cancelled_cm_cycles_in_a_row; 64 uint _successful_cm_cycles_in_a_row; 65 66 size_t _bytes_in_cset; 67 68 public: 69 70 ShenandoahHeuristics(); 71 ~ShenandoahHeuristics(); 72 73 void record_bytes_allocated(size_t bytes); 74 void record_bytes_reclaimed(size_t bytes); 157 _region_garbage_size(0) 158 { 159 } 160 161 ShenandoahHeuristics::~ShenandoahHeuristics() { 162 if (_region_garbage != NULL) { 163 FREE_C_HEAP_ARRAY(RegionGarbage, _region_garbage); 164 } 165 } 166 167 void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set, int* connections) { 168 start_choose_collection_set(); 169 170 ShenandoahHeap* heap = ShenandoahHeap::heap(); 171 172 // Step 1. Build up the region candidates we care about, rejecting losers and accepting winners right away. 173 174 ShenandoahHeapRegionSet* regions = heap->regions(); 175 size_t active = regions->active_regions(); 176 177 RegionGarbage* candidates = _region_garbage; 178 if (candidates == NULL) { 179 candidates = NEW_C_HEAP_ARRAY(RegionGarbage, active, mtGC); 180 _region_garbage_size = active; 181 } else if (_region_garbage_size < active) { 182 REALLOC_C_HEAP_ARRAY(RegionGarbage, _region_garbage, active, mtGC); 183 _region_garbage_size = active; 184 } 185 186 size_t cand_idx = 0; 187 _bytes_in_cset = 0; 188 189 size_t immediate_garbage = 0; 190 size_t immediate_regions = 0; 191 for (size_t i = 0; i < active; i++) { 192 ShenandoahHeapRegion* region = regions->get(i); 193 194 if (! region->is_humongous() && ! region->is_pinned()) { 195 if ((! region->is_empty()) && ! region->has_live()) { 196 // We can recycle it right away and put it in the free set. 197 immediate_regions++; 198 immediate_garbage += region->garbage(); 199 heap->decrease_used(region->used()); 200 region->recycle(); 201 log_develop_trace(gc)("Choose region " SIZE_FORMAT " for immediate reclaim with garbage = " SIZE_FORMAT 202 " and live = " SIZE_FORMAT "\n", 203 region->region_number(), region->garbage(), region->get_live_data_bytes()); 204 } else { 205 // This is our candidate for later consideration. 206 candidates[cand_idx].region_number = region->region_number(); 207 candidates[cand_idx].garbage = region->garbage(); 208 cand_idx++; 209 } 210 } else { 211 assert(region->has_live() || region->is_empty() || region->is_pinned() || region->is_humongous(), "check rejected"); 212 log_develop_trace(gc)("Rejected region " SIZE_FORMAT " with garbage = " SIZE_FORMAT 213 " and live = " SIZE_FORMAT "\n", 214 region->region_number(), region->garbage(), region->get_live_data_bytes()); 215 } 216 } 217 218 // Step 2. Process the remanining candidates, if any. 219 220 if (cand_idx > 0) { 221 if (needs_regions_sorted_by_garbage()) { 222 QuickSort::sort<RegionGarbage>(candidates, cand_idx, compare_by_garbage, false); 223 } 224 225 for (size_t i = 0; i < cand_idx; i++) { 226 ShenandoahHeapRegion *region = regions->get_fast(candidates[i].region_number); 227 if (region_in_collection_set(region, immediate_garbage)) { 228 log_develop_trace(gc)("Choose region " SIZE_FORMAT " with garbage = " SIZE_FORMAT 229 " and live = " SIZE_FORMAT "\n", 230 region->region_number(), region->garbage(), region->get_live_data_bytes()); 231 collection_set->add_region(region); 232 region->set_in_collection_set(true); 233 _bytes_in_cset += region->used(); 234 } 235 } 236 } 237 238 end_choose_collection_set(); 239 240 size_t total_garbage = heap->garbage(); 241 log_debug(gc)("Total Garbage: "SIZE_FORMAT, total_garbage); 242 log_debug(gc)("Immediate Garbage: "SIZE_FORMAT, immediate_garbage); 564 double _garbage_threshold_factor; 565 double _allocation_threshold_factor; 566 567 uintx _used_threshold; 568 uintx _garbage_threshold; 569 uintx _allocation_threshold; 570 571 public: 572 ConnectionHeuristics() : ShenandoahHeuristics() { 573 _max_live_data = 0; 574 575 _used_threshold = 0; 576 _garbage_threshold = 0; 577 _allocation_threshold = 0; 578 579 _used_threshold_factor = 0.; 580 _garbage_threshold_factor = 0.1; 581 _allocation_threshold_factor = 0.; 582 } 583 584 virtual ~ConnectionHeuristics() {} 585 586 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 587 size_t half_gig = 64 * 1024 * 1024; 588 size_t bytes_alloc = ShenandoahHeap::heap()->bytes_allocated_since_cm(); 589 bool result = bytes_alloc > half_gig; 590 if (result) tty->print("Starting a concurrent mark"); 591 return result; 592 } 593 594 bool maybe_add_heap_region(ShenandoahHeapRegion* hr, ShenandoahCollectionSet* collection_set) { 595 if (!hr->is_humongous() && hr->has_live() && !collection_set->contains(hr)) { 596 collection_set->add_region_check_for_duplicates(hr); 597 hr->set_in_collection_set(true); 598 return true; 599 } 600 return false; 601 } 602 603 virtual void choose_collection_set(ShenandoahCollectionSet* collection_set, int* connections) { 604 ShenandoahHeapRegionSet* regions = ShenandoahHeap::heap()->regions(); 605 size_t end = regions->active_regions(); 606 RegionGarbage sorted_by_garbage[end]; 607 for (size_t i = 0; i < end; i++) { 608 ShenandoahHeapRegion* r = regions->get_fast(i); 609 sorted_by_garbage[i].region_number = r->region_number(); 610 sorted_by_garbage[i].garbage = r->garbage(); 611 } 612 613 QuickSort::sort<RegionGarbage>(sorted_by_garbage, end, compare_by_garbage, false); 614 615 int num = ShenandoahHeap::heap()->num_regions(); 616 // simulate write heuristics by picking best region. 617 int r = 0; 618 ShenandoahHeapRegion* choosenOne = regions->get(sorted_by_garbage[0].region_number); 619 620 while (! maybe_add_heap_region(choosenOne, collection_set)) { 621 choosenOne = regions->get(sorted_by_garbage[++r].region_number); 622 } 623 624 int region_number = choosenOne->region_number(); 625 log_develop_trace(gc)("Adding choosen region %d\n", region_number); 626 627 // Add all the regions which point to this region. 628 for (int i = 0; i < num; i++) { 629 if (connections[i * num + region_number] > 0) { 630 ShenandoahHeapRegion* candidate = regions->get(sorted_by_garbage[i].region_number); 631 if (maybe_add_heap_region(candidate, collection_set)) 632 log_develop_trace(gc)("Adding region %d which points to the choosen region\n", i); 633 } 634 } 635 636 // Add all the regions they point to. 637 for (size_t ci = 0; ci < collection_set->active_regions(); ci++) { 638 ShenandoahHeapRegion* cs_heap_region = collection_set->get(ci); 639 int cs_heap_region_number = cs_heap_region->region_number(); 640 for (int i = 0; i < num; i++) { 641 if (connections[i * num + cs_heap_region_number] > 0) { 642 ShenandoahHeapRegion* candidate = regions->get(sorted_by_garbage[i].region_number); 643 if (maybe_add_heap_region(candidate, collection_set)) { 644 log_develop_trace(gc) 645 ("Adding region %d which is pointed to by region %d\n", i, cs_heap_region_number); 646 } 647 } 648 } 649 } 650 _max_live_data = MAX2(_max_live_data, collection_set->live_data()); 651 collection_set->print(); 652 } 653 654 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) { 655 assert(false, "Shouldn't get here"); 656 return false; 657 } 658 }; 659 class PartialHeuristics : public AdaptiveHeuristics { 660 public: 661 PartialHeuristics() : AdaptiveHeuristics() { 662 if (FLAG_IS_DEFAULT(ShenandoahAllocationThreshold)) { 663 FLAG_SET_DEFAULT(ShenandoahAllocationThreshold, 5); 664 } 665 FLAG_SET_DEFAULT(UseShenandoahMatrix, true); | 35 NumberSeq _allocation_rate_bytes; 36 NumberSeq _reclamation_rate_bytes; 37 38 size_t _bytes_allocated_since_CM; 39 size_t _bytes_reclaimed_this_cycle; 40 41 protected: 42 typedef struct { 43 size_t region_number; 44 size_t garbage; 45 } RegionGarbage; 46 47 static int compare_by_garbage(RegionGarbage a, RegionGarbage b) { 48 if (a.garbage > b.garbage) 49 return -1; 50 else if (b.garbage < a.garbage) 51 return 1; 52 else return 0; 53 } 54 55 RegionGarbage* get_region_garbage_cache(size_t num) { 56 RegionGarbage* res = _region_garbage; 57 if (res == NULL) { 58 res = NEW_C_HEAP_ARRAY(RegionGarbage, num, mtGC); 59 _region_garbage_size = num; 60 } else if (_region_garbage_size < num) { 61 REALLOC_C_HEAP_ARRAY(RegionGarbage, _region_garbage, num, mtGC); 62 _region_garbage_size = num; 63 } 64 return res; 65 } 66 67 RegionGarbage* _region_garbage; 68 size_t _region_garbage_size; 69 70 size_t _bytes_allocated_start_CM; 71 size_t _bytes_allocated_during_CM; 72 73 size_t _bytes_allocated_after_last_gc; 74 75 uint _cancelled_cm_cycles_in_a_row; 76 uint _successful_cm_cycles_in_a_row; 77 78 size_t _bytes_in_cset; 79 80 public: 81 82 ShenandoahHeuristics(); 83 ~ShenandoahHeuristics(); 84 85 void record_bytes_allocated(size_t bytes); 86 void record_bytes_reclaimed(size_t bytes); 169 _region_garbage_size(0) 170 { 171 } 172 173 ShenandoahHeuristics::~ShenandoahHeuristics() { 174 if (_region_garbage != NULL) { 175 FREE_C_HEAP_ARRAY(RegionGarbage, _region_garbage); 176 } 177 } 178 179 void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set, int* connections) { 180 start_choose_collection_set(); 181 182 ShenandoahHeap* heap = ShenandoahHeap::heap(); 183 184 // Step 1. Build up the region candidates we care about, rejecting losers and accepting winners right away. 185 186 ShenandoahHeapRegionSet* regions = heap->regions(); 187 size_t active = regions->active_regions(); 188 189 RegionGarbage* candidates = get_region_garbage_cache(active); 190 191 size_t cand_idx = 0; 192 _bytes_in_cset = 0; 193 194 size_t immediate_garbage = 0; 195 size_t immediate_regions = 0; 196 for (size_t i = 0; i < active; i++) { 197 ShenandoahHeapRegion* region = regions->get(i); 198 199 if (! region->is_humongous() && ! region->is_pinned()) { 200 if ((! region->is_empty()) && ! region->has_live()) { 201 // We can recycle it right away and put it in the free set. 202 immediate_regions++; 203 immediate_garbage += region->garbage(); 204 heap->decrease_used(region->used()); 205 region->recycle(); 206 log_develop_trace(gc)("Choose region " SIZE_FORMAT " for immediate reclaim with garbage = " SIZE_FORMAT 207 " and live = " SIZE_FORMAT "\n", 208 region->region_number(), region->garbage(), region->get_live_data_bytes()); 209 } else { 210 // This is our candidate for later consideration. 211 candidates[cand_idx].region_number = region->region_number(); 212 candidates[cand_idx].garbage = region->garbage(); 213 cand_idx++; 214 } 215 } else { 216 assert(region->has_live() || region->is_empty() || region->is_pinned() || region->is_humongous(), "check rejected"); 217 log_develop_trace(gc)("Rejected region " SIZE_FORMAT " with garbage = " SIZE_FORMAT 218 " and live = " SIZE_FORMAT "\n", 219 region->region_number(), region->garbage(), region->get_live_data_bytes()); 220 } 221 } 222 223 // Step 2. Process the remanining candidates, if any. 224 225 if (cand_idx > 0) { 226 if (needs_regions_sorted_by_garbage()) { 227 QuickSort::sort<RegionGarbage>(candidates, (int)cand_idx, compare_by_garbage, false); 228 } 229 230 for (size_t i = 0; i < cand_idx; i++) { 231 ShenandoahHeapRegion *region = regions->get_fast(candidates[i].region_number); 232 if (region_in_collection_set(region, immediate_garbage)) { 233 log_develop_trace(gc)("Choose region " SIZE_FORMAT " with garbage = " SIZE_FORMAT 234 " and live = " SIZE_FORMAT "\n", 235 region->region_number(), region->garbage(), region->get_live_data_bytes()); 236 collection_set->add_region(region); 237 region->set_in_collection_set(true); 238 _bytes_in_cset += region->used(); 239 } 240 } 241 } 242 243 end_choose_collection_set(); 244 245 size_t total_garbage = heap->garbage(); 246 log_debug(gc)("Total Garbage: "SIZE_FORMAT, total_garbage); 247 log_debug(gc)("Immediate Garbage: "SIZE_FORMAT, immediate_garbage); 569 double _garbage_threshold_factor; 570 double _allocation_threshold_factor; 571 572 uintx _used_threshold; 573 uintx _garbage_threshold; 574 uintx _allocation_threshold; 575 576 public: 577 ConnectionHeuristics() : ShenandoahHeuristics() { 578 _max_live_data = 0; 579 580 _used_threshold = 0; 581 _garbage_threshold = 0; 582 _allocation_threshold = 0; 583 584 _used_threshold_factor = 0.; 585 _garbage_threshold_factor = 0.1; 586 _allocation_threshold_factor = 0.; 587 } 588 589 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 590 size_t half_gig = 64 * 1024 * 1024; 591 size_t bytes_alloc = ShenandoahHeap::heap()->bytes_allocated_since_cm(); 592 bool result = bytes_alloc > half_gig; 593 if (result) tty->print("Starting a concurrent mark"); 594 return result; 595 } 596 597 bool maybe_add_heap_region(ShenandoahHeapRegion* hr, ShenandoahCollectionSet* collection_set) { 598 if (!hr->is_humongous() && hr->has_live() && !collection_set->contains(hr)) { 599 collection_set->add_region_check_for_duplicates(hr); 600 hr->set_in_collection_set(true); 601 return true; 602 } 603 return false; 604 } 605 606 virtual void choose_collection_set(ShenandoahCollectionSet* collection_set, int* connections) { 607 ShenandoahHeapRegionSet* regions = ShenandoahHeap::heap()->regions(); 608 size_t active = regions->active_regions(); 609 610 RegionGarbage* sorted_by_garbage = get_region_garbage_cache(active); 611 for (size_t i = 0; i < active; i++) { 612 ShenandoahHeapRegion* r = regions->get_fast(i); 613 sorted_by_garbage[i].region_number = r->region_number(); 614 sorted_by_garbage[i].garbage = r->garbage(); 615 } 616 617 QuickSort::sort<RegionGarbage>(sorted_by_garbage, (int) active, compare_by_garbage, false); 618 619 size_t num = ShenandoahHeap::heap()->num_regions(); 620 // simulate write heuristics by picking best region. 621 int r = 0; 622 ShenandoahHeapRegion* choosenOne = regions->get(sorted_by_garbage[0].region_number); 623 624 while (! maybe_add_heap_region(choosenOne, collection_set)) { 625 choosenOne = regions->get(sorted_by_garbage[++r].region_number); 626 } 627 628 size_t region_number = choosenOne->region_number(); 629 log_develop_trace(gc)("Adding choosen region " SIZE_FORMAT, region_number); 630 631 // Add all the regions which point to this region. 632 for (size_t i = 0; i < num; i++) { 633 if (connections[i * num + region_number] > 0) { 634 ShenandoahHeapRegion* candidate = regions->get(sorted_by_garbage[i].region_number); 635 if (maybe_add_heap_region(candidate, collection_set)) 636 log_develop_trace(gc)("Adding region " SIZE_FORMAT " which points to the choosen region", i); 637 } 638 } 639 640 // Add all the regions they point to. 641 for (size_t ci = 0; ci < collection_set->active_regions(); ci++) { 642 ShenandoahHeapRegion* cs_heap_region = collection_set->get(ci); 643 size_t cs_heap_region_number = cs_heap_region->region_number(); 644 for (size_t i = 0; i < num; i++) { 645 if (connections[i * num + cs_heap_region_number] > 0) { 646 ShenandoahHeapRegion* candidate = regions->get(sorted_by_garbage[i].region_number); 647 if (maybe_add_heap_region(candidate, collection_set)) { 648 log_develop_trace(gc) 649 ("Adding region " SIZE_FORMAT " which is pointed to by region " SIZE_FORMAT, i, cs_heap_region_number); 650 } 651 } 652 } 653 } 654 _max_live_data = MAX2(_max_live_data, collection_set->live_data()); 655 collection_set->print(); 656 } 657 658 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) { 659 assert(false, "Shouldn't get here"); 660 return false; 661 } 662 }; 663 class PartialHeuristics : public AdaptiveHeuristics { 664 public: 665 PartialHeuristics() : AdaptiveHeuristics() { 666 if (FLAG_IS_DEFAULT(ShenandoahAllocationThreshold)) { 667 FLAG_SET_DEFAULT(ShenandoahAllocationThreshold, 5); 668 } 669 FLAG_SET_DEFAULT(UseShenandoahMatrix, true); |