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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "gc/shared/workgroup.hpp"
27 #include "memory/allocation.hpp"
28 #include "memory/allocation.inline.hpp"
29 #include "runtime/atomic.inline.hpp"
30 #include "runtime/os.hpp"
31 #include "runtime/thread.inline.hpp"
32 #include "utilities/semaphore.hpp"
33
34 // Definitions of WorkGang methods.
35
36 // The current implementation will exit if the allocation
37 // of any worker fails. Still, return a boolean so that
38 // a future implementation can possibly do a partial
39 // initialization of the workers and report such to the
40 // caller.
41 bool AbstractWorkGang::initialize_workers() {
42
43 if (TraceWorkGang) {
44 tty->print_cr("Constructing work gang %s with %d threads",
45 name(),
46 total_workers());
47 }
48 _workers = NEW_C_HEAP_ARRAY(AbstractGangWorker*, total_workers(), mtInternal);
49 if (_workers == NULL) {
50 vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array.");
51 return false;
52 }
81 assert(result != NULL, "Indexing to null worker");
82 return result;
83 }
84
85 void AbstractWorkGang::print_worker_threads_on(outputStream* st) const {
86 uint workers = total_workers();
87 for (uint i = 0; i < workers; i++) {
88 worker(i)->print_on(st);
89 st->cr();
90 }
91 }
92
93 void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
94 assert(tc != NULL, "Null ThreadClosure");
95 uint workers = total_workers();
96 for (uint i = 0; i < workers; i++) {
97 tc->do_thread(worker(i));
98 }
99 }
100
101 #if IMPLEMENTS_SEMAPHORE_CLASS
102
103 // WorkGang dispatcher implemented with semaphores.
104 //
105 // Semaphores don't require the worker threads to re-claim the lock when they wake up.
106 // This helps lowering the latency when starting and stopping the worker threads.
107 class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
108 // The task currently being dispatched to the GangWorkers.
109 AbstractGangTask* _task;
110
111 volatile uint _started;
112 volatile uint _not_finished;
113
114 // Semaphore used to start the GangWorkers.
115 Semaphore* _start_semaphore;
116 // Semaphore used to notify the coordinator that all workers are done.
117 Semaphore* _end_semaphore;
118
119 public:
120 SemaphoreGangTaskDispatcher(uint workers) :
121 _task(NULL),
122 _started(0),
123 _not_finished(0),
124 // Limit the semaphore value to the number of workers.
125 _start_semaphore(new Semaphore(0, workers)),
126 _end_semaphore(new Semaphore(0, workers))
127 { }
128
129 ~SemaphoreGangTaskDispatcher() {
130 delete _start_semaphore;
131 delete _end_semaphore;
132 }
133
134 void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) {
135 // No workers are allowed to read the state variables until they have been signaled.
136 _task = task;
137 _not_finished = num_workers;
138
139 // Dispatch 'num_workers' number of tasks.
140 _start_semaphore->signal(num_workers);
141
142 // Wait for the last worker to signal the coordinator.
143 _end_semaphore->wait();
144
145 // No workers are allowed to read the state variables after the coordinator has been signaled.
146 _task = NULL;
154
155 uint num_started = (uint) Atomic::add(1, (volatile jint*)&_started);
156
157 // Subtract one to get a zero-indexed worker id.
158 uint worker_id = num_started - 1;
159
160 return WorkData(_task, worker_id);
161 }
162
163 void worker_done_with_task() {
164 // Mark that the worker is done with the task.
165 // The worker is not allowed to read the state variables after this line.
166 uint not_finished = (uint) Atomic::add(-1, (volatile jint*)&_not_finished);
167
168 // The last worker signals to the coordinator that all work is completed.
169 if (not_finished == 0) {
170 _end_semaphore->signal();
171 }
172 }
173 };
174 #endif // IMPLEMENTS_SEMAPHORE_CLASS
175
176 class MutexGangTaskDispatcher : public GangTaskDispatcher {
177 AbstractGangTask* _task;
178
179 volatile uint _started;
180 volatile uint _finished;
181 volatile uint _num_workers;
182
183 Monitor* _monitor;
184
185 public:
186 MutexGangTaskDispatcher()
187 : _task(NULL),
188 _monitor(new Monitor(Monitor::leaf, "WorkGang dispatcher lock", false, Monitor::_safepoint_check_never)),
189 _started(0),
190 _finished(0),
191 _num_workers(0) {}
192
193 ~MutexGangTaskDispatcher() {
194 delete _monitor;
224 _started++;
225
226 // Subtract one to get a zero-indexed worker id.
227 uint worker_id = _started - 1;
228
229 return WorkData(_task, worker_id);
230 }
231
232 void worker_done_with_task() {
233 MonitorLockerEx ml(_monitor, Mutex::_no_safepoint_check_flag);
234
235 _finished++;
236
237 if (_finished == _num_workers) {
238 // This will wake up all workers and not only the coordinator.
239 _monitor->notify_all();
240 }
241 }
242 };
243
244 static GangTaskDispatcher* create_dispatcher(uint workers) {
245 #if IMPLEMENTS_SEMAPHORE_CLASS
246 if (UseSemaphoreGCThreadsSynchronization) {
247 return new SemaphoreGangTaskDispatcher(workers);
248 }
249 #endif
250
251 return new MutexGangTaskDispatcher();
252 }
253
254 WorkGang::WorkGang(const char* name,
255 uint workers,
256 bool are_GC_task_threads,
257 bool are_ConcurrentGC_threads) :
258 AbstractWorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
259 _dispatcher(create_dispatcher(workers))
260 { }
261
262 AbstractGangWorker* WorkGang::allocate_worker(uint worker_id) {
263 return new GangWorker(this, worker_id);
264 }
265
266 void WorkGang::run_task(AbstractGangTask* task) {
267 _dispatcher->coordinator_execute_on_workers(task, active_workers());
268 }
269
270 AbstractGangWorker::AbstractGangWorker(AbstractWorkGang* gang, uint id) {
271 _gang = gang;
272 set_id(id);
273 set_name("%s#%d", gang->name(), id);
274 }
275
276 void AbstractGangWorker::run() {
277 initialize();
278 loop();
279 }
|
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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "gc/shared/workgroup.hpp"
27 #include "memory/allocation.hpp"
28 #include "memory/allocation.inline.hpp"
29 #include "runtime/atomic.inline.hpp"
30 #include "runtime/os.hpp"
31 #include "runtime/semaphore.hpp"
32 #include "runtime/thread.inline.hpp"
33
34 // Definitions of WorkGang methods.
35
36 // The current implementation will exit if the allocation
37 // of any worker fails. Still, return a boolean so that
38 // a future implementation can possibly do a partial
39 // initialization of the workers and report such to the
40 // caller.
41 bool AbstractWorkGang::initialize_workers() {
42
43 if (TraceWorkGang) {
44 tty->print_cr("Constructing work gang %s with %d threads",
45 name(),
46 total_workers());
47 }
48 _workers = NEW_C_HEAP_ARRAY(AbstractGangWorker*, total_workers(), mtInternal);
49 if (_workers == NULL) {
50 vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array.");
51 return false;
52 }
81 assert(result != NULL, "Indexing to null worker");
82 return result;
83 }
84
85 void AbstractWorkGang::print_worker_threads_on(outputStream* st) const {
86 uint workers = total_workers();
87 for (uint i = 0; i < workers; i++) {
88 worker(i)->print_on(st);
89 st->cr();
90 }
91 }
92
93 void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
94 assert(tc != NULL, "Null ThreadClosure");
95 uint workers = total_workers();
96 for (uint i = 0; i < workers; i++) {
97 tc->do_thread(worker(i));
98 }
99 }
100
101 // WorkGang dispatcher implemented with semaphores.
102 //
103 // Semaphores don't require the worker threads to re-claim the lock when they wake up.
104 // This helps lowering the latency when starting and stopping the worker threads.
105 class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
106 // The task currently being dispatched to the GangWorkers.
107 AbstractGangTask* _task;
108
109 volatile uint _started;
110 volatile uint _not_finished;
111
112 // Semaphore used to start the GangWorkers.
113 Semaphore* _start_semaphore;
114 // Semaphore used to notify the coordinator that all workers are done.
115 Semaphore* _end_semaphore;
116
117 public:
118 SemaphoreGangTaskDispatcher() :
119 _task(NULL),
120 _started(0),
121 _not_finished(0),
122 // Limit the semaphore value to the number of workers.
123 _start_semaphore(new Semaphore()),
124 _end_semaphore(new Semaphore())
125 { }
126
127 ~SemaphoreGangTaskDispatcher() {
128 delete _start_semaphore;
129 delete _end_semaphore;
130 }
131
132 void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) {
133 // No workers are allowed to read the state variables until they have been signaled.
134 _task = task;
135 _not_finished = num_workers;
136
137 // Dispatch 'num_workers' number of tasks.
138 _start_semaphore->signal(num_workers);
139
140 // Wait for the last worker to signal the coordinator.
141 _end_semaphore->wait();
142
143 // No workers are allowed to read the state variables after the coordinator has been signaled.
144 _task = NULL;
152
153 uint num_started = (uint) Atomic::add(1, (volatile jint*)&_started);
154
155 // Subtract one to get a zero-indexed worker id.
156 uint worker_id = num_started - 1;
157
158 return WorkData(_task, worker_id);
159 }
160
161 void worker_done_with_task() {
162 // Mark that the worker is done with the task.
163 // The worker is not allowed to read the state variables after this line.
164 uint not_finished = (uint) Atomic::add(-1, (volatile jint*)&_not_finished);
165
166 // The last worker signals to the coordinator that all work is completed.
167 if (not_finished == 0) {
168 _end_semaphore->signal();
169 }
170 }
171 };
172
173 class MutexGangTaskDispatcher : public GangTaskDispatcher {
174 AbstractGangTask* _task;
175
176 volatile uint _started;
177 volatile uint _finished;
178 volatile uint _num_workers;
179
180 Monitor* _monitor;
181
182 public:
183 MutexGangTaskDispatcher()
184 : _task(NULL),
185 _monitor(new Monitor(Monitor::leaf, "WorkGang dispatcher lock", false, Monitor::_safepoint_check_never)),
186 _started(0),
187 _finished(0),
188 _num_workers(0) {}
189
190 ~MutexGangTaskDispatcher() {
191 delete _monitor;
221 _started++;
222
223 // Subtract one to get a zero-indexed worker id.
224 uint worker_id = _started - 1;
225
226 return WorkData(_task, worker_id);
227 }
228
229 void worker_done_with_task() {
230 MonitorLockerEx ml(_monitor, Mutex::_no_safepoint_check_flag);
231
232 _finished++;
233
234 if (_finished == _num_workers) {
235 // This will wake up all workers and not only the coordinator.
236 _monitor->notify_all();
237 }
238 }
239 };
240
241 static GangTaskDispatcher* create_dispatcher() {
242 if (UseSemaphoreGCThreadsSynchronization) {
243 return new SemaphoreGangTaskDispatcher();
244 }
245
246 return new MutexGangTaskDispatcher();
247 }
248
249 WorkGang::WorkGang(const char* name,
250 uint workers,
251 bool are_GC_task_threads,
252 bool are_ConcurrentGC_threads) :
253 AbstractWorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
254 _dispatcher(create_dispatcher())
255 { }
256
257 AbstractGangWorker* WorkGang::allocate_worker(uint worker_id) {
258 return new GangWorker(this, worker_id);
259 }
260
261 void WorkGang::run_task(AbstractGangTask* task) {
262 _dispatcher->coordinator_execute_on_workers(task, active_workers());
263 }
264
265 AbstractGangWorker::AbstractGangWorker(AbstractWorkGang* gang, uint id) {
266 _gang = gang;
267 set_id(id);
268 set_name("%s#%d", gang->name(), id);
269 }
270
271 void AbstractGangWorker::run() {
272 initialize();
273 loop();
274 }
|