Mercurial > hg > truffle
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 |