Wed, 14 Dec 2011 17:43:55 -0800
7119908: G1: Cache CSet start region for each worker for subsequent reuse
Summary: Cache workers' calculated starting heap region, used for parallel iteration over the collcection set, for subsequent reuse.
Reviewed-by: tonyp, brutisso
1.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Dec 14 12:15:26 2011 +0100 1.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Dec 14 17:43:55 2011 -0800 1.3 @@ -1842,7 +1842,9 @@ 1.4 _full_collections_completed(0), 1.5 _in_cset_fast_test(NULL), 1.6 _in_cset_fast_test_base(NULL), 1.7 - _dirty_cards_region_list(NULL) { 1.8 + _dirty_cards_region_list(NULL), 1.9 + _worker_cset_start_region(NULL), 1.10 + _worker_cset_start_region_time_stamp(NULL) { 1.11 _g1h = this; // To catch bugs. 1.12 if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) { 1.13 vm_exit_during_initialization("Failed necessary allocation."); 1.14 @@ -1863,12 +1865,17 @@ 1.15 } 1.16 _rem_set_iterator = iter_arr; 1.17 1.18 + _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues); 1.19 + _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues); 1.20 + 1.21 for (int i = 0; i < n_queues; i++) { 1.22 RefToScanQueue* q = new RefToScanQueue(); 1.23 q->initialize(); 1.24 _task_queues->register_queue(i, q); 1.25 } 1.26 1.27 + clear_cset_start_regions(); 1.28 + 1.29 guarantee(_task_queues != NULL, "task_queues allocation failure."); 1.30 } 1.31 1.32 @@ -2687,25 +2694,80 @@ 1.33 } 1.34 #endif // ASSERT 1.35 1.36 -// We want the parallel threads to start their collection 1.37 -// set iteration at different collection set regions to 1.38 -// avoid contention. 1.39 -// If we have: 1.40 -// n collection set regions 1.41 -// p threads 1.42 -// Then thread t will start at region t * floor (n/p) 1.43 - 1.44 +// Clear the cached CSet starting regions and (more importantly) 1.45 +// the time stamps. Called when we reset the GC time stamp. 1.46 +void G1CollectedHeap::clear_cset_start_regions() { 1.47 + assert(_worker_cset_start_region != NULL, "sanity"); 1.48 + assert(_worker_cset_start_region_time_stamp != NULL, "sanity"); 1.49 + 1.50 + int n_queues = MAX2((int)ParallelGCThreads, 1); 1.51 + for (int i = 0; i < n_queues; i++) { 1.52 + _worker_cset_start_region[i] = NULL; 1.53 + _worker_cset_start_region_time_stamp[i] = 0; 1.54 + } 1.55 +} 1.56 + 1.57 +// Given the id of a worker, obtain or calculate a suitable 1.58 +// starting region for iterating over the current collection set. 1.59 HeapRegion* G1CollectedHeap::start_cset_region_for_worker(int worker_i) { 1.60 - HeapRegion* result = g1_policy()->collection_set(); 1.61 + assert(get_gc_time_stamp() > 0, "should have been updated by now"); 1.62 + 1.63 + HeapRegion* result = NULL; 1.64 + unsigned gc_time_stamp = get_gc_time_stamp(); 1.65 + 1.66 + if (_worker_cset_start_region_time_stamp[worker_i] == gc_time_stamp) { 1.67 + // Cached starting region for current worker was set 1.68 + // during the current pause - so it's valid. 1.69 + // Note: the cached starting heap region may be NULL 1.70 + // (when the collection set is empty). 1.71 + result = _worker_cset_start_region[worker_i]; 1.72 + assert(result == NULL || result->in_collection_set(), "sanity"); 1.73 + return result; 1.74 + } 1.75 + 1.76 + // The cached entry was not valid so let's calculate 1.77 + // a suitable starting heap region for this worker. 1.78 + 1.79 + // We want the parallel threads to start their collection 1.80 + // set iteration at different collection set regions to 1.81 + // avoid contention. 1.82 + // If we have: 1.83 + // n collection set regions 1.84 + // p threads 1.85 + // Then thread t will start at region floor ((t * n) / p) 1.86 + 1.87 + result = g1_policy()->collection_set(); 1.88 if (G1CollectedHeap::use_parallel_gc_threads()) { 1.89 size_t cs_size = g1_policy()->cset_region_length(); 1.90 - int n_workers = workers()->total_workers(); 1.91 - size_t cs_spans = cs_size / n_workers; 1.92 - size_t ind = cs_spans * worker_i; 1.93 - for (size_t i = 0; i < ind; i++) { 1.94 + int active_workers = workers()->active_workers(); 1.95 + assert(UseDynamicNumberOfGCThreads || 1.96 + active_workers == workers()->total_workers(), 1.97 + "Unless dynamic should use total workers"); 1.98 + 1.99 + size_t end_ind = (cs_size * worker_i) / active_workers; 1.100 + size_t start_ind = 0; 1.101 + 1.102 + if (worker_i > 0 && 1.103 + _worker_cset_start_region_time_stamp[worker_i - 1] == gc_time_stamp) { 1.104 + // Previous workers starting region is valid 1.105 + // so let's iterate from there 1.106 + start_ind = (cs_size * (worker_i - 1)) / active_workers; 1.107 + result = _worker_cset_start_region[worker_i - 1]; 1.108 + } 1.109 + 1.110 + for (size_t i = start_ind; i < end_ind; i++) { 1.111 result = result->next_in_collection_set(); 1.112 } 1.113 } 1.114 + 1.115 + // Note: the calculated starting heap region may be NULL 1.116 + // (when the collection set is empty). 1.117 + assert(result == NULL || result->in_collection_set(), "sanity"); 1.118 + assert(_worker_cset_start_region_time_stamp[worker_i] != gc_time_stamp, 1.119 + "should be updated only once per pause"); 1.120 + _worker_cset_start_region[worker_i] = result; 1.121 + OrderAccess::storestore(); 1.122 + _worker_cset_start_region_time_stamp[worker_i] = gc_time_stamp; 1.123 return result; 1.124 } 1.125
2.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Dec 14 12:15:26 2011 +0100 2.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Dec 14 17:43:55 2011 -0800 2.3 @@ -943,6 +943,16 @@ 2.4 // discovery. 2.5 G1CMIsAliveClosure _is_alive_closure_cm; 2.6 2.7 + // Cache used by G1CollectedHeap::start_cset_region_for_worker(). 2.8 + HeapRegion** _worker_cset_start_region; 2.9 + 2.10 + // Time stamp to validate the regions recorded in the cache 2.11 + // used by G1CollectedHeap::start_cset_region_for_worker(). 2.12 + // The heap region entry for a given worker is valid iff 2.13 + // the associated time stamp value matches the current value 2.14 + // of G1CollectedHeap::_gc_time_stamp. 2.15 + unsigned int* _worker_cset_start_region_time_stamp; 2.16 + 2.17 enum G1H_process_strong_roots_tasks { 2.18 G1H_PS_mark_stack_oops_do, 2.19 G1H_PS_refProcessor_oops_do, 2.20 @@ -1030,6 +1040,9 @@ 2.21 void reset_gc_time_stamp() { 2.22 _gc_time_stamp = 0; 2.23 OrderAccess::fence(); 2.24 + // Clear the cached CSet starting regions and time stamps. 2.25 + // Their validity is dependent on the GC timestamp. 2.26 + clear_cset_start_regions(); 2.27 } 2.28 2.29 void increment_gc_time_stamp() { 2.30 @@ -1300,9 +1313,12 @@ 2.31 bool check_cset_heap_region_claim_values(jint claim_value); 2.32 #endif // ASSERT 2.33 2.34 - // Given the id of a worker, calculate a suitable 2.35 - // starting region for iterating over the current 2.36 - // collection set. 2.37 + // Clear the cached cset start regions and (more importantly) 2.38 + // the time stamps. Called when we reset the GC time stamp. 2.39 + void clear_cset_start_regions(); 2.40 + 2.41 + // Given the id of a worker, obtain or calculate a suitable 2.42 + // starting region for iterating over the current collection set. 2.43 HeapRegion* start_cset_region_for_worker(int worker_i); 2.44 2.45 // Iterate over the regions (if any) in the current collection set.