Mercurial > hg > graal-compiler
annotate src/share/vm/utilities/workgroup.cpp @ 8804:91bf0bdae37b
8008217: CDS: Class data sharing limits the malloc heap on Solaris
Summary: In 64bit VM move CDS archive address to 32G on all platforms using new flag SharedBaseAddress. In 32bit VM set CDS archive address to 3Gb on Linux and let other OSs pick the address.
Reviewed-by: kvn, dcubed, zgu, hseigel
author | coleenp |
---|---|
date | Wed, 20 Mar 2013 08:04:54 -0400 |
parents | b9a9ed0f8eeb |
children | 6f817ce50129 |
rev | line source |
---|---|
0 | 1 /* |
6842
b9a9ed0f8eeb
7197424: update copyright year to match last edit in jdk8 hotspot repository
mikael
parents:
6197
diff
changeset
|
2 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
342
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
342
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
342
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "memory/allocation.hpp" | |
27 #include "memory/allocation.inline.hpp" | |
28 #include "runtime/os.hpp" | |
29 #include "utilities/workgroup.hpp" | |
0 | 30 |
31 // Definitions of WorkGang methods. | |
32 | |
33 AbstractWorkGang::AbstractWorkGang(const char* name, | |
342 | 34 bool are_GC_task_threads, |
35 bool are_ConcurrentGC_threads) : | |
0 | 36 _name(name), |
342 | 37 _are_GC_task_threads(are_GC_task_threads), |
38 _are_ConcurrentGC_threads(are_ConcurrentGC_threads) { | |
39 | |
40 assert(!(are_GC_task_threads && are_ConcurrentGC_threads), | |
41 "They cannot both be STW GC and Concurrent threads" ); | |
42 | |
0 | 43 // Other initialization. |
44 _monitor = new Monitor(/* priority */ Mutex::leaf, | |
45 /* name */ "WorkGroup monitor", | |
342 | 46 /* allow_vm_block */ are_GC_task_threads); |
0 | 47 assert(monitor() != NULL, "Failed to allocate monitor"); |
48 _terminate = false; | |
49 _task = NULL; | |
50 _sequence_number = 0; | |
51 _started_workers = 0; | |
52 _finished_workers = 0; | |
53 } | |
54 | |
55 WorkGang::WorkGang(const char* name, | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
56 uint workers, |
342 | 57 bool are_GC_task_threads, |
58 bool are_ConcurrentGC_threads) : | |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
59 AbstractWorkGang(name, are_GC_task_threads, are_ConcurrentGC_threads) { |
0 | 60 _total_workers = workers; |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
61 } |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
62 |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
63 GangWorker* WorkGang::allocate_worker(uint which) { |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
64 GangWorker* new_worker = new GangWorker(this, which); |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
65 return new_worker; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
66 } |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
67 |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
68 // The current implementation will exit if the allocation |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
69 // of any worker fails. Still, return a boolean so that |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
70 // a future implementation can possibly do a partial |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
71 // initialization of the workers and report such to the |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
72 // caller. |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
73 bool WorkGang::initialize_workers() { |
342 | 74 |
0 | 75 if (TraceWorkGang) { |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
76 tty->print_cr("Constructing work gang %s with %d threads", |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
77 name(), |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
78 total_workers()); |
0 | 79 } |
6197 | 80 _gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, total_workers(), mtInternal); |
342 | 81 if (gang_workers() == NULL) { |
82 vm_exit_out_of_memory(0, "Cannot create GangWorker array."); | |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
83 return false; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
84 } |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
85 os::ThreadType worker_type; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
86 if (are_ConcurrentGC_threads()) { |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
87 worker_type = os::cgc_thread; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
88 } else { |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
89 worker_type = os::pgc_thread; |
342 | 90 } |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
91 for (uint worker = 0; worker < total_workers(); worker += 1) { |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
92 GangWorker* new_worker = allocate_worker(worker); |
0 | 93 assert(new_worker != NULL, "Failed to allocate GangWorker"); |
94 _gang_workers[worker] = new_worker; | |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
95 if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) { |
0 | 96 vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources."); |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
97 return false; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
98 } |
0 | 99 if (!DisableStartThread) { |
100 os::start_thread(new_worker); | |
101 } | |
102 } | |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
103 return true; |
0 | 104 } |
105 | |
106 AbstractWorkGang::~AbstractWorkGang() { | |
107 if (TraceWorkGang) { | |
108 tty->print_cr("Destructing work gang %s", name()); | |
109 } | |
110 stop(); // stop all the workers | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
111 for (uint worker = 0; worker < total_workers(); worker += 1) { |
0 | 112 delete gang_worker(worker); |
113 } | |
114 delete gang_workers(); | |
115 delete monitor(); | |
116 } | |
117 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
118 GangWorker* AbstractWorkGang::gang_worker(uint i) const { |
0 | 119 // Array index bounds checking. |
120 GangWorker* result = NULL; | |
121 assert(gang_workers() != NULL, "No workers for indexing"); | |
122 assert(((i >= 0) && (i < total_workers())), "Worker index out of bounds"); | |
123 result = _gang_workers[i]; | |
124 assert(result != NULL, "Indexing to null worker"); | |
125 return result; | |
126 } | |
127 | |
128 void WorkGang::run_task(AbstractGangTask* task) { | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
129 run_task(task, total_workers()); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
130 } |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
131 |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
132 void WorkGang::run_task(AbstractGangTask* task, uint no_of_parallel_workers) { |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
133 task->set_for_termination(no_of_parallel_workers); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
134 |
0 | 135 // This thread is executed by the VM thread which does not block |
136 // on ordinary MutexLocker's. | |
137 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
138 if (TraceWorkGang) { | |
139 tty->print_cr("Running work gang %s task %s", name(), task->name()); | |
140 } | |
141 // Tell all the workers to run a task. | |
142 assert(task != NULL, "Running a null task"); | |
143 // Initialize. | |
144 _task = task; | |
145 _sequence_number += 1; | |
146 _started_workers = 0; | |
147 _finished_workers = 0; | |
148 // Tell the workers to get to work. | |
149 monitor()->notify_all(); | |
150 // Wait for them to be finished | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
151 while (finished_workers() < no_of_parallel_workers) { |
0 | 152 if (TraceWorkGang) { |
153 tty->print_cr("Waiting in work gang %s: %d/%d finished sequence %d", | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
154 name(), finished_workers(), no_of_parallel_workers, |
0 | 155 _sequence_number); |
156 } | |
157 monitor()->wait(/* no_safepoint_check */ true); | |
158 } | |
159 _task = NULL; | |
160 if (TraceWorkGang) { | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
161 tty->print_cr("\nFinished work gang %s: %d/%d sequence %d", |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
162 name(), finished_workers(), no_of_parallel_workers, |
0 | 163 _sequence_number); |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
164 Thread* me = Thread::current(); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
165 tty->print_cr(" T: 0x%x VM_thread: %d", me, me->is_VM_thread()); |
2369
92da084fefc9
6668573: CMS: reference processing crash if ParallelCMSThreads > ParallelGCThreads
ysr
parents:
1972
diff
changeset
|
166 } |
0 | 167 } |
168 | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
169 void FlexibleWorkGang::run_task(AbstractGangTask* task) { |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
170 // If active_workers() is passed, _finished_workers |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
171 // must only be incremented for workers that find non_null |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
172 // work (as opposed to all those that just check that the |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
173 // task is not null). |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
174 WorkGang::run_task(task, (uint) active_workers()); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
175 } |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
176 |
0 | 177 void AbstractWorkGang::stop() { |
178 // Tell all workers to terminate, then wait for them to become inactive. | |
179 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
180 if (TraceWorkGang) { | |
181 tty->print_cr("Stopping work gang %s task %s", name(), task()->name()); | |
182 } | |
183 _task = NULL; | |
184 _terminate = true; | |
185 monitor()->notify_all(); | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
186 while (finished_workers() < active_workers()) { |
0 | 187 if (TraceWorkGang) { |
188 tty->print_cr("Waiting in work gang %s: %d/%d finished", | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
189 name(), finished_workers(), active_workers()); |
0 | 190 } |
191 monitor()->wait(/* no_safepoint_check */ true); | |
192 } | |
193 } | |
194 | |
195 void AbstractWorkGang::internal_worker_poll(WorkData* data) const { | |
196 assert(monitor()->owned_by_self(), "worker_poll is an internal method"); | |
197 assert(data != NULL, "worker data is null"); | |
198 data->set_terminate(terminate()); | |
199 data->set_task(task()); | |
200 data->set_sequence_number(sequence_number()); | |
201 } | |
202 | |
203 void AbstractWorkGang::internal_note_start() { | |
204 assert(monitor()->owned_by_self(), "note_finish is an internal method"); | |
205 _started_workers += 1; | |
206 } | |
207 | |
208 void AbstractWorkGang::internal_note_finish() { | |
209 assert(monitor()->owned_by_self(), "note_finish is an internal method"); | |
210 _finished_workers += 1; | |
211 } | |
212 | |
213 void AbstractWorkGang::print_worker_threads_on(outputStream* st) const { | |
214 uint num_thr = total_workers(); | |
215 for (uint i = 0; i < num_thr; i++) { | |
216 gang_worker(i)->print_on(st); | |
217 st->cr(); | |
218 } | |
219 } | |
220 | |
221 void AbstractWorkGang::threads_do(ThreadClosure* tc) const { | |
222 assert(tc != NULL, "Null ThreadClosure"); | |
223 uint num_thr = total_workers(); | |
224 for (uint i = 0; i < num_thr; i++) { | |
225 tc->do_thread(gang_worker(i)); | |
226 } | |
227 } | |
228 | |
229 // GangWorker methods. | |
230 | |
231 GangWorker::GangWorker(AbstractWorkGang* gang, uint id) { | |
232 _gang = gang; | |
233 set_id(id); | |
234 set_name("Gang worker#%d (%s)", id, gang->name()); | |
235 } | |
236 | |
237 void GangWorker::run() { | |
238 initialize(); | |
239 loop(); | |
240 } | |
241 | |
242 void GangWorker::initialize() { | |
243 this->initialize_thread_local_storage(); | |
6197 | 244 this->record_stack_base_and_size(); |
0 | 245 assert(_gang != NULL, "No gang to run in"); |
246 os::set_priority(this, NearMaxPriority); | |
247 if (TraceWorkGang) { | |
248 tty->print_cr("Running gang worker for gang %s id %d", | |
249 gang()->name(), id()); | |
250 } | |
251 // The VM thread should not execute here because MutexLocker's are used | |
252 // as (opposed to MutexLockerEx's). | |
253 assert(!Thread::current()->is_VM_thread(), "VM thread should not be part" | |
254 " of a work gang"); | |
255 } | |
256 | |
257 void GangWorker::loop() { | |
258 int previous_sequence_number = 0; | |
259 Monitor* gang_monitor = gang()->monitor(); | |
260 for ( ; /* !terminate() */; ) { | |
261 WorkData data; | |
262 int part; // Initialized below. | |
263 { | |
264 // Grab the gang mutex. | |
265 MutexLocker ml(gang_monitor); | |
266 // Wait for something to do. | |
267 // Polling outside the while { wait } avoids missed notifies | |
268 // in the outer loop. | |
269 gang()->internal_worker_poll(&data); | |
270 if (TraceWorkGang) { | |
271 tty->print("Polled outside for work in gang %s worker %d", | |
272 gang()->name(), id()); | |
273 tty->print(" terminate: %s", | |
274 data.terminate() ? "true" : "false"); | |
275 tty->print(" sequence: %d (prev: %d)", | |
276 data.sequence_number(), previous_sequence_number); | |
277 if (data.task() != NULL) { | |
278 tty->print(" task: %s", data.task()->name()); | |
279 } else { | |
280 tty->print(" task: NULL"); | |
281 } | |
282 tty->cr(); | |
283 } | |
284 for ( ; /* break or return */; ) { | |
285 // Terminate if requested. | |
286 if (data.terminate()) { | |
287 gang()->internal_note_finish(); | |
288 gang_monitor->notify_all(); | |
289 return; | |
290 } | |
291 // Check for new work. | |
292 if ((data.task() != NULL) && | |
293 (data.sequence_number() != previous_sequence_number)) { | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
294 if (gang()->needs_more_workers()) { |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
295 gang()->internal_note_start(); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
296 gang_monitor->notify_all(); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
297 part = gang()->started_workers() - 1; |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
298 break; |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
299 } |
0 | 300 } |
301 // Nothing to do. | |
302 gang_monitor->wait(/* no_safepoint_check */ true); | |
303 gang()->internal_worker_poll(&data); | |
304 if (TraceWorkGang) { | |
305 tty->print("Polled inside for work in gang %s worker %d", | |
306 gang()->name(), id()); | |
307 tty->print(" terminate: %s", | |
308 data.terminate() ? "true" : "false"); | |
309 tty->print(" sequence: %d (prev: %d)", | |
310 data.sequence_number(), previous_sequence_number); | |
311 if (data.task() != NULL) { | |
312 tty->print(" task: %s", data.task()->name()); | |
313 } else { | |
314 tty->print(" task: NULL"); | |
315 } | |
316 tty->cr(); | |
317 } | |
318 } | |
319 // Drop gang mutex. | |
320 } | |
321 if (TraceWorkGang) { | |
322 tty->print("Work for work gang %s id %d task %s part %d", | |
323 gang()->name(), id(), data.task()->name(), part); | |
324 } | |
325 assert(data.task() != NULL, "Got null task"); | |
326 data.task()->work(part); | |
327 { | |
328 if (TraceWorkGang) { | |
329 tty->print("Finish for work gang %s id %d task %s part %d", | |
330 gang()->name(), id(), data.task()->name(), part); | |
331 } | |
332 // Grab the gang mutex. | |
333 MutexLocker ml(gang_monitor); | |
334 gang()->internal_note_finish(); | |
335 // Tell the gang you are done. | |
336 gang_monitor->notify_all(); | |
337 // Drop the gang mutex. | |
338 } | |
339 previous_sequence_number = data.sequence_number(); | |
340 } | |
341 } | |
342 | |
343 bool GangWorker::is_GC_task_thread() const { | |
342 | 344 return gang()->are_GC_task_threads(); |
345 } | |
346 | |
347 bool GangWorker::is_ConcurrentGC_thread() const { | |
348 return gang()->are_ConcurrentGC_threads(); | |
0 | 349 } |
350 | |
351 void GangWorker::print_on(outputStream* st) const { | |
352 st->print("\"%s\" ", name()); | |
353 Thread::print_on(st); | |
354 st->cr(); | |
355 } | |
356 | |
357 // Printing methods | |
358 | |
359 const char* AbstractWorkGang::name() const { | |
360 return _name; | |
361 } | |
362 | |
363 #ifndef PRODUCT | |
364 | |
365 const char* AbstractGangTask::name() const { | |
366 return _name; | |
367 } | |
368 | |
369 #endif /* PRODUCT */ | |
370 | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
371 // FlexibleWorkGang |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
372 |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
373 |
0 | 374 // *** WorkGangBarrierSync |
375 | |
376 WorkGangBarrierSync::WorkGangBarrierSync() | |
377 : _monitor(Mutex::safepoint, "work gang barrier sync", true), | |
342 | 378 _n_workers(0), _n_completed(0), _should_reset(false) { |
0 | 379 } |
380 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
381 WorkGangBarrierSync::WorkGangBarrierSync(uint n_workers, const char* name) |
0 | 382 : _monitor(Mutex::safepoint, name, true), |
342 | 383 _n_workers(n_workers), _n_completed(0), _should_reset(false) { |
0 | 384 } |
385 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
386 void WorkGangBarrierSync::set_n_workers(uint n_workers) { |
0 | 387 _n_workers = n_workers; |
388 _n_completed = 0; | |
342 | 389 _should_reset = false; |
0 | 390 } |
391 | |
392 void WorkGangBarrierSync::enter() { | |
393 MutexLockerEx x(monitor(), Mutex::_no_safepoint_check_flag); | |
342 | 394 if (should_reset()) { |
395 // The should_reset() was set and we are the first worker to enter | |
396 // the sync barrier. We will zero the n_completed() count which | |
397 // effectively resets the barrier. | |
398 zero_completed(); | |
399 set_should_reset(false); | |
400 } | |
0 | 401 inc_completed(); |
402 if (n_completed() == n_workers()) { | |
342 | 403 // At this point we would like to reset the barrier to be ready in |
404 // case it is used again. However, we cannot set n_completed() to | |
405 // 0, even after the notify_all(), given that some other workers | |
406 // might still be waiting for n_completed() to become == | |
407 // n_workers(). So, if we set n_completed() to 0, those workers | |
408 // will get stuck (as they will wake up, see that n_completed() != | |
409 // n_workers() and go back to sleep). Instead, we raise the | |
410 // should_reset() flag and the barrier will be reset the first | |
411 // time a worker enters it again. | |
412 set_should_reset(true); | |
0 | 413 monitor()->notify_all(); |
342 | 414 } else { |
0 | 415 while (n_completed() != n_workers()) { |
416 monitor()->wait(/* no_safepoint_check */ true); | |
417 } | |
418 } | |
419 } | |
420 | |
421 // SubTasksDone functions. | |
422 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
423 SubTasksDone::SubTasksDone(uint n) : |
0 | 424 _n_tasks(n), _n_threads(1), _tasks(NULL) { |
6197 | 425 _tasks = NEW_C_HEAP_ARRAY(uint, n, mtInternal); |
0 | 426 guarantee(_tasks != NULL, "alloc failure"); |
427 clear(); | |
428 } | |
429 | |
430 bool SubTasksDone::valid() { | |
431 return _tasks != NULL; | |
432 } | |
433 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
434 void SubTasksDone::set_n_threads(uint t) { |
0 | 435 assert(_claimed == 0 || _threads_completed == _n_threads, |
436 "should not be called while tasks are being processed!"); | |
437 _n_threads = (t == 0 ? 1 : t); | |
438 } | |
439 | |
440 void SubTasksDone::clear() { | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
441 for (uint i = 0; i < _n_tasks; i++) { |
0 | 442 _tasks[i] = 0; |
443 } | |
444 _threads_completed = 0; | |
445 #ifdef ASSERT | |
446 _claimed = 0; | |
447 #endif | |
448 } | |
449 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
450 bool SubTasksDone::is_task_claimed(uint t) { |
0 | 451 assert(0 <= t && t < _n_tasks, "bad task id."); |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
452 uint old = _tasks[t]; |
0 | 453 if (old == 0) { |
454 old = Atomic::cmpxchg(1, &_tasks[t], 0); | |
455 } | |
456 assert(_tasks[t] == 1, "What else?"); | |
457 bool res = old != 0; | |
458 #ifdef ASSERT | |
459 if (!res) { | |
460 assert(_claimed < _n_tasks, "Too many tasks claimed; missing clear?"); | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
461 Atomic::inc((volatile jint*) &_claimed); |
0 | 462 } |
463 #endif | |
464 return res; | |
465 } | |
466 | |
467 void SubTasksDone::all_tasks_completed() { | |
468 jint observed = _threads_completed; | |
469 jint old; | |
470 do { | |
471 old = observed; | |
472 observed = Atomic::cmpxchg(old+1, &_threads_completed, old); | |
473 } while (observed != old); | |
474 // If this was the last thread checking in, clear the tasks. | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
475 if (observed+1 == (jint)_n_threads) clear(); |
0 | 476 } |
477 | |
478 | |
479 SubTasksDone::~SubTasksDone() { | |
6197 | 480 if (_tasks != NULL) FREE_C_HEAP_ARRAY(jint, _tasks, mtInternal); |
0 | 481 } |
482 | |
483 // *** SequentialSubTasksDone | |
484 | |
485 void SequentialSubTasksDone::clear() { | |
486 _n_tasks = _n_claimed = 0; | |
487 _n_threads = _n_completed = 0; | |
488 } | |
489 | |
490 bool SequentialSubTasksDone::valid() { | |
491 return _n_threads > 0; | |
492 } | |
493 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
494 bool SequentialSubTasksDone::is_task_claimed(uint& t) { |
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
495 uint* n_claimed_ptr = &_n_claimed; |
0 | 496 t = *n_claimed_ptr; |
497 while (t < _n_tasks) { | |
498 jint res = Atomic::cmpxchg(t+1, n_claimed_ptr, t); | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
499 if (res == (jint)t) { |
0 | 500 return false; |
501 } | |
502 t = *n_claimed_ptr; | |
503 } | |
504 return true; | |
505 } | |
506 | |
507 bool SequentialSubTasksDone::all_tasks_completed() { | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
508 uint* n_completed_ptr = &_n_completed; |
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
509 uint complete = *n_completed_ptr; |
0 | 510 while (true) { |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
511 uint res = Atomic::cmpxchg(complete+1, n_completed_ptr, complete); |
0 | 512 if (res == complete) { |
513 break; | |
514 } | |
515 complete = res; | |
516 } | |
517 if (complete+1 == _n_threads) { | |
518 clear(); | |
519 return true; | |
520 } | |
521 return false; | |
522 } | |
342 | 523 |
524 bool FreeIdSet::_stat_init = false; | |
525 FreeIdSet* FreeIdSet::_sets[NSets]; | |
526 bool FreeIdSet::_safepoint; | |
527 | |
528 FreeIdSet::FreeIdSet(int sz, Monitor* mon) : | |
529 _sz(sz), _mon(mon), _hd(0), _waiters(0), _index(-1), _claimed(0) | |
530 { | |
531 _ids = new int[sz]; | |
532 for (int i = 0; i < sz; i++) _ids[i] = i+1; | |
533 _ids[sz-1] = end_of_list; // end of list. | |
534 if (_stat_init) { | |
535 for (int j = 0; j < NSets; j++) _sets[j] = NULL; | |
536 _stat_init = true; | |
537 } | |
538 // Add to sets. (This should happen while the system is still single-threaded.) | |
539 for (int j = 0; j < NSets; j++) { | |
540 if (_sets[j] == NULL) { | |
541 _sets[j] = this; | |
542 _index = j; | |
543 break; | |
544 } | |
545 } | |
546 guarantee(_index != -1, "Too many FreeIdSets in use!"); | |
547 } | |
548 | |
549 FreeIdSet::~FreeIdSet() { | |
550 _sets[_index] = NULL; | |
551 } | |
552 | |
553 void FreeIdSet::set_safepoint(bool b) { | |
554 _safepoint = b; | |
555 if (b) { | |
556 for (int j = 0; j < NSets; j++) { | |
557 if (_sets[j] != NULL && _sets[j]->_waiters > 0) { | |
558 Monitor* mon = _sets[j]->_mon; | |
559 mon->lock_without_safepoint_check(); | |
560 mon->notify_all(); | |
561 mon->unlock(); | |
562 } | |
563 } | |
564 } | |
565 } | |
566 | |
567 #define FID_STATS 0 | |
568 | |
569 int FreeIdSet::claim_par_id() { | |
570 #if FID_STATS | |
571 thread_t tslf = thr_self(); | |
572 tty->print("claim_par_id[%d]: sz = %d, claimed = %d\n", tslf, _sz, _claimed); | |
573 #endif | |
574 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); | |
575 while (!_safepoint && _hd == end_of_list) { | |
576 _waiters++; | |
577 #if FID_STATS | |
578 if (_waiters > 5) { | |
579 tty->print("claim_par_id waiting[%d]: %d waiters, %d claimed.\n", | |
580 tslf, _waiters, _claimed); | |
581 } | |
582 #endif | |
583 _mon->wait(Mutex::_no_safepoint_check_flag); | |
584 _waiters--; | |
585 } | |
586 if (_hd == end_of_list) { | |
587 #if FID_STATS | |
588 tty->print("claim_par_id[%d]: returning EOL.\n", tslf); | |
589 #endif | |
590 return -1; | |
591 } else { | |
592 int res = _hd; | |
593 _hd = _ids[res]; | |
594 _ids[res] = claimed; // For debugging. | |
595 _claimed++; | |
596 #if FID_STATS | |
597 tty->print("claim_par_id[%d]: returning %d, claimed = %d.\n", | |
598 tslf, res, _claimed); | |
599 #endif | |
600 return res; | |
601 } | |
602 } | |
603 | |
604 bool FreeIdSet::claim_perm_id(int i) { | |
605 assert(0 <= i && i < _sz, "Out of range."); | |
606 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); | |
607 int prev = end_of_list; | |
608 int cur = _hd; | |
609 while (cur != end_of_list) { | |
610 if (cur == i) { | |
611 if (prev == end_of_list) { | |
612 _hd = _ids[cur]; | |
613 } else { | |
614 _ids[prev] = _ids[cur]; | |
615 } | |
616 _ids[cur] = claimed; | |
617 _claimed++; | |
618 return true; | |
619 } else { | |
620 prev = cur; | |
621 cur = _ids[cur]; | |
622 } | |
623 } | |
624 return false; | |
625 | |
626 } | |
627 | |
628 void FreeIdSet::release_par_id(int id) { | |
629 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); | |
630 assert(_ids[id] == claimed, "Precondition."); | |
631 _ids[id] = _hd; | |
632 _hd = id; | |
633 _claimed--; | |
634 #if FID_STATS | |
635 tty->print("[%d] release_par_id(%d), waiters =%d, claimed = %d.\n", | |
636 thr_self(), id, _waiters, _claimed); | |
637 #endif | |
638 if (_waiters > 0) | |
639 // Notify all would be safer, but this is OK, right? | |
640 _mon->notify_all(); | |
641 } |