comparison src/share/vm/memory/cardTableRS.cpp @ 3287:c48ad6ab8bdf

7037276: Unnecessary double traversal of dirty card windows Summary: Short-circuited an unnecessary double traversal of dirty card windows when iterating younger refs. Also renamed some cardtable methods for more clarity. Reviewed-by: jmasa, stefank, poonam
author ysr
date Wed, 20 Apr 2011 19:19:30 -0700
parents c69b1043dfb1
children 1f4413413144
comparison
equal deleted inserted replaced
3285:49a67202bc67 3287:c48ad6ab8bdf
103 OopsInGenClosure* blk) { 103 OopsInGenClosure* blk) {
104 _last_cur_val_in_gen[g->level()+1] = cur_youngergen_card_val(); 104 _last_cur_val_in_gen[g->level()+1] = cur_youngergen_card_val();
105 g->younger_refs_iterate(blk); 105 g->younger_refs_iterate(blk);
106 } 106 }
107 107
108 class ClearNoncleanCardWrapper: public MemRegionClosure { 108 inline bool ClearNoncleanCardWrapper::clear_card(jbyte* entry) {
109 MemRegionClosure* _dirty_card_closure; 109 if (_is_par) {
110 CardTableRS* _ct; 110 return clear_card_parallel(entry);
111 bool _is_par; 111 } else {
112 private: 112 return clear_card_serial(entry);
113 // Clears the given card, return true if the corresponding card should be 113 }
114 // processed. 114 }
115 bool clear_card(jbyte* entry) { 115
116 if (_is_par) { 116 inline bool ClearNoncleanCardWrapper::clear_card_parallel(jbyte* entry) {
117 while (true) { 117 while (true) {
118 // In the parallel case, we may have to do this several times. 118 // In the parallel case, we may have to do this several times.
119 jbyte entry_val = *entry; 119 jbyte entry_val = *entry;
120 assert(entry_val != CardTableRS::clean_card_val(), 120 assert(entry_val != CardTableRS::clean_card_val(),
121 "We shouldn't be looking at clean cards, and this should " 121 "We shouldn't be looking at clean cards, and this should "
122 "be the only place they get cleaned."); 122 "be the only place they get cleaned.");
123 if (CardTableRS::card_is_dirty_wrt_gen_iter(entry_val) 123 if (CardTableRS::card_is_dirty_wrt_gen_iter(entry_val)
124 || _ct->is_prev_youngergen_card_val(entry_val)) { 124 || _ct->is_prev_youngergen_card_val(entry_val)) {
125 jbyte res = 125 jbyte res =
126 Atomic::cmpxchg(CardTableRS::clean_card_val(), entry, entry_val); 126 Atomic::cmpxchg(CardTableRS::clean_card_val(), entry, entry_val);
127 if (res == entry_val) { 127 if (res == entry_val) {
128 break; 128 break;
129 } else { 129 } else {
130 assert(res == CardTableRS::cur_youngergen_and_prev_nonclean_card, 130 assert(res == CardTableRS::cur_youngergen_and_prev_nonclean_card,
131 "The CAS above should only fail if another thread did " 131 "The CAS above should only fail if another thread did "
132 "a GC write barrier."); 132 "a GC write barrier.");
133 }
134 } else if (entry_val ==
135 CardTableRS::cur_youngergen_and_prev_nonclean_card) {
136 // Parallelism shouldn't matter in this case. Only the thread
137 // assigned to scan the card should change this value.
138 *entry = _ct->cur_youngergen_card_val();
139 break;
140 } else {
141 assert(entry_val == _ct->cur_youngergen_card_val(),
142 "Should be the only possibility.");
143 // In this case, the card was clean before, and become
144 // cur_youngergen only because of processing of a promoted object.
145 // We don't have to look at the card.
146 return false;
147 }
148 } 133 }
149 return true; 134 } else if (entry_val ==
135 CardTableRS::cur_youngergen_and_prev_nonclean_card) {
136 // Parallelism shouldn't matter in this case. Only the thread
137 // assigned to scan the card should change this value.
138 *entry = _ct->cur_youngergen_card_val();
139 break;
150 } else { 140 } else {
151 jbyte entry_val = *entry; 141 assert(entry_val == _ct->cur_youngergen_card_val(),
152 assert(entry_val != CardTableRS::clean_card_val(), 142 "Should be the only possibility.");
153 "We shouldn't be looking at clean cards, and this should " 143 // In this case, the card was clean before, and become
154 "be the only place they get cleaned."); 144 // cur_youngergen only because of processing of a promoted object.
155 assert(entry_val != CardTableRS::cur_youngergen_and_prev_nonclean_card, 145 // We don't have to look at the card.
156 "This should be possible in the sequential case."); 146 return false;
157 *entry = CardTableRS::clean_card_val(); 147 }
158 return true; 148 }
159 } 149 return true;
160 } 150 }
161 151
162 public: 152
163 ClearNoncleanCardWrapper(MemRegionClosure* dirty_card_closure, 153 inline bool ClearNoncleanCardWrapper::clear_card_serial(jbyte* entry) {
164 CardTableRS* ct) : 154 jbyte entry_val = *entry;
155 assert(entry_val != CardTableRS::clean_card_val(),
156 "We shouldn't be looking at clean cards, and this should "
157 "be the only place they get cleaned.");
158 assert(entry_val != CardTableRS::cur_youngergen_and_prev_nonclean_card,
159 "This should be possible in the sequential case.");
160 *entry = CardTableRS::clean_card_val();
161 return true;
162 }
163
164 ClearNoncleanCardWrapper::ClearNoncleanCardWrapper(
165 MemRegionClosure* dirty_card_closure, CardTableRS* ct) :
165 _dirty_card_closure(dirty_card_closure), _ct(ct) { 166 _dirty_card_closure(dirty_card_closure), _ct(ct) {
166 _is_par = (SharedHeap::heap()->n_par_threads() > 0); 167 _is_par = (SharedHeap::heap()->n_par_threads() > 0);
167 } 168 }
168 void do_MemRegion(MemRegion mr) { 169
169 // We start at the high end of "mr", walking backwards 170 void ClearNoncleanCardWrapper::do_MemRegion(MemRegion mr) {
170 // while accumulating a contiguous dirty range of cards in 171 assert(mr.word_size() > 0, "Error");
171 // [start_of_non_clean, end_of_non_clean) which we then 172 assert(_ct->is_aligned(mr.start()), "mr.start() should be card aligned");
172 // process en masse. 173 // mr.end() may not necessarily be card aligned.
173 HeapWord* end_of_non_clean = mr.end(); 174 jbyte* cur_entry = _ct->byte_for(mr.last());
174 HeapWord* start_of_non_clean = end_of_non_clean; 175 const jbyte* limit = _ct->byte_for(mr.start());
175 jbyte* entry = _ct->byte_for(mr.last()); 176 HeapWord* end_of_non_clean = mr.end();
176 const jbyte* first_entry = _ct->byte_for(mr.start()); 177 HeapWord* start_of_non_clean = end_of_non_clean;
177 while (entry >= first_entry) { 178 while (cur_entry >= limit) {
178 HeapWord* cur = _ct->addr_for(entry); 179 HeapWord* cur_hw = _ct->addr_for(cur_entry);
179 if (!clear_card(entry)) { 180 if ((*cur_entry != CardTableRS::clean_card_val()) && clear_card(cur_entry)) {
180 // We hit a clean card; process any non-empty 181 // Continue the dirty range by opening the
181 // dirty range accumulated so far. 182 // dirty window one card to the left.
182 if (start_of_non_clean < end_of_non_clean) { 183 start_of_non_clean = cur_hw;
183 MemRegion mr2(start_of_non_clean, end_of_non_clean); 184 } else {
184 _dirty_card_closure->do_MemRegion(mr2); 185 // We hit a "clean" card; process any non-empty
185 } 186 // "dirty" range accumulated so far.
186 // Reset the dirty window while continuing to 187 if (start_of_non_clean < end_of_non_clean) {
187 // look for the next dirty window to process. 188 const MemRegion mrd(start_of_non_clean, end_of_non_clean);
188 end_of_non_clean = cur; 189 _dirty_card_closure->do_MemRegion(mrd);
189 start_of_non_clean = end_of_non_clean;
190 } 190 }
191 // Open the left end of the window one card to the left. 191 // Reset the dirty window, while continuing to look
192 start_of_non_clean = cur; 192 // for the next dirty card that will start a
193 // Note that "entry" leads "start_of_non_clean" in 193 // new dirty window.
194 // its leftward excursion after this point 194 end_of_non_clean = cur_hw;
195 // in the loop and, when we hit the left end of "mr", 195 start_of_non_clean = cur_hw;
196 // will point off of the left end of the card-table 196 }
197 // for "mr". 197 // Note that "cur_entry" leads "start_of_non_clean" in
198 entry--; 198 // its leftward excursion after this point
199 } 199 // in the loop and, when we hit the left end of "mr",
200 // If the first card of "mr" was dirty, we will have 200 // will point off of the left end of the card-table
201 // been left with a dirty window, co-initial with "mr", 201 // for "mr".
202 // which we now process. 202 cur_entry--;
203 if (start_of_non_clean < end_of_non_clean) { 203 }
204 MemRegion mr2(start_of_non_clean, end_of_non_clean); 204 // If the first card of "mr" was dirty, we will have
205 _dirty_card_closure->do_MemRegion(mr2); 205 // been left with a dirty window, co-initial with "mr",
206 } 206 // which we now process.
207 } 207 if (start_of_non_clean < end_of_non_clean) {
208 }; 208 const MemRegion mrd(start_of_non_clean, end_of_non_clean);
209 _dirty_card_closure->do_MemRegion(mrd);
210 }
211 }
212
209 // clean (by dirty->clean before) ==> cur_younger_gen 213 // clean (by dirty->clean before) ==> cur_younger_gen
210 // dirty ==> cur_youngergen_and_prev_nonclean_card 214 // dirty ==> cur_youngergen_and_prev_nonclean_card
211 // precleaned ==> cur_youngergen_and_prev_nonclean_card 215 // precleaned ==> cur_youngergen_and_prev_nonclean_card
212 // prev-younger-gen ==> cur_youngergen_and_prev_nonclean_card 216 // prev-younger-gen ==> cur_youngergen_and_prev_nonclean_card
213 // cur-younger-gen ==> cur_younger_gen 217 // cur-younger-gen ==> cur_younger_gen
244 OopsInGenClosure* cl) { 248 OopsInGenClosure* cl) {
245 DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, _ct_bs->precision(), 249 DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, _ct_bs->precision(),
246 cl->gen_boundary()); 250 cl->gen_boundary());
247 ClearNoncleanCardWrapper clear_cl(dcto_cl, this); 251 ClearNoncleanCardWrapper clear_cl(dcto_cl, this);
248 252
249 _ct_bs->non_clean_card_iterate(sp, sp->used_region_at_save_marks(), 253 _ct_bs->non_clean_card_iterate_possibly_parallel(sp, sp->used_region_at_save_marks(),
250 dcto_cl, &clear_cl); 254 dcto_cl, &clear_cl);
251 } 255 }
252 256
253 void CardTableRS::clear_into_younger(Generation* gen, bool clear_perm) { 257 void CardTableRS::clear_into_younger(Generation* gen, bool clear_perm) {
254 GenCollectedHeap* gch = GenCollectedHeap::heap(); 258 GenCollectedHeap* gch = GenCollectedHeap::heap();
255 // Generations younger than gen have been evacuated. We can clear 259 // Generations younger than gen have been evacuated. We can clear