comparison src/share/vm/gc_implementation/g1/collectionSetChooser.hpp @ 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 b9390528617c
children 720b6a76dd9d
comparison
equal deleted inserted replaced
4911:d903bf750e9f 4912:a9647476d1a4
1 /* 1 /*
2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
25 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_COLLECTIONSETCHOOSER_HPP 25 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_COLLECTIONSETCHOOSER_HPP
26 #define SHARE_VM_GC_IMPLEMENTATION_G1_COLLECTIONSETCHOOSER_HPP 26 #define SHARE_VM_GC_IMPLEMENTATION_G1_COLLECTIONSETCHOOSER_HPP
27 27
28 #include "gc_implementation/g1/heapRegion.hpp" 28 #include "gc_implementation/g1/heapRegion.hpp"
29 #include "utilities/growableArray.hpp" 29 #include "utilities/growableArray.hpp"
30
31 // We need to sort heap regions by collection desirability.
32 // This sorting is currently done in two "stages". An initial sort is
33 // done following a cleanup pause as soon as all of the marked but
34 // non-empty regions have been identified and the completely empty
35 // ones reclaimed.
36 // This gives us a global sort on a GC efficiency metric
37 // based on predictive data available at that time. However,
38 // any of these regions that are collected will only be collected
39 // during a future GC pause, by which time it is possible that newer
40 // data might allow us to revise and/or refine the earlier
41 // pause predictions, leading to changes in expected gc efficiency
42 // order. To somewhat mitigate this obsolescence, more so in the
43 // case of regions towards the end of the list, which will be
44 // picked later, these pre-sorted regions from the _markedRegions
45 // array are not used as is, but a small prefix thereof is
46 // insertion-sorted again into a small cache, based on more
47 // recent remembered set information. Regions are then drawn
48 // from this cache to construct the collection set at each
49 // incremental GC.
50 // This scheme and/or its implementation may be subject to
51 // revision in the future.
52 30
53 class CSetChooserCache VALUE_OBJ_CLASS_SPEC { 31 class CSetChooserCache VALUE_OBJ_CLASS_SPEC {
54 private: 32 private:
55 enum { 33 enum {
56 CacheLength = 16 34 CacheLength = 16
101 }; 79 };
102 80
103 class CollectionSetChooser: public CHeapObj { 81 class CollectionSetChooser: public CHeapObj {
104 82
105 GrowableArray<HeapRegion*> _markedRegions; 83 GrowableArray<HeapRegion*> _markedRegions;
106 int _curMarkedIndex; 84
107 int _numMarkedRegions; 85 // The index of the next candidate old region to be considered for
86 // addition to the CSet.
87 int _curr_index;
88
89 // The number of candidate old regions added to the CSet chooser.
90 int _length;
91
108 CSetChooserCache _cache; 92 CSetChooserCache _cache;
109
110 // True iff last collection pause ran of out new "age 0" regions, and
111 // returned an "age 1" region.
112 bool _unmarked_age_1_returned_as_new;
113
114 jint _first_par_unreserved_idx; 93 jint _first_par_unreserved_idx;
115 94
95 // If a region has more live bytes than this threshold, it will not
96 // be added to the CSet chooser and will not be a candidate for
97 // collection.
98 size_t _regionLiveThresholdBytes;
99
100 // The sum of reclaimable bytes over all the regions in the CSet chooser.
101 size_t _remainingReclaimableBytes;
102
116 public: 103 public:
117 104
118 HeapRegion* getNextMarkedRegion(double time_so_far, double avg_prediction); 105 // Return the current candidate region to be considered for
106 // collection without removing it from the CSet chooser.
107 HeapRegion* peek() {
108 HeapRegion* res = NULL;
109 if (_curr_index < _length) {
110 res = _markedRegions.at(_curr_index);
111 assert(res != NULL,
112 err_msg("Unexpected NULL hr in _markedRegions at index %d",
113 _curr_index));
114 }
115 return res;
116 }
117
118 // Remove the given region from the CSet chooser and move to the
119 // next one. The given region should be the current candidate region
120 // in the CSet chooser.
121 void remove_and_move_to_next(HeapRegion* hr) {
122 assert(hr != NULL, "pre-condition");
123 assert(_curr_index < _length, "pre-condition");
124 assert(_markedRegions.at(_curr_index) == hr, "pre-condition");
125 hr->set_sort_index(-1);
126 _markedRegions.at_put(_curr_index, NULL);
127 assert(hr->reclaimable_bytes() <= _remainingReclaimableBytes,
128 err_msg("remaining reclaimable bytes inconsistent "
129 "from region: "SIZE_FORMAT" remaining: "SIZE_FORMAT,
130 hr->reclaimable_bytes(), _remainingReclaimableBytes));
131 _remainingReclaimableBytes -= hr->reclaimable_bytes();
132 _curr_index += 1;
133 }
119 134
120 CollectionSetChooser(); 135 CollectionSetChooser();
121 136
122 void sortMarkedHeapRegions(); 137 void sortMarkedHeapRegions();
123 void fillCache(); 138 void fillCache();
139
140 // Determine whether to add the given region to the CSet chooser or
141 // not. Currently, we skip humongous regions (we never add them to
142 // the CSet, we only reclaim them during cleanup) and regions whose
143 // live bytes are over the threshold.
144 bool shouldAdd(HeapRegion* hr) {
145 assert(hr->is_marked(), "pre-condition");
146 assert(!hr->is_young(), "should never consider young regions");
147 return !hr->isHumongous() &&
148 hr->live_bytes() < _regionLiveThresholdBytes;
149 }
150
151 // Calculate the minimum number of old regions we'll add to the CSet
152 // during a mixed GC.
153 size_t calcMinOldCSetLength();
154
155 // Calculate the maximum number of old regions we'll add to the CSet
156 // during a mixed GC.
157 size_t calcMaxOldCSetLength();
158
159 // Serial version.
124 void addMarkedHeapRegion(HeapRegion *hr); 160 void addMarkedHeapRegion(HeapRegion *hr);
125 161
126 // Must be called before calls to getParMarkedHeapRegionChunk. 162 // Must be called before calls to getParMarkedHeapRegionChunk.
127 // "n_regions" is the number of regions, "chunkSize" the chunk size. 163 // "n_regions" is the number of regions, "chunkSize" the chunk size.
128 void prepareForAddMarkedHeapRegionsPar(size_t n_regions, size_t chunkSize); 164 void prepareForAddMarkedHeapRegionsPar(size_t n_regions, size_t chunkSize);
131 // calling thread using "setMarkedHeapRegion" (to NULL if necessary). 167 // calling thread using "setMarkedHeapRegion" (to NULL if necessary).
132 jint getParMarkedHeapRegionChunk(jint n_regions); 168 jint getParMarkedHeapRegionChunk(jint n_regions);
133 // Set the marked array entry at index to hr. Careful to claim the index 169 // Set the marked array entry at index to hr. Careful to claim the index
134 // first if in parallel. 170 // first if in parallel.
135 void setMarkedHeapRegion(jint index, HeapRegion* hr); 171 void setMarkedHeapRegion(jint index, HeapRegion* hr);
136 // Atomically increment the number of claimed regions by "inc_by". 172 // Atomically increment the number of added regions by region_num
137 void incNumMarkedHeapRegions(jint inc_by); 173 // and the amount of reclaimable bytes by reclaimable_bytes.
174 void updateTotals(jint region_num, size_t reclaimable_bytes);
138 175
139 void clearMarkedHeapRegions(); 176 void clearMarkedHeapRegions();
140 177
141 void updateAfterFullCollection(); 178 // Return the number of candidate regions that remain to be collected.
142 179 size_t remainingRegions() { return _length - _curr_index; }
143 bool unmarked_age_1_returned_as_new() { return _unmarked_age_1_returned_as_new; } 180
181 // Determine whether the CSet chooser has more candidate regions or not.
182 bool isEmpty() { return remainingRegions() == 0; }
183
184 // Return the reclaimable bytes that remain to be collected on
185 // all the candidate regions in the CSet chooser.
186 size_t remainingReclaimableBytes () { return _remainingReclaimableBytes; }
144 187
145 // Returns true if the used portion of "_markedRegions" is properly 188 // Returns true if the used portion of "_markedRegions" is properly
146 // sorted, otherwise asserts false. 189 // sorted, otherwise asserts false.
147 #ifndef PRODUCT 190 #ifndef PRODUCT
148 bool verify(void); 191 bool verify(void);
149 bool regionProperlyOrdered(HeapRegion* r) { 192 bool regionProperlyOrdered(HeapRegion* r) {
150 int si = r->sort_index(); 193 int si = r->sort_index();
151 return (si == -1) || 194 if (si > -1) {
152 (si > -1 && _markedRegions.at(si) == r) || 195 guarantee(_curr_index <= si && si < _length,
153 (si < -1 && _cache.region_in_cache(r)); 196 err_msg("curr: %d sort index: %d: length: %d",
197 _curr_index, si, _length));
198 guarantee(_markedRegions.at(si) == r,
199 err_msg("sort index: %d at: "PTR_FORMAT" r: "PTR_FORMAT,
200 si, _markedRegions.at(si), r));
201 } else {
202 guarantee(si == -1, err_msg("sort index: %d", si));
203 }
204 return true;
154 } 205 }
155 #endif 206 #endif
156 207
157 }; 208 };
158 209