Thu, 22 Apr 2010 10:02:38 -0700
6819061: G1: eliminate serial Other times that are proportional to the collection set length
6871109: G1: remove the concept of the scan only prefix
Summary: Removed scan only regions and associated code. The young portion of the collection set is now constructed incrementally - when a young region is retired as the current allocation region it is added to the collection set.
Reviewed-by: apetrusenko, iveresov, tonyp
1 /*
2 * Copyright 2001-2010 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
25 #include "incls/_precompiled.incl"
26 #include "incls/_concurrentG1RefineThread.cpp.incl"
28 ConcurrentG1RefineThread::
29 ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next,
30 int worker_id_offset, int worker_id) :
31 ConcurrentGCThread(),
32 _worker_id_offset(worker_id_offset),
33 _worker_id(worker_id),
34 _active(false),
35 _next(next),
36 _monitor(NULL),
37 _cg1r(cg1r),
38 _vtime_accum(0.0)
39 {
41 // Each thread has its own monitor. The i-th thread is responsible for signalling
42 // to thread i+1 if the number of buffers in the queue exceeds a threashold for this
43 // thread. Monitors are also used to wake up the threads during termination.
44 // The 0th worker in notified by mutator threads and has a special monitor.
45 // The last worker is used for young gen rset size sampling.
46 if (worker_id > 0) {
47 _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true);
48 } else {
49 _monitor = DirtyCardQ_CBL_mon;
50 }
51 initialize();
52 create_and_start();
53 }
55 void ConcurrentG1RefineThread::initialize() {
56 if (_worker_id < cg1r()->worker_thread_num()) {
57 // Current thread activation threshold
58 _threshold = MIN2<int>(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(),
59 cg1r()->yellow_zone());
60 // A thread deactivates once the number of buffer reached a deactivation threshold
61 _deactivation_threshold = MAX2<int>(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone());
62 } else {
63 set_active(true);
64 }
65 }
67 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
68 G1CollectedHeap* g1h = G1CollectedHeap::heap();
69 G1CollectorPolicy* g1p = g1h->g1_policy();
70 if (g1p->adaptive_young_list_length()) {
71 int regions_visited = 0;
72 g1h->young_list()->rs_length_sampling_init();
73 while (g1h->young_list()->rs_length_sampling_more()) {
74 g1h->young_list()->rs_length_sampling_next();
75 ++regions_visited;
77 // we try to yield every time we visit 10 regions
78 if (regions_visited == 10) {
79 if (_sts.should_yield()) {
80 _sts.yield("G1 refine");
81 // we just abandon the iteration
82 break;
83 }
84 regions_visited = 0;
85 }
86 }
88 g1p->check_prediction_validity();
89 }
90 }
92 void ConcurrentG1RefineThread::run_young_rs_sampling() {
93 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
94 _vtime_start = os::elapsedVTime();
95 while(!_should_terminate) {
96 _sts.join();
97 sample_young_list_rs_lengths();
98 _sts.leave();
100 if (os::supports_vtime()) {
101 _vtime_accum = (os::elapsedVTime() - _vtime_start);
102 } else {
103 _vtime_accum = 0.0;
104 }
106 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
107 if (_should_terminate) {
108 break;
109 }
110 _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis);
111 }
112 }
114 void ConcurrentG1RefineThread::wait_for_completed_buffers() {
115 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
116 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
117 while (!_should_terminate && !is_active()) {
118 _monitor->wait(Mutex::_no_safepoint_check_flag);
119 }
120 }
122 bool ConcurrentG1RefineThread::is_active() {
123 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
124 return _worker_id > 0 ? _active : dcqs.process_completed_buffers();
125 }
127 void ConcurrentG1RefineThread::activate() {
128 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
129 if (_worker_id > 0) {
130 if (G1TraceConcRefinement) {
131 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
132 gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d",
133 _worker_id, _threshold, (int)dcqs.completed_buffers_num());
134 }
135 set_active(true);
136 } else {
137 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
138 dcqs.set_process_completed(true);
139 }
140 _monitor->notify();
141 }
143 void ConcurrentG1RefineThread::deactivate() {
144 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
145 if (_worker_id > 0) {
146 if (G1TraceConcRefinement) {
147 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
148 gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d",
149 _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num());
150 }
151 set_active(false);
152 } else {
153 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
154 dcqs.set_process_completed(false);
155 }
156 }
158 void ConcurrentG1RefineThread::run() {
159 initialize_in_thread();
160 wait_for_universe_init();
162 if (_worker_id >= cg1r()->worker_thread_num()) {
163 run_young_rs_sampling();
164 terminate();
165 return;
166 }
168 _vtime_start = os::elapsedVTime();
169 while (!_should_terminate) {
170 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
172 // Wait for work
173 wait_for_completed_buffers();
175 if (_should_terminate) {
176 break;
177 }
179 _sts.join();
181 do {
182 int curr_buffer_num = (int)dcqs.completed_buffers_num();
183 // If the number of the buffers falls down into the yellow zone,
184 // that means that the transition period after the evacuation pause has ended.
185 if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
186 dcqs.set_completed_queue_padding(0);
187 }
189 if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
190 // If the number of the buffer has fallen below our threshold
191 // we should deactivate. The predecessor will reactivate this
192 // thread should the number of the buffers cross the threshold again.
193 deactivate();
194 break;
195 }
197 // Check if we need to activate the next thread.
198 if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
199 _next->activate();
200 }
201 } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone()));
203 // We can exit the loop above while being active if there was a yield request.
204 if (is_active()) {
205 deactivate();
206 }
208 _sts.leave();
210 if (os::supports_vtime()) {
211 _vtime_accum = (os::elapsedVTime() - _vtime_start);
212 } else {
213 _vtime_accum = 0.0;
214 }
215 }
216 assert(_should_terminate, "just checking");
217 terminate();
218 }
221 void ConcurrentG1RefineThread::yield() {
222 if (G1TraceConcRefinement) {
223 gclog_or_tty->print_cr("G1-Refine-yield");
224 }
225 _sts.yield("G1 refine");
226 if (G1TraceConcRefinement) {
227 gclog_or_tty->print_cr("G1-Refine-yield-end");
228 }
229 }
231 void ConcurrentG1RefineThread::stop() {
232 // it is ok to take late safepoints here, if needed
233 {
234 MutexLockerEx mu(Terminator_lock);
235 _should_terminate = true;
236 }
238 {
239 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
240 _monitor->notify();
241 }
243 {
244 MutexLockerEx mu(Terminator_lock);
245 while (!_has_terminated) {
246 Terminator_lock->wait();
247 }
248 }
249 if (G1TraceConcRefinement) {
250 gclog_or_tty->print_cr("G1-Refine-stop");
251 }
252 }
254 void ConcurrentG1RefineThread::print() const {
255 print_on(tty);
256 }
258 void ConcurrentG1RefineThread::print_on(outputStream* st) const {
259 st->print("\"G1 Concurrent Refinement Thread#%d\" ", _worker_id);
260 Thread::print_on(st);
261 st->cr();
262 }