28 // ======= Concurrent Mark Thread ======== |
28 // ======= Concurrent Mark Thread ======== |
29 |
29 |
30 // The CM thread is created when the G1 garbage collector is used |
30 // The CM thread is created when the G1 garbage collector is used |
31 |
31 |
32 ConcurrentG1RefineThread:: |
32 ConcurrentG1RefineThread:: |
33 ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r) : |
33 ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next, int worker_id) : |
34 ConcurrentGCThread(), |
34 ConcurrentGCThread(), |
|
35 _worker_id(worker_id), |
|
36 _active(false), |
|
37 _next(next), |
35 _cg1r(cg1r), |
38 _cg1r(cg1r), |
36 _started(false), |
|
37 _in_progress(false), |
|
38 _do_traversal(false), |
|
39 _vtime_accum(0.0), |
39 _vtime_accum(0.0), |
40 _co_tracker(G1CRGroup), |
40 _co_tracker(G1CRGroup), |
41 _interval_ms(5.0) |
41 _interval_ms(5.0) |
42 { |
42 { |
43 create_and_start(); |
43 create_and_start(); |
44 } |
44 } |
45 |
45 |
46 const long timeout = 200; // ms. |
46 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() { |
47 |
47 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
48 void ConcurrentG1RefineThread::traversalBasedRefinement() { |
48 G1CollectorPolicy* g1p = g1h->g1_policy(); |
49 _cg1r->wait_for_ConcurrentG1Refine_enabled(); |
49 if (g1p->adaptive_young_list_length()) { |
50 MutexLocker x(G1ConcRefine_mon); |
50 int regions_visited = 0; |
51 while (_cg1r->enabled()) { |
51 |
52 MutexUnlocker ux(G1ConcRefine_mon); |
52 g1h->young_list_rs_length_sampling_init(); |
53 ResourceMark rm; |
53 while (g1h->young_list_rs_length_sampling_more()) { |
54 HandleMark hm; |
54 g1h->young_list_rs_length_sampling_next(); |
55 |
55 ++regions_visited; |
56 if (G1TraceConcurrentRefinement) { |
56 |
57 gclog_or_tty->print_cr("G1-Refine starting pass"); |
57 // we try to yield every time we visit 10 regions |
58 } |
58 if (regions_visited == 10) { |
|
59 if (_sts.should_yield()) { |
|
60 _sts.yield("G1 refine"); |
|
61 // we just abandon the iteration |
|
62 break; |
|
63 } |
|
64 regions_visited = 0; |
|
65 } |
|
66 } |
|
67 |
|
68 g1p->check_prediction_validity(); |
|
69 } |
|
70 } |
|
71 |
|
72 void ConcurrentG1RefineThread::run() { |
|
73 initialize_in_thread(); |
|
74 _vtime_start = os::elapsedVTime(); |
|
75 wait_for_universe_init(); |
|
76 |
|
77 _co_tracker.enable(); |
|
78 _co_tracker.start(); |
|
79 |
|
80 while (!_should_terminate) { |
|
81 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); |
|
82 // Wait for completed log buffers to exist. |
|
83 { |
|
84 MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); |
|
85 while (((_worker_id == 0 && !dcqs.process_completed_buffers()) || |
|
86 (_worker_id > 0 && !is_active())) && |
|
87 !_should_terminate) { |
|
88 DirtyCardQ_CBL_mon->wait(Mutex::_no_safepoint_check_flag); |
|
89 } |
|
90 } |
|
91 |
|
92 if (_should_terminate) { |
|
93 return; |
|
94 } |
|
95 |
|
96 // Now we take them off (this doesn't hold locks while it applies |
|
97 // closures.) (If we did a full collection, then we'll do a full |
|
98 // traversal. |
59 _sts.join(); |
99 _sts.join(); |
60 bool no_sleep = _cg1r->refine(); |
|
61 _sts.leave(); |
|
62 if (!no_sleep) { |
|
63 MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); |
|
64 // We do this only for the timeout; we don't expect this to be signalled. |
|
65 CGC_lock->wait(Mutex::_no_safepoint_check_flag, timeout); |
|
66 } |
|
67 } |
|
68 } |
|
69 |
|
70 void ConcurrentG1RefineThread::queueBasedRefinement() { |
|
71 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); |
|
72 // Wait for completed log buffers to exist. |
|
73 { |
|
74 MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); |
|
75 while (!_do_traversal && !dcqs.process_completed_buffers() && |
|
76 !_should_terminate) { |
|
77 DirtyCardQ_CBL_mon->wait(Mutex::_no_safepoint_check_flag); |
|
78 } |
|
79 } |
|
80 |
|
81 if (_should_terminate) { |
|
82 return; |
|
83 } |
|
84 |
|
85 // Now we take them off (this doesn't hold locks while it applies |
|
86 // closures.) (If we did a full collection, then we'll do a full |
|
87 // traversal. |
|
88 _sts.join(); |
|
89 if (_do_traversal) { |
|
90 (void)_cg1r->refine(); |
|
91 switch (_cg1r->get_last_pya()) { |
|
92 case PYA_cancel: case PYA_continue: |
|
93 // Continue was caught and handled inside "refine". If it's still |
|
94 // "continue" when we get here, we're done. |
|
95 _do_traversal = false; |
|
96 break; |
|
97 case PYA_restart: |
|
98 assert(_do_traversal, "Because of Full GC."); |
|
99 break; |
|
100 } |
|
101 } else { |
|
102 int n_logs = 0; |
100 int n_logs = 0; |
103 int lower_limit = 0; |
101 int lower_limit = 0; |
104 double start_vtime_sec; // only used when G1SmoothConcRefine is on |
102 double start_vtime_sec; // only used when G1SmoothConcRefine is on |
105 int prev_buffer_num; // only used when G1SmoothConcRefine is on |
103 int prev_buffer_num; // only used when G1SmoothConcRefine is on |
|
104 // This thread activation threshold |
|
105 int threshold = DCQBarrierProcessCompletedThreshold * _worker_id; |
|
106 // Next thread activation threshold |
|
107 int next_threshold = threshold + DCQBarrierProcessCompletedThreshold; |
|
108 int deactivation_threshold = MAX2<int>(threshold - DCQBarrierProcessCompletedThreshold / 2, 0); |
106 |
109 |
107 if (G1SmoothConcRefine) { |
110 if (G1SmoothConcRefine) { |
108 lower_limit = 0; |
111 lower_limit = 0; |
109 start_vtime_sec = os::elapsedVTime(); |
112 start_vtime_sec = os::elapsedVTime(); |
110 prev_buffer_num = (int) dcqs.completed_buffers_num(); |
113 prev_buffer_num = (int) dcqs.completed_buffers_num(); |
111 } else { |
114 } else { |
112 lower_limit = DCQBarrierProcessCompletedThreshold / 4; // For now. |
115 lower_limit = DCQBarrierProcessCompletedThreshold / 4; // For now. |
113 } |
116 } |
114 while (dcqs.apply_closure_to_completed_buffer(0, lower_limit)) { |
117 while (dcqs.apply_closure_to_completed_buffer(_worker_id, lower_limit)) { |
115 double end_vtime_sec; |
118 double end_vtime_sec; |
116 double elapsed_vtime_sec; |
119 double elapsed_vtime_sec; |
117 int elapsed_vtime_ms; |
120 int elapsed_vtime_ms; |
118 int curr_buffer_num; |
121 int curr_buffer_num = (int) dcqs.completed_buffers_num(); |
119 |
122 |
120 if (G1SmoothConcRefine) { |
123 if (G1SmoothConcRefine) { |
121 end_vtime_sec = os::elapsedVTime(); |
124 end_vtime_sec = os::elapsedVTime(); |
122 elapsed_vtime_sec = end_vtime_sec - start_vtime_sec; |
125 elapsed_vtime_sec = end_vtime_sec - start_vtime_sec; |
123 elapsed_vtime_ms = (int) (elapsed_vtime_sec * 1000.0); |
126 elapsed_vtime_ms = (int) (elapsed_vtime_sec * 1000.0); |
124 curr_buffer_num = (int) dcqs.completed_buffers_num(); |
|
125 |
127 |
126 if (curr_buffer_num > prev_buffer_num || |
128 if (curr_buffer_num > prev_buffer_num || |
127 curr_buffer_num > DCQBarrierProcessCompletedThreshold) { |
129 curr_buffer_num > next_threshold) { |
128 decreaseInterval(elapsed_vtime_ms); |
130 decreaseInterval(elapsed_vtime_ms); |
129 } else if (curr_buffer_num < prev_buffer_num) { |
131 } else if (curr_buffer_num < prev_buffer_num) { |
130 increaseInterval(elapsed_vtime_ms); |
132 increaseInterval(elapsed_vtime_ms); |
131 } |
133 } |
132 } |
134 } |
133 |
135 if (_worker_id == 0) { |
134 sample_young_list_rs_lengths(); |
136 sample_young_list_rs_lengths(); |
|
137 } else if (curr_buffer_num < deactivation_threshold) { |
|
138 // If the number of the buffer has fallen below our threshold |
|
139 // we should deactivate. The predecessor will reactivate this |
|
140 // thread should the number of the buffers cross the threshold again. |
|
141 MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); |
|
142 deactivate(); |
|
143 if (G1TraceConcurrentRefinement) { |
|
144 gclog_or_tty->print_cr("G1-Refine-deactivated worker %d", _worker_id); |
|
145 } |
|
146 break; |
|
147 } |
135 _co_tracker.update(false); |
148 _co_tracker.update(false); |
|
149 |
|
150 // Check if we need to activate the next thread. |
|
151 if (curr_buffer_num > next_threshold && _next != NULL && !_next->is_active()) { |
|
152 MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); |
|
153 _next->activate(); |
|
154 DirtyCardQ_CBL_mon->notify_all(); |
|
155 if (G1TraceConcurrentRefinement) { |
|
156 gclog_or_tty->print_cr("G1-Refine-activated worker %d", _next->_worker_id); |
|
157 } |
|
158 } |
136 |
159 |
137 if (G1SmoothConcRefine) { |
160 if (G1SmoothConcRefine) { |
138 prev_buffer_num = curr_buffer_num; |
161 prev_buffer_num = curr_buffer_num; |
139 _sts.leave(); |
162 _sts.leave(); |
140 os::sleep(Thread::current(), (jlong) _interval_ms, false); |
163 os::sleep(Thread::current(), (jlong) _interval_ms, false); |
141 _sts.join(); |
164 _sts.join(); |
142 start_vtime_sec = os::elapsedVTime(); |
165 start_vtime_sec = os::elapsedVTime(); |
143 } |
166 } |
144 n_logs++; |
167 n_logs++; |
145 } |
168 } |
146 // Make sure we harvest the PYA, if any. |
169 _co_tracker.update(false); |
147 (void)_cg1r->get_pya(); |
|
148 } |
|
149 _sts.leave(); |
|
150 } |
|
151 |
|
152 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() { |
|
153 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
|
154 G1CollectorPolicy* g1p = g1h->g1_policy(); |
|
155 if (g1p->adaptive_young_list_length()) { |
|
156 int regions_visited = 0; |
|
157 |
|
158 g1h->young_list_rs_length_sampling_init(); |
|
159 while (g1h->young_list_rs_length_sampling_more()) { |
|
160 g1h->young_list_rs_length_sampling_next(); |
|
161 ++regions_visited; |
|
162 |
|
163 // we try to yield every time we visit 10 regions |
|
164 if (regions_visited == 10) { |
|
165 if (_sts.should_yield()) { |
|
166 _sts.yield("G1 refine"); |
|
167 // we just abandon the iteration |
|
168 break; |
|
169 } |
|
170 regions_visited = 0; |
|
171 } |
|
172 } |
|
173 |
|
174 g1p->check_prediction_validity(); |
|
175 } |
|
176 } |
|
177 |
|
178 void ConcurrentG1RefineThread::run() { |
|
179 initialize_in_thread(); |
|
180 _vtime_start = os::elapsedVTime(); |
|
181 wait_for_universe_init(); |
|
182 |
|
183 _co_tracker.enable(); |
|
184 _co_tracker.start(); |
|
185 |
|
186 while (!_should_terminate) { |
|
187 // wait until started is set. |
|
188 if (G1RSBarrierUseQueue) { |
|
189 queueBasedRefinement(); |
|
190 } else { |
|
191 traversalBasedRefinement(); |
|
192 } |
|
193 _sts.join(); |
|
194 _co_tracker.update(); |
|
195 _sts.leave(); |
170 _sts.leave(); |
|
171 |
196 if (os::supports_vtime()) { |
172 if (os::supports_vtime()) { |
197 _vtime_accum = (os::elapsedVTime() - _vtime_start); |
173 _vtime_accum = (os::elapsedVTime() - _vtime_start); |
198 } else { |
174 } else { |
199 _vtime_accum = 0.0; |
175 _vtime_accum = 0.0; |
200 } |
176 } |