Mon, 03 Aug 2009 12:59:30 -0700
6865703: G1: Parallelize hot card cache cleanup
Summary: Have the GC worker threads clear the hot card cache in parallel by having each worker thread claim a chunk of the card cache and process the cards in that chunk. The size of the chunks that each thread will claim is determined at VM initialization from the size of the card cache and the number of worker threads.
Reviewed-by: jmasa, tonyp
ysr@777 | 1 | /* |
xdono@1279 | 2 | * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. |
ysr@777 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ysr@777 | 4 | * |
ysr@777 | 5 | * This code is free software; you can redistribute it and/or modify it |
ysr@777 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ysr@777 | 7 | * published by the Free Software Foundation. |
ysr@777 | 8 | * |
ysr@777 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ysr@777 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ysr@777 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ysr@777 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
ysr@777 | 13 | * accompanied this code). |
ysr@777 | 14 | * |
ysr@777 | 15 | * You should have received a copy of the GNU General Public License version |
ysr@777 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
ysr@777 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ysr@777 | 18 | * |
ysr@777 | 19 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
ysr@777 | 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
ysr@777 | 21 | * have any questions. |
ysr@777 | 22 | * |
ysr@777 | 23 | */ |
ysr@777 | 24 | |
ysr@777 | 25 | #include "incls/_precompiled.incl" |
ysr@777 | 26 | #include "incls/_sparsePRT.cpp.incl" |
ysr@777 | 27 | |
ysr@777 | 28 | #define SPARSE_PRT_VERBOSE 0 |
ysr@777 | 29 | |
ysr@777 | 30 | #define UNROLL_CARD_LOOPS 1 |
ysr@777 | 31 | |
ysr@777 | 32 | void SparsePRT::init_iterator(SparsePRTIter* sprt_iter) { |
ysr@777 | 33 | sprt_iter->init(this); |
ysr@777 | 34 | } |
ysr@777 | 35 | |
johnc@1242 | 36 | void SparsePRTEntry::init(RegionIdx_t region_ind) { |
ysr@777 | 37 | _region_ind = region_ind; |
ysr@777 | 38 | _next_index = NullEntry; |
ysr@777 | 39 | #if UNROLL_CARD_LOOPS |
ysr@777 | 40 | assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll."); |
ysr@777 | 41 | _cards[0] = NullEntry; |
ysr@777 | 42 | _cards[1] = NullEntry; |
ysr@777 | 43 | _cards[2] = NullEntry; |
ysr@777 | 44 | _cards[3] = NullEntry; |
ysr@777 | 45 | #else |
johnc@1242 | 46 | for (int i = 0; i < CardsPerEntry; i++) |
johnc@1242 | 47 | _cards[i] = NullEntry; |
ysr@777 | 48 | #endif |
ysr@777 | 49 | } |
ysr@777 | 50 | |
johnc@1242 | 51 | bool SparsePRTEntry::contains_card(CardIdx_t card_index) const { |
ysr@777 | 52 | #if UNROLL_CARD_LOOPS |
ysr@777 | 53 | assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll."); |
ysr@777 | 54 | if (_cards[0] == card_index) return true; |
ysr@777 | 55 | if (_cards[1] == card_index) return true; |
ysr@777 | 56 | if (_cards[2] == card_index) return true; |
ysr@777 | 57 | if (_cards[3] == card_index) return true; |
ysr@777 | 58 | #else |
ysr@777 | 59 | for (int i = 0; i < CardsPerEntry; i++) { |
ysr@777 | 60 | if (_cards[i] == card_index) return true; |
ysr@777 | 61 | } |
ysr@777 | 62 | #endif |
ysr@777 | 63 | // Otherwise, we're full. |
ysr@777 | 64 | return false; |
ysr@777 | 65 | } |
ysr@777 | 66 | |
ysr@777 | 67 | int SparsePRTEntry::num_valid_cards() const { |
ysr@777 | 68 | int sum = 0; |
ysr@777 | 69 | #if UNROLL_CARD_LOOPS |
ysr@777 | 70 | assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll."); |
ysr@777 | 71 | if (_cards[0] != NullEntry) sum++; |
ysr@777 | 72 | if (_cards[1] != NullEntry) sum++; |
ysr@777 | 73 | if (_cards[2] != NullEntry) sum++; |
ysr@777 | 74 | if (_cards[3] != NullEntry) sum++; |
ysr@777 | 75 | #else |
ysr@777 | 76 | for (int i = 0; i < CardsPerEntry; i++) { |
ysr@777 | 77 | if (_cards[i] != NulLEntry) sum++; |
ysr@777 | 78 | } |
ysr@777 | 79 | #endif |
ysr@777 | 80 | // Otherwise, we're full. |
ysr@777 | 81 | return sum; |
ysr@777 | 82 | } |
ysr@777 | 83 | |
johnc@1242 | 84 | SparsePRTEntry::AddCardResult SparsePRTEntry::add_card(CardIdx_t card_index) { |
ysr@777 | 85 | #if UNROLL_CARD_LOOPS |
ysr@777 | 86 | assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll."); |
johnc@1242 | 87 | CardIdx_t c = _cards[0]; |
ysr@777 | 88 | if (c == card_index) return found; |
ysr@777 | 89 | if (c == NullEntry) { _cards[0] = card_index; return added; } |
ysr@777 | 90 | c = _cards[1]; |
ysr@777 | 91 | if (c == card_index) return found; |
ysr@777 | 92 | if (c == NullEntry) { _cards[1] = card_index; return added; } |
ysr@777 | 93 | c = _cards[2]; |
ysr@777 | 94 | if (c == card_index) return found; |
ysr@777 | 95 | if (c == NullEntry) { _cards[2] = card_index; return added; } |
ysr@777 | 96 | c = _cards[3]; |
ysr@777 | 97 | if (c == card_index) return found; |
ysr@777 | 98 | if (c == NullEntry) { _cards[3] = card_index; return added; } |
ysr@777 | 99 | #else |
ysr@777 | 100 | for (int i = 0; i < CardsPerEntry; i++) { |
johnc@1242 | 101 | CardIdx_t c = _cards[i]; |
ysr@777 | 102 | if (c == card_index) return found; |
johnc@1242 | 103 | if (c == NullEntry) { |
johnc@1242 | 104 | _cards[i] = card_index; |
johnc@1242 | 105 | return added; |
johnc@1242 | 106 | } |
ysr@777 | 107 | } |
ysr@777 | 108 | #endif |
ysr@777 | 109 | // Otherwise, we're full. |
ysr@777 | 110 | return overflow; |
ysr@777 | 111 | } |
ysr@777 | 112 | |
johnc@1242 | 113 | void SparsePRTEntry::copy_cards(CardIdx_t* cards) const { |
ysr@777 | 114 | #if UNROLL_CARD_LOOPS |
ysr@777 | 115 | assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll."); |
ysr@777 | 116 | cards[0] = _cards[0]; |
ysr@777 | 117 | cards[1] = _cards[1]; |
ysr@777 | 118 | cards[2] = _cards[2]; |
ysr@777 | 119 | cards[3] = _cards[3]; |
ysr@777 | 120 | #else |
ysr@777 | 121 | for (int i = 0; i < CardsPerEntry; i++) { |
ysr@777 | 122 | cards[i] = _cards[i]; |
ysr@777 | 123 | } |
ysr@777 | 124 | #endif |
ysr@777 | 125 | } |
ysr@777 | 126 | |
ysr@777 | 127 | void SparsePRTEntry::copy_cards(SparsePRTEntry* e) const { |
ysr@777 | 128 | copy_cards(&e->_cards[0]); |
ysr@777 | 129 | } |
ysr@777 | 130 | |
ysr@777 | 131 | // ---------------------------------------------------------------------- |
ysr@777 | 132 | |
ysr@777 | 133 | RSHashTable::RSHashTable(size_t capacity) : |
ysr@777 | 134 | _capacity(capacity), _capacity_mask(capacity-1), |
ysr@777 | 135 | _occupied_entries(0), _occupied_cards(0), |
ysr@777 | 136 | _entries(NEW_C_HEAP_ARRAY(SparsePRTEntry, capacity)), |
johnc@1242 | 137 | _buckets(NEW_C_HEAP_ARRAY(int, capacity)), |
ysr@777 | 138 | _next_deleted(NULL), _deleted(false), |
ysr@777 | 139 | _free_list(NullEntry), _free_region(0) |
ysr@777 | 140 | { |
ysr@777 | 141 | clear(); |
ysr@777 | 142 | } |
ysr@777 | 143 | |
ysr@777 | 144 | RSHashTable::~RSHashTable() { |
ysr@777 | 145 | if (_entries != NULL) { |
ysr@777 | 146 | FREE_C_HEAP_ARRAY(SparsePRTEntry, _entries); |
ysr@777 | 147 | _entries = NULL; |
ysr@777 | 148 | } |
ysr@777 | 149 | if (_buckets != NULL) { |
johnc@1242 | 150 | FREE_C_HEAP_ARRAY(int, _buckets); |
ysr@777 | 151 | _buckets = NULL; |
ysr@777 | 152 | } |
ysr@777 | 153 | } |
ysr@777 | 154 | |
ysr@777 | 155 | void RSHashTable::clear() { |
ysr@777 | 156 | _occupied_entries = 0; |
ysr@777 | 157 | _occupied_cards = 0; |
ysr@777 | 158 | guarantee(_entries != NULL, "INV"); |
ysr@777 | 159 | guarantee(_buckets != NULL, "INV"); |
johnc@1242 | 160 | |
johnc@1242 | 161 | guarantee(_capacity <= ((size_t)1 << (sizeof(int)*BitsPerByte-1)) - 1, |
johnc@1242 | 162 | "_capacity too large"); |
johnc@1242 | 163 | |
ysr@777 | 164 | // This will put -1 == NullEntry in the key field of all entries. |
ysr@777 | 165 | memset(_entries, -1, _capacity * sizeof(SparsePRTEntry)); |
johnc@1242 | 166 | memset(_buckets, -1, _capacity * sizeof(int)); |
ysr@777 | 167 | _free_list = NullEntry; |
ysr@777 | 168 | _free_region = 0; |
ysr@777 | 169 | } |
ysr@777 | 170 | |
johnc@1242 | 171 | bool RSHashTable::add_card(RegionIdx_t region_ind, CardIdx_t card_index) { |
ysr@777 | 172 | SparsePRTEntry* e = entry_for_region_ind_create(region_ind); |
ysr@777 | 173 | assert(e != NULL && e->r_ind() == region_ind, |
ysr@777 | 174 | "Postcondition of call above."); |
ysr@777 | 175 | SparsePRTEntry::AddCardResult res = e->add_card(card_index); |
ysr@777 | 176 | if (res == SparsePRTEntry::added) _occupied_cards++; |
ysr@777 | 177 | #if SPARSE_PRT_VERBOSE |
ysr@777 | 178 | gclog_or_tty->print_cr(" after add_card[%d]: valid-cards = %d.", |
ysr@777 | 179 | pointer_delta(e, _entries, sizeof(SparsePRTEntry)), |
ysr@777 | 180 | e->num_valid_cards()); |
ysr@777 | 181 | #endif |
ysr@777 | 182 | assert(e->num_valid_cards() > 0, "Postcondition"); |
ysr@777 | 183 | return res != SparsePRTEntry::overflow; |
ysr@777 | 184 | } |
ysr@777 | 185 | |
johnc@1242 | 186 | bool RSHashTable::get_cards(RegionIdx_t region_ind, CardIdx_t* cards) { |
johnc@1242 | 187 | int ind = (int) (region_ind & capacity_mask()); |
johnc@1242 | 188 | int cur_ind = _buckets[ind]; |
ysr@777 | 189 | SparsePRTEntry* cur; |
ysr@777 | 190 | while (cur_ind != NullEntry && |
ysr@777 | 191 | (cur = entry(cur_ind))->r_ind() != region_ind) { |
ysr@777 | 192 | cur_ind = cur->next_index(); |
ysr@777 | 193 | } |
ysr@777 | 194 | |
ysr@777 | 195 | if (cur_ind == NullEntry) return false; |
ysr@777 | 196 | // Otherwise... |
ysr@777 | 197 | assert(cur->r_ind() == region_ind, "Postcondition of loop + test above."); |
ysr@777 | 198 | assert(cur->num_valid_cards() > 0, "Inv"); |
ysr@777 | 199 | cur->copy_cards(cards); |
ysr@777 | 200 | return true; |
ysr@777 | 201 | } |
ysr@777 | 202 | |
johnc@1242 | 203 | bool RSHashTable::delete_entry(RegionIdx_t region_ind) { |
johnc@1242 | 204 | int ind = (int) (region_ind & capacity_mask()); |
johnc@1242 | 205 | int* prev_loc = &_buckets[ind]; |
johnc@1242 | 206 | int cur_ind = *prev_loc; |
ysr@777 | 207 | SparsePRTEntry* cur; |
ysr@777 | 208 | while (cur_ind != NullEntry && |
ysr@777 | 209 | (cur = entry(cur_ind))->r_ind() != region_ind) { |
ysr@777 | 210 | prev_loc = cur->next_index_addr(); |
ysr@777 | 211 | cur_ind = *prev_loc; |
ysr@777 | 212 | } |
ysr@777 | 213 | |
ysr@777 | 214 | if (cur_ind == NullEntry) return false; |
ysr@777 | 215 | // Otherwise, splice out "cur". |
ysr@777 | 216 | *prev_loc = cur->next_index(); |
ysr@777 | 217 | _occupied_cards -= cur->num_valid_cards(); |
ysr@777 | 218 | free_entry(cur_ind); |
ysr@777 | 219 | _occupied_entries--; |
ysr@777 | 220 | return true; |
ysr@777 | 221 | } |
ysr@777 | 222 | |
johnc@1242 | 223 | SparsePRTEntry* |
johnc@1242 | 224 | RSHashTable::entry_for_region_ind(RegionIdx_t region_ind) const { |
ysr@777 | 225 | assert(occupied_entries() < capacity(), "Precondition"); |
johnc@1242 | 226 | int ind = (int) (region_ind & capacity_mask()); |
johnc@1242 | 227 | int cur_ind = _buckets[ind]; |
ysr@777 | 228 | SparsePRTEntry* cur; |
ysr@777 | 229 | // XXX |
ysr@777 | 230 | // int k = 0; |
ysr@777 | 231 | while (cur_ind != NullEntry && |
ysr@777 | 232 | (cur = entry(cur_ind))->r_ind() != region_ind) { |
ysr@777 | 233 | /* |
ysr@777 | 234 | k++; |
ysr@777 | 235 | if (k > 10) { |
ysr@777 | 236 | gclog_or_tty->print_cr("RSHashTable::entry_for_region_ind(%d): " |
ysr@777 | 237 | "k = %d, cur_ind = %d.", region_ind, k, cur_ind); |
ysr@777 | 238 | if (k >= 1000) { |
ysr@777 | 239 | while (1) ; |
ysr@777 | 240 | } |
ysr@777 | 241 | } |
ysr@777 | 242 | */ |
ysr@777 | 243 | cur_ind = cur->next_index(); |
ysr@777 | 244 | } |
ysr@777 | 245 | |
ysr@777 | 246 | if (cur_ind != NullEntry) { |
ysr@777 | 247 | assert(cur->r_ind() == region_ind, "Loop postcondition + test"); |
ysr@777 | 248 | return cur; |
ysr@777 | 249 | } else { |
ysr@777 | 250 | return NULL; |
ysr@777 | 251 | } |
ysr@777 | 252 | } |
ysr@777 | 253 | |
johnc@1242 | 254 | SparsePRTEntry* |
johnc@1242 | 255 | RSHashTable::entry_for_region_ind_create(RegionIdx_t region_ind) { |
ysr@777 | 256 | SparsePRTEntry* res = entry_for_region_ind(region_ind); |
ysr@777 | 257 | if (res == NULL) { |
johnc@1242 | 258 | int new_ind = alloc_entry(); |
ysr@777 | 259 | assert(0 <= new_ind && (size_t)new_ind < capacity(), "There should be room."); |
ysr@777 | 260 | res = entry(new_ind); |
ysr@777 | 261 | res->init(region_ind); |
ysr@777 | 262 | // Insert at front. |
johnc@1242 | 263 | int ind = (int) (region_ind & capacity_mask()); |
ysr@777 | 264 | res->set_next_index(_buckets[ind]); |
ysr@777 | 265 | _buckets[ind] = new_ind; |
ysr@777 | 266 | _occupied_entries++; |
ysr@777 | 267 | } |
ysr@777 | 268 | return res; |
ysr@777 | 269 | } |
ysr@777 | 270 | |
johnc@1242 | 271 | int RSHashTable::alloc_entry() { |
johnc@1242 | 272 | int res; |
ysr@777 | 273 | if (_free_list != NullEntry) { |
ysr@777 | 274 | res = _free_list; |
ysr@777 | 275 | _free_list = entry(res)->next_index(); |
ysr@777 | 276 | return res; |
ysr@777 | 277 | } else if ((size_t) _free_region+1 < capacity()) { |
ysr@777 | 278 | res = _free_region; |
ysr@777 | 279 | _free_region++; |
ysr@777 | 280 | return res; |
ysr@777 | 281 | } else { |
ysr@777 | 282 | return NullEntry; |
ysr@777 | 283 | } |
ysr@777 | 284 | } |
ysr@777 | 285 | |
johnc@1242 | 286 | void RSHashTable::free_entry(int fi) { |
ysr@777 | 287 | entry(fi)->set_next_index(_free_list); |
ysr@777 | 288 | _free_list = fi; |
ysr@777 | 289 | } |
ysr@777 | 290 | |
ysr@777 | 291 | void RSHashTable::add_entry(SparsePRTEntry* e) { |
ysr@777 | 292 | assert(e->num_valid_cards() > 0, "Precondition."); |
ysr@777 | 293 | SparsePRTEntry* e2 = entry_for_region_ind_create(e->r_ind()); |
ysr@777 | 294 | e->copy_cards(e2); |
ysr@777 | 295 | _occupied_cards += e2->num_valid_cards(); |
ysr@777 | 296 | assert(e2->num_valid_cards() > 0, "Postcondition."); |
ysr@777 | 297 | } |
ysr@777 | 298 | |
ysr@777 | 299 | RSHashTable* RSHashTable::_head_deleted_list = NULL; |
ysr@777 | 300 | |
ysr@777 | 301 | void RSHashTable::add_to_deleted_list(RSHashTable* rsht) { |
ysr@777 | 302 | assert(!rsht->deleted(), "Should delete only once."); |
ysr@777 | 303 | rsht->set_deleted(true); |
ysr@777 | 304 | RSHashTable* hd = _head_deleted_list; |
ysr@777 | 305 | while (true) { |
ysr@777 | 306 | rsht->_next_deleted = hd; |
ysr@777 | 307 | RSHashTable* res = |
ysr@777 | 308 | (RSHashTable*) |
ysr@777 | 309 | Atomic::cmpxchg_ptr(rsht, &_head_deleted_list, hd); |
ysr@777 | 310 | if (res == hd) return; |
ysr@777 | 311 | else hd = res; |
ysr@777 | 312 | } |
ysr@777 | 313 | } |
ysr@777 | 314 | |
ysr@777 | 315 | RSHashTable* RSHashTable::get_from_deleted_list() { |
ysr@777 | 316 | RSHashTable* hd = _head_deleted_list; |
ysr@777 | 317 | while (hd != NULL) { |
ysr@777 | 318 | RSHashTable* next = hd->next_deleted(); |
ysr@777 | 319 | RSHashTable* res = |
ysr@777 | 320 | (RSHashTable*) |
ysr@777 | 321 | Atomic::cmpxchg_ptr(next, &_head_deleted_list, hd); |
ysr@777 | 322 | if (res == hd) { |
ysr@777 | 323 | hd->set_next_deleted(NULL); |
ysr@777 | 324 | hd->set_deleted(false); |
ysr@777 | 325 | return hd; |
ysr@777 | 326 | } else { |
ysr@777 | 327 | hd = res; |
ysr@777 | 328 | } |
ysr@777 | 329 | } |
ysr@777 | 330 | return NULL; |
ysr@777 | 331 | } |
ysr@777 | 332 | |
johnc@1242 | 333 | CardIdx_t /* RSHashTable:: */ RSHashTableIter::find_first_card_in_list() { |
johnc@1242 | 334 | CardIdx_t res; |
ysr@777 | 335 | while (_bl_ind != RSHashTable::NullEntry) { |
ysr@777 | 336 | res = _rsht->entry(_bl_ind)->card(0); |
ysr@777 | 337 | if (res != SparsePRTEntry::NullEntry) { |
ysr@777 | 338 | return res; |
ysr@777 | 339 | } else { |
ysr@777 | 340 | _bl_ind = _rsht->entry(_bl_ind)->next_index(); |
ysr@777 | 341 | } |
ysr@777 | 342 | } |
ysr@777 | 343 | // Otherwise, none found: |
ysr@777 | 344 | return SparsePRTEntry::NullEntry; |
ysr@777 | 345 | } |
ysr@777 | 346 | |
johnc@1242 | 347 | size_t /* RSHashTable:: */ RSHashTableIter::compute_card_ind(CardIdx_t ci) { |
ysr@777 | 348 | return |
ysr@777 | 349 | _heap_bot_card_ind |
ysr@777 | 350 | + (_rsht->entry(_bl_ind)->r_ind() * CardsPerRegion) |
ysr@777 | 351 | + ci; |
ysr@777 | 352 | } |
ysr@777 | 353 | |
ysr@777 | 354 | bool /* RSHashTable:: */ RSHashTableIter::has_next(size_t& card_index) { |
ysr@777 | 355 | _card_ind++; |
johnc@1242 | 356 | CardIdx_t ci; |
ysr@777 | 357 | if (_card_ind < SparsePRTEntry::CardsPerEntry && |
ysr@777 | 358 | ((ci = _rsht->entry(_bl_ind)->card(_card_ind)) != |
ysr@777 | 359 | SparsePRTEntry::NullEntry)) { |
ysr@777 | 360 | card_index = compute_card_ind(ci); |
ysr@777 | 361 | return true; |
ysr@777 | 362 | } |
ysr@777 | 363 | // Otherwise, must find the next valid entry. |
ysr@777 | 364 | _card_ind = 0; |
ysr@777 | 365 | |
ysr@777 | 366 | if (_bl_ind != RSHashTable::NullEntry) { |
ysr@777 | 367 | _bl_ind = _rsht->entry(_bl_ind)->next_index(); |
ysr@777 | 368 | ci = find_first_card_in_list(); |
ysr@777 | 369 | if (ci != SparsePRTEntry::NullEntry) { |
ysr@777 | 370 | card_index = compute_card_ind(ci); |
ysr@777 | 371 | return true; |
ysr@777 | 372 | } |
ysr@777 | 373 | } |
ysr@777 | 374 | // If we didn't return above, must go to the next non-null table index. |
ysr@777 | 375 | _tbl_ind++; |
ysr@777 | 376 | while ((size_t)_tbl_ind < _rsht->capacity()) { |
ysr@777 | 377 | _bl_ind = _rsht->_buckets[_tbl_ind]; |
ysr@777 | 378 | ci = find_first_card_in_list(); |
ysr@777 | 379 | if (ci != SparsePRTEntry::NullEntry) { |
ysr@777 | 380 | card_index = compute_card_ind(ci); |
ysr@777 | 381 | return true; |
ysr@777 | 382 | } |
ysr@777 | 383 | // Otherwise, try next entry. |
ysr@777 | 384 | _tbl_ind++; |
ysr@777 | 385 | } |
ysr@777 | 386 | // Otherwise, there were no entry. |
ysr@777 | 387 | return false; |
ysr@777 | 388 | } |
ysr@777 | 389 | |
johnc@1242 | 390 | bool RSHashTable::contains_card(RegionIdx_t region_index, CardIdx_t card_index) const { |
ysr@777 | 391 | SparsePRTEntry* e = entry_for_region_ind(region_index); |
ysr@777 | 392 | return (e != NULL && e->contains_card(card_index)); |
ysr@777 | 393 | } |
ysr@777 | 394 | |
ysr@777 | 395 | size_t RSHashTable::mem_size() const { |
johnc@1242 | 396 | return sizeof(this) + |
johnc@1242 | 397 | capacity() * (sizeof(SparsePRTEntry) + sizeof(int)); |
ysr@777 | 398 | } |
ysr@777 | 399 | |
ysr@777 | 400 | // ---------------------------------------------------------------------- |
ysr@777 | 401 | |
ysr@777 | 402 | SparsePRT* SparsePRT::_head_expanded_list = NULL; |
ysr@777 | 403 | |
ysr@777 | 404 | void SparsePRT::add_to_expanded_list(SparsePRT* sprt) { |
ysr@777 | 405 | // We could expand multiple times in a pause -- only put on list once. |
ysr@777 | 406 | if (sprt->expanded()) return; |
ysr@777 | 407 | sprt->set_expanded(true); |
ysr@777 | 408 | SparsePRT* hd = _head_expanded_list; |
ysr@777 | 409 | while (true) { |
ysr@777 | 410 | sprt->_next_expanded = hd; |
ysr@777 | 411 | SparsePRT* res = |
ysr@777 | 412 | (SparsePRT*) |
ysr@777 | 413 | Atomic::cmpxchg_ptr(sprt, &_head_expanded_list, hd); |
ysr@777 | 414 | if (res == hd) return; |
ysr@777 | 415 | else hd = res; |
ysr@777 | 416 | } |
ysr@777 | 417 | } |
ysr@777 | 418 | |
johnc@1242 | 419 | |
ysr@777 | 420 | SparsePRT* SparsePRT::get_from_expanded_list() { |
ysr@777 | 421 | SparsePRT* hd = _head_expanded_list; |
ysr@777 | 422 | while (hd != NULL) { |
ysr@777 | 423 | SparsePRT* next = hd->next_expanded(); |
ysr@777 | 424 | SparsePRT* res = |
ysr@777 | 425 | (SparsePRT*) |
ysr@777 | 426 | Atomic::cmpxchg_ptr(next, &_head_expanded_list, hd); |
ysr@777 | 427 | if (res == hd) { |
ysr@777 | 428 | hd->set_next_expanded(NULL); |
ysr@777 | 429 | return hd; |
ysr@777 | 430 | } else { |
ysr@777 | 431 | hd = res; |
ysr@777 | 432 | } |
ysr@777 | 433 | } |
ysr@777 | 434 | return NULL; |
ysr@777 | 435 | } |
ysr@777 | 436 | |
ysr@777 | 437 | |
ysr@777 | 438 | void SparsePRT::cleanup_all() { |
ysr@777 | 439 | // First clean up all expanded tables so they agree on next and cur. |
ysr@777 | 440 | SparsePRT* sprt = get_from_expanded_list(); |
ysr@777 | 441 | while (sprt != NULL) { |
ysr@777 | 442 | sprt->cleanup(); |
ysr@777 | 443 | sprt = get_from_expanded_list(); |
ysr@777 | 444 | } |
ysr@777 | 445 | // Now delete all deleted RSHashTables. |
ysr@777 | 446 | RSHashTable* rsht = RSHashTable::get_from_deleted_list(); |
ysr@777 | 447 | while (rsht != NULL) { |
ysr@777 | 448 | #if SPARSE_PRT_VERBOSE |
ysr@777 | 449 | gclog_or_tty->print_cr("About to delete RSHT " PTR_FORMAT ".", rsht); |
ysr@777 | 450 | #endif |
ysr@777 | 451 | delete rsht; |
ysr@777 | 452 | rsht = RSHashTable::get_from_deleted_list(); |
ysr@777 | 453 | } |
ysr@777 | 454 | } |
ysr@777 | 455 | |
ysr@777 | 456 | |
ysr@777 | 457 | SparsePRT::SparsePRT(HeapRegion* hr) : |
ysr@777 | 458 | _expanded(false), _next_expanded(NULL) |
ysr@777 | 459 | { |
ysr@777 | 460 | _cur = new RSHashTable(InitialCapacity); |
ysr@777 | 461 | _next = _cur; |
ysr@777 | 462 | } |
ysr@777 | 463 | |
johnc@1242 | 464 | |
ysr@777 | 465 | SparsePRT::~SparsePRT() { |
ysr@777 | 466 | assert(_next != NULL && _cur != NULL, "Inv"); |
ysr@777 | 467 | if (_cur != _next) { delete _cur; } |
ysr@777 | 468 | delete _next; |
ysr@777 | 469 | } |
ysr@777 | 470 | |
ysr@777 | 471 | |
ysr@777 | 472 | size_t SparsePRT::mem_size() const { |
ysr@777 | 473 | // We ignore "_cur" here, because it either = _next, or else it is |
ysr@777 | 474 | // on the deleted list. |
ysr@777 | 475 | return sizeof(this) + _next->mem_size(); |
ysr@777 | 476 | } |
ysr@777 | 477 | |
johnc@1242 | 478 | bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) { |
ysr@777 | 479 | #if SPARSE_PRT_VERBOSE |
ysr@777 | 480 | gclog_or_tty->print_cr(" Adding card %d from region %d to region %d sparse.", |
ysr@777 | 481 | card_index, region_id, _hr->hrs_index()); |
ysr@777 | 482 | #endif |
ysr@777 | 483 | if (_next->occupied_entries() * 2 > _next->capacity()) { |
ysr@777 | 484 | expand(); |
ysr@777 | 485 | } |
ysr@777 | 486 | return _next->add_card(region_id, card_index); |
ysr@777 | 487 | } |
ysr@777 | 488 | |
johnc@1242 | 489 | bool SparsePRT::get_cards(RegionIdx_t region_id, CardIdx_t* cards) { |
ysr@777 | 490 | return _next->get_cards(region_id, cards); |
ysr@777 | 491 | } |
ysr@777 | 492 | |
johnc@1242 | 493 | bool SparsePRT::delete_entry(RegionIdx_t region_id) { |
ysr@777 | 494 | return _next->delete_entry(region_id); |
ysr@777 | 495 | } |
ysr@777 | 496 | |
ysr@777 | 497 | void SparsePRT::clear() { |
ysr@777 | 498 | // If they differ, _next is bigger then cur, so next has no chance of |
ysr@777 | 499 | // being the initial size. |
ysr@777 | 500 | if (_next != _cur) { |
ysr@777 | 501 | delete _next; |
ysr@777 | 502 | } |
ysr@777 | 503 | |
ysr@777 | 504 | if (_cur->capacity() != InitialCapacity) { |
ysr@777 | 505 | delete _cur; |
ysr@777 | 506 | _cur = new RSHashTable(InitialCapacity); |
ysr@777 | 507 | } else { |
ysr@777 | 508 | _cur->clear(); |
ysr@777 | 509 | } |
ysr@777 | 510 | _next = _cur; |
ysr@777 | 511 | } |
ysr@777 | 512 | |
ysr@777 | 513 | void SparsePRT::cleanup() { |
ysr@777 | 514 | // Make sure that the current and next tables agree. (Another mechanism |
ysr@777 | 515 | // takes care of deleting now-unused tables.) |
ysr@777 | 516 | _cur = _next; |
tonyp@1052 | 517 | set_expanded(false); |
ysr@777 | 518 | } |
ysr@777 | 519 | |
ysr@777 | 520 | void SparsePRT::expand() { |
ysr@777 | 521 | RSHashTable* last = _next; |
ysr@777 | 522 | _next = new RSHashTable(last->capacity() * 2); |
ysr@777 | 523 | |
ysr@777 | 524 | #if SPARSE_PRT_VERBOSE |
ysr@777 | 525 | gclog_or_tty->print_cr(" Expanded sparse table for %d to %d.", |
ysr@777 | 526 | _hr->hrs_index(), _next->capacity()); |
ysr@777 | 527 | #endif |
ysr@777 | 528 | for (size_t i = 0; i < last->capacity(); i++) { |
ysr@777 | 529 | SparsePRTEntry* e = last->entry((int)i); |
ysr@777 | 530 | if (e->valid_entry()) { |
ysr@777 | 531 | #if SPARSE_PRT_VERBOSE |
ysr@777 | 532 | gclog_or_tty->print_cr(" During expansion, transferred entry for %d.", |
ysr@777 | 533 | e->r_ind()); |
ysr@777 | 534 | #endif |
ysr@777 | 535 | _next->add_entry(e); |
ysr@777 | 536 | } |
ysr@777 | 537 | } |
ysr@777 | 538 | if (last != _cur) |
ysr@777 | 539 | RSHashTable::add_to_deleted_list(last); |
ysr@777 | 540 | add_to_expanded_list(this); |
ysr@777 | 541 | } |