33 |
33 |
34 ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics() : |
34 ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics() : |
35 ShenandoahHeuristics(), |
35 ShenandoahHeuristics(), |
36 _cycle_gap_history(new TruncatedSeq(5)), |
36 _cycle_gap_history(new TruncatedSeq(5)), |
37 _conc_mark_duration_history(new TruncatedSeq(5)), |
37 _conc_mark_duration_history(new TruncatedSeq(5)), |
38 _conc_uprefs_duration_history(new TruncatedSeq(5)) { |
38 _conc_uprefs_duration_history(new TruncatedSeq(5)) {} |
39 |
|
40 SHENANDOAH_ERGO_ENABLE_FLAG(ExplicitGCInvokesConcurrent); |
|
41 SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent); |
|
42 |
|
43 // Final configuration checks |
|
44 SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier); |
|
45 SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier); |
|
46 SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier); |
|
47 SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); |
|
48 SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); |
|
49 } |
|
50 |
39 |
51 ShenandoahAdaptiveHeuristics::~ShenandoahAdaptiveHeuristics() {} |
40 ShenandoahAdaptiveHeuristics::~ShenandoahAdaptiveHeuristics() {} |
52 |
41 |
53 void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, |
42 void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, |
54 RegionData* data, size_t size, |
43 RegionData* data, size_t size, |
75 size_t capacity = ShenandoahHeap::heap()->max_capacity(); |
64 size_t capacity = ShenandoahHeap::heap()->max_capacity(); |
76 size_t free_target = capacity / 100 * ShenandoahMinFreeThreshold; |
65 size_t free_target = capacity / 100 * ShenandoahMinFreeThreshold; |
77 size_t min_garbage = free_target > actual_free ? (free_target - actual_free) : 0; |
66 size_t min_garbage = free_target > actual_free ? (free_target - actual_free) : 0; |
78 size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste); |
67 size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste); |
79 |
68 |
80 log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "M, Actual Free: " |
69 log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "%s, Actual Free: " |
81 SIZE_FORMAT "M, Max CSet: " SIZE_FORMAT "M, Min Garbage: " SIZE_FORMAT "M", |
70 SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s, Min Garbage: " SIZE_FORMAT "%s", |
82 free_target / M, actual_free / M, max_cset / M, min_garbage / M); |
71 byte_size_in_proper_unit(free_target), proper_unit_for_byte_size(free_target), |
|
72 byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free), |
|
73 byte_size_in_proper_unit(max_cset), proper_unit_for_byte_size(max_cset), |
|
74 byte_size_in_proper_unit(min_garbage), proper_unit_for_byte_size(min_garbage)); |
83 |
75 |
84 // Better select garbage-first regions |
76 // Better select garbage-first regions |
85 QuickSort::sort<RegionData>(data, (int)size, compare_by_garbage, false); |
77 QuickSort::sort<RegionData>(data, (int)size, compare_by_garbage, false); |
86 |
78 |
87 size_t cur_cset = 0; |
79 size_t cur_cset = 0; |
119 } else if (phase == ShenandoahPhaseTimings::conc_update_refs) { |
111 } else if (phase == ShenandoahPhaseTimings::conc_update_refs) { |
120 _conc_uprefs_duration_history->add(secs); |
112 _conc_uprefs_duration_history->add(secs); |
121 } // Else ignore |
113 } // Else ignore |
122 } |
114 } |
123 |
115 |
124 bool ShenandoahAdaptiveHeuristics::should_start_normal_gc() const { |
116 bool ShenandoahAdaptiveHeuristics::should_start_gc() const { |
125 ShenandoahHeap* heap = ShenandoahHeap::heap(); |
117 ShenandoahHeap* heap = ShenandoahHeap::heap(); |
126 size_t capacity = heap->max_capacity(); |
118 size_t capacity = heap->max_capacity(); |
127 size_t available = heap->free_set()->available(); |
119 size_t available = heap->free_set()->available(); |
128 |
120 |
129 // Check if we are falling below the worst limit, time to trigger the GC, regardless of |
121 // Check if we are falling below the worst limit, time to trigger the GC, regardless of |
130 // anything else. |
122 // anything else. |
131 size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; |
123 size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; |
132 if (available < min_threshold) { |
124 if (available < min_threshold) { |
133 log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)", |
125 log_info(gc)("Trigger: Free (" SIZE_FORMAT "%s) is below minimum threshold (" SIZE_FORMAT "%s)", |
134 available / M, min_threshold / M); |
126 byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), |
|
127 byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold)); |
135 return true; |
128 return true; |
136 } |
129 } |
137 |
130 |
138 // Check if are need to learn a bit about the application |
131 // Check if are need to learn a bit about the application |
139 const size_t max_learn = ShenandoahLearningSteps; |
132 const size_t max_learn = ShenandoahLearningSteps; |
140 if (_gc_times_learned < max_learn) { |
133 if (_gc_times_learned < max_learn) { |
141 size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold; |
134 size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold; |
142 if (available < init_threshold) { |
135 if (available < init_threshold) { |
143 log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "M) is below initial threshold (" SIZE_FORMAT "M)", |
136 log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "%s) is below initial threshold (" SIZE_FORMAT "%s)", |
144 _gc_times_learned + 1, max_learn, available / M, init_threshold / M); |
137 _gc_times_learned + 1, max_learn, |
|
138 byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), |
|
139 byte_size_in_proper_unit(init_threshold), proper_unit_for_byte_size(init_threshold)); |
145 return true; |
140 return true; |
146 } |
141 } |
147 } |
142 } |
148 |
143 |
149 // Check if allocation headroom is still okay. This also factors in: |
144 // Check if allocation headroom is still okay. This also factors in: |
163 double average_gc = _gc_time_history->avg(); |
158 double average_gc = _gc_time_history->avg(); |
164 double time_since_last = time_since_last_gc(); |
159 double time_since_last = time_since_last_gc(); |
165 double allocation_rate = heap->bytes_allocated_since_gc_start() / time_since_last; |
160 double allocation_rate = heap->bytes_allocated_since_gc_start() / time_since_last; |
166 |
161 |
167 if (average_gc > allocation_headroom / allocation_rate) { |
162 if (average_gc > allocation_headroom / allocation_rate) { |
168 log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for allocation rate (%.2f MB/s) to deplete free headroom (" SIZE_FORMAT "M)", |
163 log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s)", |
169 average_gc * 1000, allocation_rate / M, allocation_headroom / M); |
164 average_gc * 1000, |
170 log_info(gc, ergo)("Free headroom: " SIZE_FORMAT "M (free) - " SIZE_FORMAT "M (spike) - " SIZE_FORMAT "M (penalties) = " SIZE_FORMAT "M", |
165 byte_size_in_proper_unit(allocation_rate), proper_unit_for_byte_size(allocation_rate), |
171 available / M, spike_headroom / M, penalties / M, allocation_headroom / M); |
166 byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom)); |
|
167 log_info(gc, ergo)("Free headroom: " SIZE_FORMAT "%s (free) - " SIZE_FORMAT "%s (spike) - " SIZE_FORMAT "%s (penalties) = " SIZE_FORMAT "%s", |
|
168 byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), |
|
169 byte_size_in_proper_unit(spike_headroom), proper_unit_for_byte_size(spike_headroom), |
|
170 byte_size_in_proper_unit(penalties), proper_unit_for_byte_size(penalties), |
|
171 byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom)); |
172 return true; |
172 return true; |
173 } |
173 } |
174 |
174 |
175 return ShenandoahHeuristics::should_start_normal_gc(); |
175 return ShenandoahHeuristics::should_start_gc(); |
176 } |
176 } |
177 |
177 |
178 bool ShenandoahAdaptiveHeuristics::should_start_update_refs() { |
178 bool ShenandoahAdaptiveHeuristics::should_start_update_refs() { |
179 if (! _update_refs_adaptive) { |
179 if (! _update_refs_adaptive) { |
180 return _update_refs_early; |
180 return _update_refs_early; |