Mercurial > hg > truffle
comparison src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @ 4912:a9647476d1a4
7132029: G1: mixed GC phase lasts for longer than it should
Summary: Revamp of the mechanism that chooses old regions for inclusion in the CSet. It simplifies the code and introduces min and max bounds on the number of old regions added to the CSet at each mixed GC to avoid pathological cases. It also ensures that when we do a mixed GC we'll always find old regions to add to the CSet (i.e., it eliminates the case where a mixed GC will collect no old regions which can happen today).
Reviewed-by: johnc, brutisso
author | tonyp |
---|---|
date | Wed, 15 Feb 2012 13:06:53 -0500 |
parents | eff609af17d7 |
children | 21595f05bc93 |
comparison
equal
deleted
inserted
replaced
4911:d903bf750e9f | 4912:a9647476d1a4 |
---|---|
204 | 204 |
205 _all_full_gc_times_ms(new NumberSeq()), | 205 _all_full_gc_times_ms(new NumberSeq()), |
206 | 206 |
207 _initiate_conc_mark_if_possible(false), | 207 _initiate_conc_mark_if_possible(false), |
208 _during_initial_mark_pause(false), | 208 _during_initial_mark_pause(false), |
209 _should_revert_to_young_gcs(false), | |
210 _last_young_gc(false), | 209 _last_young_gc(false), |
211 _last_gc_was_young(false), | 210 _last_gc_was_young(false), |
212 | 211 |
213 _eden_bytes_before_gc(0), | 212 _eden_bytes_before_gc(0), |
214 _survivor_bytes_before_gc(0), | 213 _survivor_bytes_before_gc(0), |
292 _par_last_termination_times_ms = new double[_parallel_gc_threads]; | 291 _par_last_termination_times_ms = new double[_parallel_gc_threads]; |
293 _par_last_termination_attempts = new double[_parallel_gc_threads]; | 292 _par_last_termination_attempts = new double[_parallel_gc_threads]; |
294 _par_last_gc_worker_end_times_ms = new double[_parallel_gc_threads]; | 293 _par_last_gc_worker_end_times_ms = new double[_parallel_gc_threads]; |
295 _par_last_gc_worker_times_ms = new double[_parallel_gc_threads]; | 294 _par_last_gc_worker_times_ms = new double[_parallel_gc_threads]; |
296 _par_last_gc_worker_other_times_ms = new double[_parallel_gc_threads]; | 295 _par_last_gc_worker_other_times_ms = new double[_parallel_gc_threads]; |
297 | |
298 // start conservatively | |
299 _expensive_region_limit_ms = 0.5 * (double) MaxGCPauseMillis; | |
300 | 296 |
301 int index; | 297 int index; |
302 if (ParallelGCThreads == 0) | 298 if (ParallelGCThreads == 0) |
303 index = 0; | 299 index = 0; |
304 else if (ParallelGCThreads > 8) | 300 else if (ParallelGCThreads > 8) |
627 // Don't calculate anything and let the code below bound it to | 623 // Don't calculate anything and let the code below bound it to |
628 // the desired_min_length, i.e., do the next GC as soon as | 624 // the desired_min_length, i.e., do the next GC as soon as |
629 // possible to maximize how many old regions we can add to it. | 625 // possible to maximize how many old regions we can add to it. |
630 } | 626 } |
631 } else { | 627 } else { |
632 if (gcs_are_young()) { | 628 // The user asked for a fixed young gen so we'll fix the young gen |
633 young_list_target_length = _young_list_fixed_length; | 629 // whether the next GC is young or mixed. |
634 } else { | 630 young_list_target_length = _young_list_fixed_length; |
635 // A bit arbitrary: during mixed GCs we allocate half | |
636 // the young regions to try to add old regions to the CSet. | |
637 young_list_target_length = _young_list_fixed_length / 2; | |
638 // We choose to accept that we might go under the desired min | |
639 // length given that we intentionally ask for a smaller young gen. | |
640 desired_min_length = absolute_min_length; | |
641 } | |
642 } | 631 } |
643 | 632 |
644 // Make sure we don't go over the desired max length, nor under the | 633 // Make sure we don't go over the desired max length, nor under the |
645 // desired min length. In case they clash, desired_min_length wins | 634 // desired min length. In case they clash, desired_min_length wins |
646 // which is why that test is second. | 635 // which is why that test is second. |
870 | 859 |
871 // "Nuke" the heuristics that control the young/mixed GC | 860 // "Nuke" the heuristics that control the young/mixed GC |
872 // transitions and make sure we start with young GCs after the Full GC. | 861 // transitions and make sure we start with young GCs after the Full GC. |
873 set_gcs_are_young(true); | 862 set_gcs_are_young(true); |
874 _last_young_gc = false; | 863 _last_young_gc = false; |
875 _should_revert_to_young_gcs = false; | |
876 clear_initiate_conc_mark_if_possible(); | 864 clear_initiate_conc_mark_if_possible(); |
877 clear_during_initial_mark_pause(); | 865 clear_during_initial_mark_pause(); |
878 _known_garbage_bytes = 0; | 866 _known_garbage_bytes = 0; |
879 _known_garbage_ratio = 0.0; | 867 _known_garbage_ratio = 0.0; |
880 _in_marking_window = false; | 868 _in_marking_window = false; |
887 | 875 |
888 _free_regions_at_end_of_collection = _g1->free_regions(); | 876 _free_regions_at_end_of_collection = _g1->free_regions(); |
889 // Reset survivors SurvRateGroup. | 877 // Reset survivors SurvRateGroup. |
890 _survivor_surv_rate_group->reset(); | 878 _survivor_surv_rate_group->reset(); |
891 update_young_list_target_length(); | 879 update_young_list_target_length(); |
892 _collectionSetChooser->updateAfterFullCollection(); | 880 _collectionSetChooser->clearMarkedHeapRegions(); |
893 } | 881 } |
894 | 882 |
895 void G1CollectorPolicy::record_stop_world_start() { | 883 void G1CollectorPolicy::record_stop_world_start() { |
896 _stop_world_start = os::elapsedTime(); | 884 _stop_world_start = os::elapsedTime(); |
897 } | 885 } |
998 void G1CollectorPolicy::record_concurrent_mark_cleanup_start() { | 986 void G1CollectorPolicy::record_concurrent_mark_cleanup_start() { |
999 _mark_cleanup_start_sec = os::elapsedTime(); | 987 _mark_cleanup_start_sec = os::elapsedTime(); |
1000 } | 988 } |
1001 | 989 |
1002 void G1CollectorPolicy::record_concurrent_mark_cleanup_completed() { | 990 void G1CollectorPolicy::record_concurrent_mark_cleanup_completed() { |
1003 _should_revert_to_young_gcs = false; | |
1004 _last_young_gc = true; | 991 _last_young_gc = true; |
1005 _in_marking_window = false; | 992 _in_marking_window = false; |
1006 } | 993 } |
1007 | 994 |
1008 void G1CollectorPolicy::record_concurrent_pause() { | 995 void G1CollectorPolicy::record_concurrent_pause() { |
1203 #endif // PRODUCT | 1190 #endif // PRODUCT |
1204 | 1191 |
1205 last_pause_included_initial_mark = during_initial_mark_pause(); | 1192 last_pause_included_initial_mark = during_initial_mark_pause(); |
1206 if (last_pause_included_initial_mark) { | 1193 if (last_pause_included_initial_mark) { |
1207 record_concurrent_mark_init_end(0.0); | 1194 record_concurrent_mark_init_end(0.0); |
1208 } | 1195 } else if (!_last_young_gc && need_to_start_conc_mark("end of GC")) { |
1209 | |
1210 if (!_last_young_gc && need_to_start_conc_mark("end of GC")) { | |
1211 // Note: this might have already been set, if during the last | 1196 // Note: this might have already been set, if during the last |
1212 // pause we decided to start a cycle but at the beginning of | 1197 // pause we decided to start a cycle but at the beginning of |
1213 // this pause we decided to postpone it. That's OK. | 1198 // this pause we decided to postpone it. That's OK. |
1214 set_initiate_conc_mark_if_possible(); | 1199 set_initiate_conc_mark_if_possible(); |
1215 } | 1200 } |
1490 new_in_marking_window = true; | 1475 new_in_marking_window = true; |
1491 new_in_marking_window_im = true; | 1476 new_in_marking_window_im = true; |
1492 } | 1477 } |
1493 | 1478 |
1494 if (_last_young_gc) { | 1479 if (_last_young_gc) { |
1480 // This is supposed to to be the "last young GC" before we start | |
1481 // doing mixed GCs. Here we decide whether to start mixed GCs or not. | |
1482 | |
1495 if (!last_pause_included_initial_mark) { | 1483 if (!last_pause_included_initial_mark) { |
1496 ergo_verbose2(ErgoMixedGCs, | 1484 if (next_gc_should_be_mixed("start mixed GCs", |
1497 "start mixed GCs", | 1485 "do not start mixed GCs")) { |
1498 ergo_format_byte_perc("known garbage"), | 1486 set_gcs_are_young(false); |
1499 _known_garbage_bytes, _known_garbage_ratio * 100.0); | 1487 } |
1500 set_gcs_are_young(false); | |
1501 } else { | 1488 } else { |
1502 ergo_verbose0(ErgoMixedGCs, | 1489 ergo_verbose0(ErgoMixedGCs, |
1503 "do not start mixed GCs", | 1490 "do not start mixed GCs", |
1504 ergo_format_reason("concurrent cycle is about to start")); | 1491 ergo_format_reason("concurrent cycle is about to start")); |
1505 } | 1492 } |
1506 _last_young_gc = false; | 1493 _last_young_gc = false; |
1507 } | 1494 } |
1508 | 1495 |
1509 if (!_last_gc_was_young) { | 1496 if (!_last_gc_was_young) { |
1510 if (_should_revert_to_young_gcs) { | 1497 // This is a mixed GC. Here we decide whether to continue doing |
1511 ergo_verbose2(ErgoMixedGCs, | 1498 // mixed GCs or not. |
1512 "end mixed GCs", | 1499 |
1513 ergo_format_reason("mixed GCs end requested") | 1500 if (!next_gc_should_be_mixed("continue mixed GCs", |
1514 ergo_format_byte_perc("known garbage"), | 1501 "do not continue mixed GCs")) { |
1515 _known_garbage_bytes, _known_garbage_ratio * 100.0); | |
1516 set_gcs_are_young(true); | 1502 set_gcs_are_young(true); |
1517 } else if (_known_garbage_ratio < 0.05) { | 1503 } |
1518 ergo_verbose3(ErgoMixedGCs, | 1504 } |
1519 "end mixed GCs", | |
1520 ergo_format_reason("known garbage percent lower than threshold") | |
1521 ergo_format_byte_perc("known garbage") | |
1522 ergo_format_perc("threshold"), | |
1523 _known_garbage_bytes, _known_garbage_ratio * 100.0, | |
1524 0.05 * 100.0); | |
1525 set_gcs_are_young(true); | |
1526 } else if (adaptive_young_list_length() && | |
1527 (get_gc_eff_factor() * cur_efficiency < predict_young_gc_eff())) { | |
1528 ergo_verbose5(ErgoMixedGCs, | |
1529 "end mixed GCs", | |
1530 ergo_format_reason("current GC efficiency lower than " | |
1531 "predicted young GC efficiency") | |
1532 ergo_format_double("GC efficiency factor") | |
1533 ergo_format_double("current GC efficiency") | |
1534 ergo_format_double("predicted young GC efficiency") | |
1535 ergo_format_byte_perc("known garbage"), | |
1536 get_gc_eff_factor(), cur_efficiency, | |
1537 predict_young_gc_eff(), | |
1538 _known_garbage_bytes, _known_garbage_ratio * 100.0); | |
1539 set_gcs_are_young(true); | |
1540 } | |
1541 } | |
1542 _should_revert_to_young_gcs = false; | |
1543 | 1505 |
1544 if (_last_gc_was_young && !_during_marking) { | 1506 if (_last_gc_was_young && !_during_marking) { |
1545 _young_gc_eff_seq->add(cur_efficiency); | 1507 _young_gc_eff_seq->add(cur_efficiency); |
1546 } | 1508 } |
1547 | 1509 |
1646 (double) _bytes_in_collection_set_before_gc; | 1608 (double) _bytes_in_collection_set_before_gc; |
1647 } | 1609 } |
1648 | 1610 |
1649 _pending_cards_seq->add((double) _pending_cards); | 1611 _pending_cards_seq->add((double) _pending_cards); |
1650 _rs_lengths_seq->add((double) _max_rs_lengths); | 1612 _rs_lengths_seq->add((double) _max_rs_lengths); |
1651 | |
1652 double expensive_region_limit_ms = | |
1653 (double) MaxGCPauseMillis - predict_constant_other_time_ms(); | |
1654 if (expensive_region_limit_ms < 0.0) { | |
1655 // this means that the other time was predicted to be longer than | |
1656 // than the max pause time | |
1657 expensive_region_limit_ms = (double) MaxGCPauseMillis; | |
1658 } | |
1659 _expensive_region_limit_ms = expensive_region_limit_ms; | |
1660 } | 1613 } |
1661 | 1614 |
1662 _in_marking_window = new_in_marking_window; | 1615 _in_marking_window = new_in_marking_window; |
1663 _in_marking_window_im = new_in_marking_window_im; | 1616 _in_marking_window_im = new_in_marking_window_im; |
1664 _free_regions_at_end_of_collection = _g1->free_regions(); | 1617 _free_regions_at_end_of_collection = _g1->free_regions(); |
1836 G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) { | 1789 G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) { |
1837 size_t bytes_to_copy; | 1790 size_t bytes_to_copy; |
1838 if (hr->is_marked()) | 1791 if (hr->is_marked()) |
1839 bytes_to_copy = hr->max_live_bytes(); | 1792 bytes_to_copy = hr->max_live_bytes(); |
1840 else { | 1793 else { |
1841 guarantee( hr->is_young() && hr->age_in_surv_rate_group() != -1, | 1794 assert(hr->is_young() && hr->age_in_surv_rate_group() != -1, "invariant"); |
1842 "invariant" ); | |
1843 int age = hr->age_in_surv_rate_group(); | 1795 int age = hr->age_in_surv_rate_group(); |
1844 double yg_surv_rate = predict_yg_surv_rate(age, hr->surv_rate_group()); | 1796 double yg_surv_rate = predict_yg_surv_rate(age, hr->surv_rate_group()); |
1845 bytes_to_copy = (size_t) ((double) hr->used() * yg_surv_rate); | 1797 bytes_to_copy = (size_t) ((double) hr->used() * yg_surv_rate); |
1846 } | 1798 } |
1847 | |
1848 return bytes_to_copy; | 1799 return bytes_to_copy; |
1849 } | 1800 } |
1850 | 1801 |
1851 void | 1802 void |
1852 G1CollectorPolicy::init_cset_region_lengths(size_t eden_cset_region_length, | 1803 G1CollectorPolicy::init_cset_region_lengths(size_t eden_cset_region_length, |
1856 _old_cset_region_length = 0; | 1807 _old_cset_region_length = 0; |
1857 } | 1808 } |
1858 | 1809 |
1859 void G1CollectorPolicy::set_recorded_rs_lengths(size_t rs_lengths) { | 1810 void G1CollectorPolicy::set_recorded_rs_lengths(size_t rs_lengths) { |
1860 _recorded_rs_lengths = rs_lengths; | 1811 _recorded_rs_lengths = rs_lengths; |
1861 } | |
1862 | |
1863 void G1CollectorPolicy::check_if_region_is_too_expensive(double | |
1864 predicted_time_ms) { | |
1865 // I don't think we need to do this when in young GC mode since | |
1866 // marking will be initiated next time we hit the soft limit anyway... | |
1867 if (predicted_time_ms > _expensive_region_limit_ms) { | |
1868 ergo_verbose2(ErgoMixedGCs, | |
1869 "request mixed GCs end", | |
1870 ergo_format_reason("predicted region time higher than threshold") | |
1871 ergo_format_ms("predicted region time") | |
1872 ergo_format_ms("threshold"), | |
1873 predicted_time_ms, _expensive_region_limit_ms); | |
1874 // no point in doing another mixed GC | |
1875 _should_revert_to_young_gcs = true; | |
1876 } | |
1877 } | 1812 } |
1878 | 1813 |
1879 void G1CollectorPolicy::update_recent_gc_times(double end_time_sec, | 1814 void G1CollectorPolicy::update_recent_gc_times(double end_time_sec, |
1880 double elapsed_ms) { | 1815 double elapsed_ms) { |
1881 _recent_gc_times_ms->add(elapsed_ms); | 1816 _recent_gc_times_ms->add(elapsed_ms); |
2272 } | 2207 } |
2273 } | 2208 } |
2274 } | 2209 } |
2275 | 2210 |
2276 class KnownGarbageClosure: public HeapRegionClosure { | 2211 class KnownGarbageClosure: public HeapRegionClosure { |
2212 G1CollectedHeap* _g1h; | |
2277 CollectionSetChooser* _hrSorted; | 2213 CollectionSetChooser* _hrSorted; |
2278 | 2214 |
2279 public: | 2215 public: |
2280 KnownGarbageClosure(CollectionSetChooser* hrSorted) : | 2216 KnownGarbageClosure(CollectionSetChooser* hrSorted) : |
2281 _hrSorted(hrSorted) | 2217 _g1h(G1CollectedHeap::heap()), _hrSorted(hrSorted) { } |
2282 {} | |
2283 | 2218 |
2284 bool doHeapRegion(HeapRegion* r) { | 2219 bool doHeapRegion(HeapRegion* r) { |
2285 // We only include humongous regions in collection | 2220 // We only include humongous regions in collection |
2286 // sets when concurrent mark shows that their contained object is | 2221 // sets when concurrent mark shows that their contained object is |
2287 // unreachable. | 2222 // unreachable. |
2288 | 2223 |
2289 // Do we have any marking information for this region? | 2224 // Do we have any marking information for this region? |
2290 if (r->is_marked()) { | 2225 if (r->is_marked()) { |
2291 // We don't include humongous regions in collection | 2226 // We will skip any region that's currently used as an old GC |
2292 // sets because we collect them immediately at the end of a marking | 2227 // alloc region (we should not consider those for collection |
2293 // cycle. We also don't include young regions because we *must* | 2228 // before we fill them up). |
2294 // include them in the next collection pause. | 2229 if (_hrSorted->shouldAdd(r) && !_g1h->is_old_gc_alloc_region(r)) { |
2295 if (!r->isHumongous() && !r->is_young()) { | |
2296 _hrSorted->addMarkedHeapRegion(r); | 2230 _hrSorted->addMarkedHeapRegion(r); |
2297 } | 2231 } |
2298 } | 2232 } |
2299 return false; | 2233 return false; |
2300 } | 2234 } |
2301 }; | 2235 }; |
2302 | 2236 |
2303 class ParKnownGarbageHRClosure: public HeapRegionClosure { | 2237 class ParKnownGarbageHRClosure: public HeapRegionClosure { |
2238 G1CollectedHeap* _g1h; | |
2304 CollectionSetChooser* _hrSorted; | 2239 CollectionSetChooser* _hrSorted; |
2305 jint _marked_regions_added; | 2240 jint _marked_regions_added; |
2241 size_t _reclaimable_bytes_added; | |
2306 jint _chunk_size; | 2242 jint _chunk_size; |
2307 jint _cur_chunk_idx; | 2243 jint _cur_chunk_idx; |
2308 jint _cur_chunk_end; // Cur chunk [_cur_chunk_idx, _cur_chunk_end) | 2244 jint _cur_chunk_end; // Cur chunk [_cur_chunk_idx, _cur_chunk_end) |
2309 int _worker; | 2245 int _worker; |
2310 int _invokes; | 2246 int _invokes; |
2318 get_new_chunk(); | 2254 get_new_chunk(); |
2319 } | 2255 } |
2320 assert(_cur_chunk_idx < _cur_chunk_end, "postcondition"); | 2256 assert(_cur_chunk_idx < _cur_chunk_end, "postcondition"); |
2321 _hrSorted->setMarkedHeapRegion(_cur_chunk_idx, r); | 2257 _hrSorted->setMarkedHeapRegion(_cur_chunk_idx, r); |
2322 _marked_regions_added++; | 2258 _marked_regions_added++; |
2259 _reclaimable_bytes_added += r->reclaimable_bytes(); | |
2323 _cur_chunk_idx++; | 2260 _cur_chunk_idx++; |
2324 } | 2261 } |
2325 | 2262 |
2326 public: | 2263 public: |
2327 ParKnownGarbageHRClosure(CollectionSetChooser* hrSorted, | 2264 ParKnownGarbageHRClosure(CollectionSetChooser* hrSorted, |
2328 jint chunk_size, | 2265 jint chunk_size, |
2329 int worker) : | 2266 int worker) : |
2330 _hrSorted(hrSorted), _chunk_size(chunk_size), _worker(worker), | 2267 _g1h(G1CollectedHeap::heap()), |
2331 _marked_regions_added(0), _cur_chunk_idx(0), _cur_chunk_end(0), | 2268 _hrSorted(hrSorted), _chunk_size(chunk_size), _worker(worker), |
2332 _invokes(0) | 2269 _marked_regions_added(0), _reclaimable_bytes_added(0), |
2333 {} | 2270 _cur_chunk_idx(0), _cur_chunk_end(0), _invokes(0) { } |
2334 | 2271 |
2335 bool doHeapRegion(HeapRegion* r) { | 2272 bool doHeapRegion(HeapRegion* r) { |
2336 // We only include humongous regions in collection | 2273 // We only include humongous regions in collection |
2337 // sets when concurrent mark shows that their contained object is | 2274 // sets when concurrent mark shows that their contained object is |
2338 // unreachable. | 2275 // unreachable. |
2339 _invokes++; | 2276 _invokes++; |
2340 | 2277 |
2341 // Do we have any marking information for this region? | 2278 // Do we have any marking information for this region? |
2342 if (r->is_marked()) { | 2279 if (r->is_marked()) { |
2343 // We don't include humongous regions in collection | 2280 // We will skip any region that's currently used as an old GC |
2344 // sets because we collect them immediately at the end of a marking | 2281 // alloc region (we should not consider those for collection |
2345 // cycle. | 2282 // before we fill them up). |
2346 // We also do not include young regions in collection sets | 2283 if (_hrSorted->shouldAdd(r) && !_g1h->is_old_gc_alloc_region(r)) { |
2347 if (!r->isHumongous() && !r->is_young()) { | |
2348 add_region(r); | 2284 add_region(r); |
2349 } | 2285 } |
2350 } | 2286 } |
2351 return false; | 2287 return false; |
2352 } | 2288 } |
2353 jint marked_regions_added() { return _marked_regions_added; } | 2289 jint marked_regions_added() { return _marked_regions_added; } |
2290 size_t reclaimable_bytes_added() { return _reclaimable_bytes_added; } | |
2354 int invokes() { return _invokes; } | 2291 int invokes() { return _invokes; } |
2355 }; | 2292 }; |
2356 | 2293 |
2357 class ParKnownGarbageTask: public AbstractGangTask { | 2294 class ParKnownGarbageTask: public AbstractGangTask { |
2358 CollectionSetChooser* _hrSorted; | 2295 CollectionSetChooser* _hrSorted; |
2360 G1CollectedHeap* _g1; | 2297 G1CollectedHeap* _g1; |
2361 public: | 2298 public: |
2362 ParKnownGarbageTask(CollectionSetChooser* hrSorted, jint chunk_size) : | 2299 ParKnownGarbageTask(CollectionSetChooser* hrSorted, jint chunk_size) : |
2363 AbstractGangTask("ParKnownGarbageTask"), | 2300 AbstractGangTask("ParKnownGarbageTask"), |
2364 _hrSorted(hrSorted), _chunk_size(chunk_size), | 2301 _hrSorted(hrSorted), _chunk_size(chunk_size), |
2365 _g1(G1CollectedHeap::heap()) | 2302 _g1(G1CollectedHeap::heap()) { } |
2366 {} | |
2367 | 2303 |
2368 void work(uint worker_id) { | 2304 void work(uint worker_id) { |
2369 ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, | 2305 ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, |
2370 _chunk_size, | 2306 _chunk_size, |
2371 worker_id); | 2307 worker_id); |
2372 // Back to zero for the claim value. | 2308 // Back to zero for the claim value. |
2373 _g1->heap_region_par_iterate_chunked(&parKnownGarbageCl, worker_id, | 2309 _g1->heap_region_par_iterate_chunked(&parKnownGarbageCl, worker_id, |
2374 _g1->workers()->active_workers(), | 2310 _g1->workers()->active_workers(), |
2375 HeapRegion::InitialClaimValue); | 2311 HeapRegion::InitialClaimValue); |
2376 jint regions_added = parKnownGarbageCl.marked_regions_added(); | 2312 jint regions_added = parKnownGarbageCl.marked_regions_added(); |
2377 _hrSorted->incNumMarkedHeapRegions(regions_added); | 2313 size_t reclaimable_bytes_added = |
2314 parKnownGarbageCl.reclaimable_bytes_added(); | |
2315 _hrSorted->updateTotals(regions_added, reclaimable_bytes_added); | |
2378 if (G1PrintParCleanupStats) { | 2316 if (G1PrintParCleanupStats) { |
2379 gclog_or_tty->print_cr(" Thread %d called %d times, added %d regions to list.", | 2317 gclog_or_tty->print_cr(" Thread %d called %d times, added %d regions to list.", |
2380 worker_id, parKnownGarbageCl.invokes(), regions_added); | 2318 worker_id, parKnownGarbageCl.invokes(), regions_added); |
2381 } | 2319 } |
2382 } | 2320 } |
2656 csr = next; | 2594 csr = next; |
2657 } | 2595 } |
2658 } | 2596 } |
2659 #endif // !PRODUCT | 2597 #endif // !PRODUCT |
2660 | 2598 |
2661 void G1CollectorPolicy::choose_collection_set(double target_pause_time_ms) { | 2599 bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, |
2600 const char* false_action_str) { | |
2601 CollectionSetChooser* cset_chooser = _collectionSetChooser; | |
2602 if (cset_chooser->isEmpty()) { | |
2603 ergo_verbose0(ErgoMixedGCs, | |
2604 false_action_str, | |
2605 ergo_format_reason("candidate old regions not available")); | |
2606 return false; | |
2607 } | |
2608 size_t reclaimable_bytes = cset_chooser->remainingReclaimableBytes(); | |
2609 size_t capacity_bytes = _g1->capacity(); | |
2610 double perc = (double) reclaimable_bytes * 100.0 / (double) capacity_bytes; | |
2611 double threshold = (double) G1OldReclaimableThresholdPercent; | |
2612 if (perc < threshold) { | |
2613 ergo_verbose4(ErgoMixedGCs, | |
2614 false_action_str, | |
2615 ergo_format_reason("reclaimable percentage lower than threshold") | |
2616 ergo_format_region("candidate old regions") | |
2617 ergo_format_byte_perc("reclaimable") | |
2618 ergo_format_perc("threshold"), | |
2619 cset_chooser->remainingRegions(), | |
2620 reclaimable_bytes, perc, threshold); | |
2621 return false; | |
2622 } | |
2623 | |
2624 ergo_verbose4(ErgoMixedGCs, | |
2625 true_action_str, | |
2626 ergo_format_reason("candidate old regions available") | |
2627 ergo_format_region("candidate old regions") | |
2628 ergo_format_byte_perc("reclaimable") | |
2629 ergo_format_perc("threshold"), | |
2630 cset_chooser->remainingRegions(), | |
2631 reclaimable_bytes, perc, threshold); | |
2632 return true; | |
2633 } | |
2634 | |
2635 void G1CollectorPolicy::finalize_cset(double target_pause_time_ms) { | |
2662 // Set this here - in case we're not doing young collections. | 2636 // Set this here - in case we're not doing young collections. |
2663 double non_young_start_time_sec = os::elapsedTime(); | 2637 double non_young_start_time_sec = os::elapsedTime(); |
2664 | 2638 |
2665 YoungList* young_list = _g1->young_list(); | 2639 YoungList* young_list = _g1->young_list(); |
2666 finalize_incremental_cset_building(); | 2640 finalize_incremental_cset_building(); |
2670 target_pause_time_ms)); | 2644 target_pause_time_ms)); |
2671 guarantee(_collection_set == NULL, "Precondition"); | 2645 guarantee(_collection_set == NULL, "Precondition"); |
2672 | 2646 |
2673 double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); | 2647 double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); |
2674 double predicted_pause_time_ms = base_time_ms; | 2648 double predicted_pause_time_ms = base_time_ms; |
2675 | |
2676 double time_remaining_ms = target_pause_time_ms - base_time_ms; | 2649 double time_remaining_ms = target_pause_time_ms - base_time_ms; |
2677 | 2650 |
2678 ergo_verbose3(ErgoCSetConstruction | ErgoHigh, | 2651 ergo_verbose3(ErgoCSetConstruction | ErgoHigh, |
2679 "start choosing CSet", | 2652 "start choosing CSet", |
2680 ergo_format_ms("predicted base time") | 2653 ergo_format_ms("predicted base time") |
2681 ergo_format_ms("remaining time") | 2654 ergo_format_ms("remaining time") |
2682 ergo_format_ms("target pause time"), | 2655 ergo_format_ms("target pause time"), |
2683 base_time_ms, time_remaining_ms, target_pause_time_ms); | 2656 base_time_ms, time_remaining_ms, target_pause_time_ms); |
2684 | |
2685 // the 10% and 50% values are arbitrary... | |
2686 double threshold = 0.10 * target_pause_time_ms; | |
2687 if (time_remaining_ms < threshold) { | |
2688 double prev_time_remaining_ms = time_remaining_ms; | |
2689 time_remaining_ms = 0.50 * target_pause_time_ms; | |
2690 ergo_verbose3(ErgoCSetConstruction, | |
2691 "adjust remaining time", | |
2692 ergo_format_reason("remaining time lower than threshold") | |
2693 ergo_format_ms("remaining time") | |
2694 ergo_format_ms("threshold") | |
2695 ergo_format_ms("adjusted remaining time"), | |
2696 prev_time_remaining_ms, threshold, time_remaining_ms); | |
2697 } | |
2698 | |
2699 size_t expansion_bytes = _g1->expansion_regions() * HeapRegion::GrainBytes; | |
2700 | 2657 |
2701 HeapRegion* hr; | 2658 HeapRegion* hr; |
2702 double young_start_time_sec = os::elapsedTime(); | 2659 double young_start_time_sec = os::elapsedTime(); |
2703 | 2660 |
2704 _collection_set_bytes_used_before = 0; | 2661 _collection_set_bytes_used_before = 0; |
2750 | 2707 |
2751 // We are doing young collections so reset this. | 2708 // We are doing young collections so reset this. |
2752 non_young_start_time_sec = young_end_time_sec; | 2709 non_young_start_time_sec = young_end_time_sec; |
2753 | 2710 |
2754 if (!gcs_are_young()) { | 2711 if (!gcs_are_young()) { |
2755 bool should_continue = true; | 2712 CollectionSetChooser* cset_chooser = _collectionSetChooser; |
2756 NumberSeq seq; | 2713 assert(cset_chooser->verify(), "CSet Chooser verification - pre"); |
2757 double avg_prediction = 100000000000000000.0; // something very large | 2714 const size_t min_old_cset_length = cset_chooser->calcMinOldCSetLength(); |
2758 | 2715 const size_t max_old_cset_length = cset_chooser->calcMaxOldCSetLength(); |
2759 double prev_predicted_pause_time_ms = predicted_pause_time_ms; | 2716 |
2760 do { | 2717 size_t expensive_region_num = 0; |
2761 // Note that add_old_region_to_cset() increments the | 2718 bool check_time_remaining = adaptive_young_list_length(); |
2762 // _old_cset_region_length field and cset_region_length() returns the | 2719 HeapRegion* hr = cset_chooser->peek(); |
2763 // sum of _eden_cset_region_length, _survivor_cset_region_length, and | 2720 while (hr != NULL) { |
2764 // _old_cset_region_length. So, as old regions are added to the | 2721 if (old_cset_region_length() >= max_old_cset_length) { |
2765 // CSet, _old_cset_region_length will be incremented and | 2722 // Added maximum number of old regions to the CSet. |
2766 // cset_region_length(), which is used below, will always reflect | 2723 ergo_verbose2(ErgoCSetConstruction, |
2767 // the the total number of regions added up to this point to the CSet. | 2724 "finish adding old regions to CSet", |
2768 | 2725 ergo_format_reason("old CSet region num reached max") |
2769 hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms, | 2726 ergo_format_region("old") |
2770 avg_prediction); | 2727 ergo_format_region("max"), |
2771 if (hr != NULL) { | 2728 old_cset_region_length(), max_old_cset_length); |
2772 _g1->old_set_remove(hr); | 2729 break; |
2773 double predicted_time_ms = predict_region_elapsed_time_ms(hr, false); | |
2774 time_remaining_ms -= predicted_time_ms; | |
2775 predicted_pause_time_ms += predicted_time_ms; | |
2776 add_old_region_to_cset(hr); | |
2777 seq.add(predicted_time_ms); | |
2778 avg_prediction = seq.avg() + seq.sd(); | |
2779 } | 2730 } |
2780 | 2731 |
2781 should_continue = true; | 2732 double predicted_time_ms = predict_region_elapsed_time_ms(hr, false); |
2782 if (hr == NULL) { | 2733 if (check_time_remaining) { |
2783 // No need for an ergo verbose message here, | 2734 if (predicted_time_ms > time_remaining_ms) { |
2784 // getNextMarkRegion() does this when it returns NULL. | 2735 // Too expensive for the current CSet. |
2785 should_continue = false; | 2736 |
2737 if (old_cset_region_length() >= min_old_cset_length) { | |
2738 // We have added the minimum number of old regions to the CSet, | |
2739 // we are done with this CSet. | |
2740 ergo_verbose4(ErgoCSetConstruction, | |
2741 "finish adding old regions to CSet", | |
2742 ergo_format_reason("predicted time is too high") | |
2743 ergo_format_ms("predicted time") | |
2744 ergo_format_ms("remaining time") | |
2745 ergo_format_region("old") | |
2746 ergo_format_region("min"), | |
2747 predicted_time_ms, time_remaining_ms, | |
2748 old_cset_region_length(), min_old_cset_length); | |
2749 break; | |
2750 } | |
2751 | |
2752 // We'll add it anyway given that we haven't reached the | |
2753 // minimum number of old regions. | |
2754 expensive_region_num += 1; | |
2755 } | |
2786 } else { | 2756 } else { |
2787 if (adaptive_young_list_length()) { | 2757 if (old_cset_region_length() >= min_old_cset_length) { |
2788 if (time_remaining_ms < 0.0) { | 2758 // In the non-auto-tuning case, we'll finish adding regions |
2789 ergo_verbose1(ErgoCSetConstruction, | 2759 // to the CSet if we reach the minimum. |
2790 "stop adding old regions to CSet", | 2760 ergo_verbose2(ErgoCSetConstruction, |
2791 ergo_format_reason("remaining time is lower than 0") | 2761 "finish adding old regions to CSet", |
2792 ergo_format_ms("remaining time"), | 2762 ergo_format_reason("old CSet region num reached min") |
2793 time_remaining_ms); | 2763 ergo_format_region("old") |
2794 should_continue = false; | 2764 ergo_format_region("min"), |
2795 } | 2765 old_cset_region_length(), min_old_cset_length); |
2796 } else { | 2766 break; |
2797 if (cset_region_length() >= _young_list_fixed_length) { | |
2798 ergo_verbose2(ErgoCSetConstruction, | |
2799 "stop adding old regions to CSet", | |
2800 ergo_format_reason("CSet length reached target") | |
2801 ergo_format_region("CSet") | |
2802 ergo_format_region("young target"), | |
2803 cset_region_length(), _young_list_fixed_length); | |
2804 should_continue = false; | |
2805 } | |
2806 } | 2767 } |
2807 } | 2768 } |
2808 } while (should_continue); | 2769 |
2809 | 2770 // We will add this region to the CSet. |
2810 if (!adaptive_young_list_length() && | 2771 time_remaining_ms -= predicted_time_ms; |
2811 cset_region_length() < _young_list_fixed_length) { | 2772 predicted_pause_time_ms += predicted_time_ms; |
2812 ergo_verbose2(ErgoCSetConstruction, | 2773 cset_chooser->remove_and_move_to_next(hr); |
2813 "request mixed GCs end", | 2774 _g1->old_set_remove(hr); |
2814 ergo_format_reason("CSet length lower than target") | 2775 add_old_region_to_cset(hr); |
2815 ergo_format_region("CSet") | 2776 |
2816 ergo_format_region("young target"), | 2777 hr = cset_chooser->peek(); |
2817 cset_region_length(), _young_list_fixed_length); | 2778 } |
2818 _should_revert_to_young_gcs = true; | 2779 if (hr == NULL) { |
2819 } | 2780 ergo_verbose0(ErgoCSetConstruction, |
2820 | 2781 "finish adding old regions to CSet", |
2821 ergo_verbose2(ErgoCSetConstruction | ErgoHigh, | 2782 ergo_format_reason("candidate old regions not available")); |
2822 "add old regions to CSet", | 2783 } |
2823 ergo_format_region("old") | 2784 |
2824 ergo_format_ms("predicted old region time"), | 2785 if (expensive_region_num > 0) { |
2825 old_cset_region_length(), | 2786 // We print the information once here at the end, predicated on |
2826 predicted_pause_time_ms - prev_predicted_pause_time_ms); | 2787 // whether we added any apparently expensive regions or not, to |
2788 // avoid generating output per region. | |
2789 ergo_verbose4(ErgoCSetConstruction, | |
2790 "added expensive regions to CSet", | |
2791 ergo_format_reason("old CSet region num not reached min") | |
2792 ergo_format_region("old") | |
2793 ergo_format_region("expensive") | |
2794 ergo_format_region("min") | |
2795 ergo_format_ms("remaining time"), | |
2796 old_cset_region_length(), | |
2797 expensive_region_num, | |
2798 min_old_cset_length, | |
2799 time_remaining_ms); | |
2800 } | |
2801 | |
2802 assert(cset_chooser->verify(), "CSet Chooser verification - post"); | |
2827 } | 2803 } |
2828 | 2804 |
2829 stop_incremental_cset_building(); | 2805 stop_incremental_cset_building(); |
2830 | 2806 |
2831 count_CS_bytes_used(); | 2807 count_CS_bytes_used(); |