src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp

Mon, 03 Aug 2009 12:59:30 -0700

author
johnc
date
Mon, 03 Aug 2009 12:59:30 -0700
changeset 1324
15c5903cf9e1
parent 1280
df6caf649ff7
child 1696
0414c1049f15
permissions
-rw-r--r--

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@1014 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 // Remembered set for a heap region. Represent a set of "cards" that
ysr@777 26 // contain pointers into the owner heap region. Cards are defined somewhat
ysr@777 27 // abstractly, in terms of what the "BlockOffsetTable" in use can parse.
ysr@777 28
ysr@777 29 class G1CollectedHeap;
ysr@777 30 class G1BlockOffsetSharedArray;
ysr@777 31 class HeapRegion;
ysr@777 32 class HeapRegionRemSetIterator;
ysr@777 33 class PosParPRT;
ysr@777 34 class SparsePRT;
ysr@777 35
ysr@777 36
ysr@777 37 // The "_coarse_map" is a bitmap with one bit for each region, where set
ysr@777 38 // bits indicate that the corresponding region may contain some pointer
ysr@777 39 // into the owning region.
ysr@777 40
ysr@777 41 // The "_fine_grain_entries" array is an open hash table of PerRegionTables
ysr@777 42 // (PRTs), indicating regions for which we're keeping the RS as a set of
ysr@777 43 // cards. The strategy is to cap the size of the fine-grain table,
ysr@777 44 // deleting an entry and setting the corresponding coarse-grained bit when
ysr@777 45 // we would overflow this cap.
ysr@777 46
ysr@777 47 // We use a mixture of locking and lock-free techniques here. We allow
ysr@777 48 // threads to locate PRTs without locking, but threads attempting to alter
ysr@777 49 // a bucket list obtain a lock. This means that any failing attempt to
ysr@777 50 // find a PRT must be retried with the lock. It might seem dangerous that
ysr@777 51 // a read can find a PRT that is concurrently deleted. This is all right,
ysr@777 52 // because:
ysr@777 53 //
ysr@777 54 // 1) We only actually free PRT's at safe points (though we reuse them at
ysr@777 55 // other times).
ysr@777 56 // 2) We find PRT's in an attempt to add entries. If a PRT is deleted,
ysr@777 57 // it's _coarse_map bit is set, so the that we were attempting to add
ysr@777 58 // is represented. If a deleted PRT is re-used, a thread adding a bit,
ysr@777 59 // thinking the PRT is for a different region, does no harm.
ysr@777 60
apetrusenko@984 61 class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
ysr@777 62 friend class HeapRegionRemSetIterator;
ysr@777 63
ysr@777 64 G1CollectedHeap* _g1h;
ysr@777 65 Mutex _m;
ysr@777 66 HeapRegion* _hr;
ysr@777 67
ysr@777 68 // These are protected by "_m".
ysr@777 69 BitMap _coarse_map;
ysr@777 70 size_t _n_coarse_entries;
ysr@777 71 static jint _n_coarsenings;
ysr@777 72
ysr@777 73 PosParPRT** _fine_grain_regions;
ysr@777 74 size_t _n_fine_entries;
ysr@777 75
ysr@777 76 #define SAMPLE_FOR_EVICTION 1
ysr@777 77 #if SAMPLE_FOR_EVICTION
ysr@777 78 size_t _fine_eviction_start;
ysr@777 79 static size_t _fine_eviction_stride;
ysr@777 80 static size_t _fine_eviction_sample_size;
ysr@777 81 #endif
ysr@777 82
ysr@777 83 SparsePRT _sparse_table;
ysr@777 84
ysr@777 85 // These are static after init.
ysr@777 86 static size_t _max_fine_entries;
ysr@777 87 static size_t _mod_max_fine_entries_mask;
ysr@777 88
ysr@777 89 // Requires "prt" to be the first element of the bucket list appropriate
ysr@777 90 // for "hr". If this list contains an entry for "hr", return it,
ysr@777 91 // otherwise return "NULL".
ysr@777 92 PosParPRT* find_region_table(size_t ind, HeapRegion* hr) const;
ysr@777 93
ysr@777 94 // Find, delete, and return a candidate PosParPRT, if any exists,
ysr@777 95 // adding the deleted region to the coarse bitmap. Requires the caller
ysr@777 96 // to hold _m, and the fine-grain table to be full.
ysr@777 97 PosParPRT* delete_region_table();
ysr@777 98
ysr@777 99 // If a PRT for "hr" is in the bucket list indicated by "ind" (which must
ysr@777 100 // be the correct index for "hr"), delete it and return true; else return
ysr@777 101 // false.
ysr@777 102 bool del_single_region_table(size_t ind, HeapRegion* hr);
ysr@777 103
ysr@777 104 static jint _cache_probes;
ysr@777 105 static jint _cache_hits;
ysr@777 106
ysr@777 107 // Indexed by thread X heap region, to minimize thread contention.
ysr@777 108 static int** _from_card_cache;
ysr@777 109 static size_t _from_card_cache_max_regions;
ysr@777 110 static size_t _from_card_cache_mem_size;
ysr@777 111
ysr@777 112 public:
ysr@777 113 OtherRegionsTable(HeapRegion* hr);
ysr@777 114
ysr@777 115 HeapRegion* hr() const { return _hr; }
ysr@777 116
ysr@777 117 // For now. Could "expand" some tables in the future, so that this made
ysr@777 118 // sense.
ysr@1280 119 void add_reference(OopOrNarrowOopStar from, int tid);
ysr@777 120
ysr@1280 121 void add_reference(OopOrNarrowOopStar from) {
ysr@777 122 return add_reference(from, 0);
ysr@777 123 }
ysr@777 124
ysr@777 125 // Removes any entries shown by the given bitmaps to contain only dead
ysr@777 126 // objects.
ysr@777 127 void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
ysr@777 128
ysr@777 129 // Not const because it takes a lock.
ysr@777 130 size_t occupied() const;
ysr@777 131 size_t occ_fine() const;
ysr@777 132 size_t occ_coarse() const;
ysr@777 133 size_t occ_sparse() const;
ysr@777 134
ysr@777 135 static jint n_coarsenings() { return _n_coarsenings; }
ysr@777 136
ysr@777 137 // Returns size in bytes.
ysr@777 138 // Not const because it takes a lock.
ysr@777 139 size_t mem_size() const;
ysr@777 140 static size_t static_mem_size();
ysr@777 141 static size_t fl_mem_size();
ysr@777 142
ysr@1280 143 bool contains_reference(OopOrNarrowOopStar from) const;
ysr@1280 144 bool contains_reference_locked(OopOrNarrowOopStar from) const;
ysr@777 145
ysr@777 146 void clear();
ysr@777 147
ysr@777 148 // Specifically clear the from_card_cache.
ysr@777 149 void clear_fcc();
ysr@777 150
ysr@777 151 // "from_hr" is being cleared; remove any entries from it.
ysr@777 152 void clear_incoming_entry(HeapRegion* from_hr);
ysr@777 153
ysr@777 154 // Declare the heap size (in # of regions) to the OtherRegionsTable.
ysr@777 155 // (Uses it to initialize from_card_cache).
ysr@777 156 static void init_from_card_cache(size_t max_regions);
ysr@777 157
ysr@777 158 // Declares that only regions i s.t. 0 <= i < new_n_regs are in use.
ysr@777 159 // Make sure any entries for higher regions are invalid.
ysr@777 160 static void shrink_from_card_cache(size_t new_n_regs);
ysr@777 161
ysr@777 162 static void print_from_card_cache();
ysr@777 163
ysr@777 164 };
ysr@777 165
ysr@777 166
ysr@777 167 class HeapRegionRemSet : public CHeapObj {
ysr@777 168 friend class VMStructs;
ysr@777 169 friend class HeapRegionRemSetIterator;
ysr@777 170
ysr@777 171 public:
ysr@777 172 enum Event {
ysr@777 173 Event_EvacStart, Event_EvacEnd, Event_RSUpdateEnd
ysr@777 174 };
ysr@777 175
ysr@777 176 private:
ysr@777 177 G1BlockOffsetSharedArray* _bosa;
ysr@777 178 G1BlockOffsetSharedArray* bosa() const { return _bosa; }
ysr@777 179
ysr@777 180 OtherRegionsTable _other_regions;
ysr@777 181
ysr@777 182 // One set bit for every region that has an entry for this one.
ysr@777 183 BitMap _outgoing_region_map;
ysr@777 184
ysr@777 185 // Clear entries for the current region in any rem sets named in
ysr@777 186 // the _outgoing_region_map.
ysr@777 187 void clear_outgoing_entries();
ysr@777 188
ysr@777 189 enum ParIterState { Unclaimed, Claimed, Complete };
ysr@777 190 ParIterState _iter_state;
ysr@777 191
ysr@777 192 // Unused unless G1RecordHRRSOops is true.
ysr@777 193
ysr@777 194 static const int MaxRecorded = 1000000;
ysr@1280 195 static OopOrNarrowOopStar* _recorded_oops;
ysr@1280 196 static HeapWord** _recorded_cards;
ysr@1280 197 static HeapRegion** _recorded_regions;
ysr@1280 198 static int _n_recorded;
ysr@777 199
ysr@777 200 static const int MaxRecordedEvents = 1000;
ysr@777 201 static Event* _recorded_events;
ysr@777 202 static int* _recorded_event_index;
ysr@777 203 static int _n_recorded_events;
ysr@777 204
ysr@777 205 static void print_event(outputStream* str, Event evnt);
ysr@777 206
ysr@777 207 public:
ysr@777 208 HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
ysr@777 209 HeapRegion* hr);
ysr@777 210
ysr@777 211 static int num_par_rem_sets();
ysr@777 212
ysr@777 213 HeapRegion* hr() const {
ysr@777 214 return _other_regions.hr();
ysr@777 215 }
ysr@777 216
ysr@777 217 size_t occupied() const {
ysr@777 218 return _other_regions.occupied();
ysr@777 219 }
ysr@777 220 size_t occ_fine() const {
ysr@777 221 return _other_regions.occ_fine();
ysr@777 222 }
ysr@777 223 size_t occ_coarse() const {
ysr@777 224 return _other_regions.occ_coarse();
ysr@777 225 }
ysr@777 226 size_t occ_sparse() const {
ysr@777 227 return _other_regions.occ_sparse();
ysr@777 228 }
ysr@777 229
ysr@777 230 static jint n_coarsenings() { return OtherRegionsTable::n_coarsenings(); }
ysr@777 231
ysr@777 232 /* Used in the sequential case. Returns "true" iff this addition causes
ysr@777 233 the size limit to be reached. */
ysr@1280 234 void add_reference(OopOrNarrowOopStar from) {
ysr@777 235 _other_regions.add_reference(from);
ysr@777 236 }
ysr@777 237
ysr@777 238 /* Used in the parallel case. Returns "true" iff this addition causes
ysr@777 239 the size limit to be reached. */
ysr@1280 240 void add_reference(OopOrNarrowOopStar from, int tid) {
ysr@777 241 _other_regions.add_reference(from, tid);
ysr@777 242 }
ysr@777 243
ysr@777 244 // Records the fact that the current region contains an outgoing
ysr@777 245 // reference into "to_hr".
ysr@777 246 void add_outgoing_reference(HeapRegion* to_hr);
ysr@777 247
ysr@777 248 // Removes any entries shown by the given bitmaps to contain only dead
ysr@777 249 // objects.
ysr@777 250 void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
ysr@777 251
ysr@777 252 // The region is being reclaimed; clear its remset, and any mention of
ysr@777 253 // entries for this region in other remsets.
ysr@777 254 void clear();
ysr@777 255
ysr@777 256 // Forget any entries due to pointers from "from_hr".
ysr@777 257 void clear_incoming_entry(HeapRegion* from_hr) {
ysr@777 258 _other_regions.clear_incoming_entry(from_hr);
ysr@777 259 }
ysr@777 260
ysr@777 261 #if 0
ysr@777 262 virtual void cleanup() = 0;
ysr@777 263 #endif
ysr@777 264
ysr@777 265 // Should be called from single-threaded code.
ysr@777 266 void init_for_par_iteration();
ysr@777 267 // Attempt to claim the region. Returns true iff this call caused an
ysr@777 268 // atomic transition from Unclaimed to Claimed.
ysr@777 269 bool claim_iter();
ysr@777 270 // Sets the iteration state to "complete".
ysr@777 271 void set_iter_complete();
ysr@777 272 // Returns "true" iff the region's iteration is complete.
ysr@777 273 bool iter_is_complete();
ysr@777 274
ysr@777 275 // Initialize the given iterator to iterate over this rem set.
ysr@777 276 void init_iterator(HeapRegionRemSetIterator* iter) const;
ysr@777 277
ysr@777 278 #if 0
ysr@777 279 // Apply the "do_card" method to the start address of every card in the
ysr@777 280 // rem set. Returns false if some application of the closure aborted.
ysr@777 281 virtual bool card_iterate(CardClosure* iter) = 0;
ysr@777 282 #endif
ysr@777 283
ysr@777 284 // The actual # of bytes this hr_remset takes up.
ysr@777 285 size_t mem_size() {
ysr@777 286 return _other_regions.mem_size()
ysr@777 287 // This correction is necessary because the above includes the second
ysr@777 288 // part.
ysr@777 289 + sizeof(this) - sizeof(OtherRegionsTable);
ysr@777 290 }
ysr@777 291
ysr@777 292 // Returns the memory occupancy of all static data structures associated
ysr@777 293 // with remembered sets.
ysr@777 294 static size_t static_mem_size() {
ysr@777 295 return OtherRegionsTable::static_mem_size();
ysr@777 296 }
ysr@777 297
ysr@777 298 // Returns the memory occupancy of all free_list data structures associated
ysr@777 299 // with remembered sets.
ysr@777 300 static size_t fl_mem_size() {
ysr@777 301 return OtherRegionsTable::fl_mem_size();
ysr@777 302 }
ysr@777 303
ysr@1280 304 bool contains_reference(OopOrNarrowOopStar from) const {
ysr@777 305 return _other_regions.contains_reference(from);
ysr@777 306 }
ysr@777 307 void print() const;
ysr@777 308
ysr@777 309 // Called during a stop-world phase to perform any deferred cleanups.
ysr@777 310 // The second version may be called by parallel threads after then finish
ysr@777 311 // collection work.
ysr@777 312 static void cleanup();
ysr@777 313 static void par_cleanup();
ysr@777 314
ysr@777 315 // Declare the heap size (in # of regions) to the HeapRegionRemSet(s).
ysr@777 316 // (Uses it to initialize from_card_cache).
ysr@777 317 static void init_heap(size_t max_regions) {
ysr@777 318 OtherRegionsTable::init_from_card_cache(max_regions);
ysr@777 319 }
ysr@777 320
ysr@777 321 // Declares that only regions i s.t. 0 <= i < new_n_regs are in use.
ysr@777 322 static void shrink_heap(size_t new_n_regs) {
ysr@777 323 OtherRegionsTable::shrink_from_card_cache(new_n_regs);
ysr@777 324 }
ysr@777 325
ysr@777 326 #ifndef PRODUCT
ysr@777 327 static void print_from_card_cache() {
ysr@777 328 OtherRegionsTable::print_from_card_cache();
ysr@777 329 }
ysr@777 330 #endif
ysr@777 331
ysr@1280 332 static void record(HeapRegion* hr, OopOrNarrowOopStar f);
ysr@777 333 static void print_recorded();
ysr@777 334 static void record_event(Event evnt);
ysr@777 335
ysr@777 336 // Run unit tests.
ysr@777 337 #ifndef PRODUCT
ysr@777 338 static void test();
ysr@777 339 #endif
ysr@777 340
ysr@777 341 };
ysr@777 342
ysr@777 343 class HeapRegionRemSetIterator : public CHeapObj {
ysr@777 344
ysr@777 345 // The region over which we're iterating.
ysr@777 346 const HeapRegionRemSet* _hrrs;
ysr@777 347
ysr@777 348 // Local caching of HRRS fields.
ysr@777 349 const BitMap* _coarse_map;
ysr@777 350 PosParPRT** _fine_grain_regions;
ysr@777 351
ysr@777 352 G1BlockOffsetSharedArray* _bosa;
ysr@777 353 G1CollectedHeap* _g1h;
ysr@777 354
ysr@777 355 // The number yielded since initialization.
ysr@777 356 size_t _n_yielded_fine;
ysr@777 357 size_t _n_yielded_coarse;
ysr@777 358 size_t _n_yielded_sparse;
ysr@777 359
ysr@777 360 // If true we're iterating over the coarse table; if false the fine
ysr@777 361 // table.
ysr@777 362 enum IterState {
ysr@777 363 Sparse,
ysr@777 364 Fine,
ysr@777 365 Coarse
ysr@777 366 };
ysr@777 367 IterState _is;
ysr@777 368
ysr@777 369 // In both kinds of iteration, heap offset of first card of current
ysr@777 370 // region.
ysr@777 371 size_t _cur_region_card_offset;
ysr@777 372 // Card offset within cur region.
ysr@777 373 size_t _cur_region_cur_card;
ysr@777 374
ysr@777 375 // Coarse table iteration fields:
ysr@777 376
ysr@777 377 // Current region index;
ysr@777 378 int _coarse_cur_region_index;
ysr@777 379 int _coarse_cur_region_cur_card;
ysr@777 380
ysr@777 381 bool coarse_has_next(size_t& card_index);
ysr@777 382
ysr@777 383 // Fine table iteration fields:
ysr@777 384
ysr@777 385 // Index of bucket-list we're working on.
ysr@777 386 int _fine_array_index;
ysr@777 387 // Per Region Table we're doing within current bucket list.
ysr@777 388 PosParPRT* _fine_cur_prt;
ysr@777 389
ysr@777 390 /* SparsePRT::*/ SparsePRTIter _sparse_iter;
ysr@777 391
ysr@777 392 void fine_find_next_non_null_prt();
ysr@777 393
ysr@777 394 bool fine_has_next();
ysr@777 395 bool fine_has_next(size_t& card_index);
ysr@777 396
ysr@777 397 public:
ysr@777 398 // We require an iterator to be initialized before use, so the
ysr@777 399 // constructor does little.
ysr@777 400 HeapRegionRemSetIterator();
ysr@777 401
ysr@777 402 void initialize(const HeapRegionRemSet* hrrs);
ysr@777 403
ysr@777 404 // If there remains one or more cards to be yielded, returns true and
ysr@777 405 // sets "card_index" to one of those cards (which is then considered
ysr@777 406 // yielded.) Otherwise, returns false (and leaves "card_index"
ysr@777 407 // undefined.)
ysr@777 408 bool has_next(size_t& card_index);
ysr@777 409
ysr@777 410 size_t n_yielded_fine() { return _n_yielded_fine; }
ysr@777 411 size_t n_yielded_coarse() { return _n_yielded_coarse; }
ysr@777 412 size_t n_yielded_sparse() { return _n_yielded_sparse; }
ysr@777 413 size_t n_yielded() {
ysr@777 414 return n_yielded_fine() + n_yielded_coarse() + n_yielded_sparse();
ysr@777 415 }
ysr@777 416 };
ysr@777 417
ysr@777 418 #if 0
ysr@777 419 class CardClosure: public Closure {
ysr@777 420 public:
ysr@777 421 virtual void do_card(HeapWord* card_start) = 0;
ysr@777 422 };
ysr@777 423
ysr@777 424 #endif

mercurial