src/share/vm/utilities/yieldingWorkgroup.cpp

Tue, 08 Aug 2017 15:57:29 +0800

author
aoqi
date
Tue, 08 Aug 2017 15:57:29 +0800
changeset 6876
710a3c8b516e
parent 6198
55fb97c4c58d
parent 0
f90c822e73f8
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 *
aoqi@0 23 */
aoqi@0 24
aoqi@0 25 #include "precompiled.hpp"
aoqi@0 26 #include "utilities/macros.hpp"
aoqi@0 27 #include "utilities/yieldingWorkgroup.hpp"
aoqi@0 28
aoqi@0 29 // Forward declaration of classes declared here.
aoqi@0 30
aoqi@0 31 class GangWorker;
aoqi@0 32 class WorkData;
aoqi@0 33
aoqi@0 34 YieldingFlexibleWorkGang::YieldingFlexibleWorkGang(
aoqi@0 35 const char* name, uint workers, bool are_GC_task_threads) :
aoqi@0 36 FlexibleWorkGang(name, workers, are_GC_task_threads, false),
aoqi@0 37 _yielded_workers(0) {}
aoqi@0 38
aoqi@0 39 GangWorker* YieldingFlexibleWorkGang::allocate_worker(uint which) {
aoqi@0 40 YieldingFlexibleGangWorker* new_member =
aoqi@0 41 new YieldingFlexibleGangWorker(this, which);
aoqi@0 42 return (YieldingFlexibleGangWorker*) new_member;
aoqi@0 43 }
aoqi@0 44
aoqi@0 45 // Run a task; returns when the task is done, or the workers yield,
aoqi@0 46 // or the task is aborted, or the work gang is terminated via stop().
aoqi@0 47 // A task that has been yielded can be continued via this interface
aoqi@0 48 // by using the same task repeatedly as the argument to the call.
aoqi@0 49 // It is expected that the YieldingFlexibleGangTask carries the appropriate
aoqi@0 50 // continuation information used by workers to continue the task
aoqi@0 51 // from its last yield point. Thus, a completed task will return
aoqi@0 52 // immediately with no actual work having been done by the workers.
aoqi@0 53 /////////////////////
aoqi@0 54 // Implementatiuon notes: remove before checking XXX
aoqi@0 55 /*
aoqi@0 56 Each gang is working on a task at a certain time.
aoqi@0 57 Some subset of workers may have yielded and some may
aoqi@0 58 have finished their quota of work. Until this task has
aoqi@0 59 been completed, the workers are bound to that task.
aoqi@0 60 Once the task has been completed, the gang unbounds
aoqi@0 61 itself from the task.
aoqi@0 62
aoqi@0 63 The yielding work gang thus exports two invokation
aoqi@0 64 interfaces: run_task() and continue_task(). The
aoqi@0 65 first is used to initiate a new task and bind it
aoqi@0 66 to the workers; the second is used to continue an
aoqi@0 67 already bound task that has yielded. Upon completion
aoqi@0 68 the binding is released and a new binding may be
aoqi@0 69 created.
aoqi@0 70
aoqi@0 71 The shape of a yielding work gang is as follows:
aoqi@0 72
aoqi@0 73 Overseer invokes run_task(*task).
aoqi@0 74 Lock gang monitor
aoqi@0 75 Check that there is no existing binding for the gang
aoqi@0 76 If so, abort with an error
aoqi@0 77 Else, create a new binding of this gang to the given task
aoqi@0 78 Set number of active workers (as asked)
aoqi@0 79 Notify workers that work is ready to be done
aoqi@0 80 [the requisite # workers would then start up
aoqi@0 81 and do the task]
aoqi@0 82 Wait on the monitor until either
aoqi@0 83 all work is completed or the task has yielded
aoqi@0 84 -- this is normally done through
aoqi@0 85 yielded + completed == active
aoqi@0 86 [completed workers are rest to idle state by overseer?]
aoqi@0 87 return appropriate status to caller
aoqi@0 88
aoqi@0 89 Overseer invokes continue_task(*task),
aoqi@0 90 Lock gang monitor
aoqi@0 91 Check that task is the same as current binding
aoqi@0 92 If not, abort with an error
aoqi@0 93 Else, set the number of active workers as requested?
aoqi@0 94 Notify workers that they can continue from yield points
aoqi@0 95 New workers can also start up as required
aoqi@0 96 while satisfying the constraint that
aoqi@0 97 active + yielded does not exceed required number
aoqi@0 98 Wait (as above).
aoqi@0 99
aoqi@0 100 NOTE: In the above, for simplicity in a first iteration
aoqi@0 101 our gangs will be of fixed population and will not
aoqi@0 102 therefore be flexible work gangs, just yielding work
aoqi@0 103 gangs. Once this works well, we will in a second
aoqi@0 104 iteration.refinement introduce flexibility into
aoqi@0 105 the work gang.
aoqi@0 106
aoqi@0 107 NOTE: we can always create a new gang per each iteration
aoqi@0 108 in order to get the flexibility, but we will for now
aoqi@0 109 desist that simplified route.
aoqi@0 110
aoqi@0 111 */
aoqi@0 112 /////////////////////
aoqi@0 113 void YieldingFlexibleWorkGang::start_task(YieldingFlexibleGangTask* new_task) {
aoqi@0 114 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
aoqi@0 115 assert(task() == NULL, "Gang currently tied to a task");
aoqi@0 116 assert(new_task != NULL, "Null task");
aoqi@0 117 // Bind task to gang
aoqi@0 118 _task = new_task;
aoqi@0 119 new_task->set_gang(this); // Establish 2-way binding to support yielding
aoqi@0 120 _sequence_number++;
aoqi@0 121
aoqi@0 122 uint requested_size = new_task->requested_size();
aoqi@0 123 assert(requested_size >= 0, "Should be non-negative");
aoqi@0 124 if (requested_size != 0) {
aoqi@0 125 _active_workers = MIN2(requested_size, total_workers());
aoqi@0 126 } else {
aoqi@0 127 _active_workers = active_workers();
aoqi@0 128 }
aoqi@0 129 new_task->set_actual_size(_active_workers);
aoqi@0 130 new_task->set_for_termination(_active_workers);
aoqi@0 131
aoqi@0 132 assert(_started_workers == 0, "Tabula rasa non");
aoqi@0 133 assert(_finished_workers == 0, "Tabula rasa non");
aoqi@0 134 assert(_yielded_workers == 0, "Tabula rasa non");
aoqi@0 135 yielding_task()->set_status(ACTIVE);
aoqi@0 136
aoqi@0 137 // Wake up all the workers, the first few will get to work,
aoqi@0 138 // and the rest will go back to sleep
aoqi@0 139 monitor()->notify_all();
aoqi@0 140 wait_for_gang();
aoqi@0 141 }
aoqi@0 142
aoqi@0 143 void YieldingFlexibleWorkGang::wait_for_gang() {
aoqi@0 144
aoqi@0 145 assert(monitor()->owned_by_self(), "Data race");
aoqi@0 146 // Wait for task to complete or yield
aoqi@0 147 for (Status status = yielding_task()->status();
aoqi@0 148 status != COMPLETED && status != YIELDED && status != ABORTED;
aoqi@0 149 status = yielding_task()->status()) {
aoqi@0 150 assert(started_workers() <= active_workers(), "invariant");
aoqi@0 151 assert(finished_workers() <= active_workers(), "invariant");
aoqi@0 152 assert(yielded_workers() <= active_workers(), "invariant");
aoqi@0 153 monitor()->wait(Mutex::_no_safepoint_check_flag);
aoqi@0 154 }
aoqi@0 155 switch (yielding_task()->status()) {
aoqi@0 156 case COMPLETED:
aoqi@0 157 case ABORTED: {
aoqi@0 158 assert(finished_workers() == active_workers(), "Inconsistent status");
aoqi@0 159 assert(yielded_workers() == 0, "Invariant");
aoqi@0 160 reset(); // for next task; gang<->task binding released
aoqi@0 161 break;
aoqi@0 162 }
aoqi@0 163 case YIELDED: {
aoqi@0 164 assert(yielded_workers() > 0, "Invariant");
aoqi@0 165 assert(yielded_workers() + finished_workers() == active_workers(),
aoqi@0 166 "Inconsistent counts");
aoqi@0 167 break;
aoqi@0 168 }
aoqi@0 169 case ACTIVE:
aoqi@0 170 case INACTIVE:
aoqi@0 171 case COMPLETING:
aoqi@0 172 case YIELDING:
aoqi@0 173 case ABORTING:
aoqi@0 174 default:
aoqi@0 175 ShouldNotReachHere();
aoqi@0 176 }
aoqi@0 177 }
aoqi@0 178
aoqi@0 179 void YieldingFlexibleWorkGang::continue_task(
aoqi@0 180 YieldingFlexibleGangTask* gang_task) {
aoqi@0 181
aoqi@0 182 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
aoqi@0 183 assert(task() != NULL && task() == gang_task, "Incorrect usage");
aoqi@0 184 assert(_started_workers == _active_workers, "Precondition");
aoqi@0 185 assert(_yielded_workers > 0 && yielding_task()->status() == YIELDED,
aoqi@0 186 "Else why are we calling continue_task()");
aoqi@0 187 // Restart the yielded gang workers
aoqi@0 188 yielding_task()->set_status(ACTIVE);
aoqi@0 189 monitor()->notify_all();
aoqi@0 190 wait_for_gang();
aoqi@0 191 }
aoqi@0 192
aoqi@0 193 void YieldingFlexibleWorkGang::reset() {
aoqi@0 194 _started_workers = 0;
aoqi@0 195 _finished_workers = 0;
aoqi@0 196 yielding_task()->set_gang(NULL);
aoqi@0 197 _task = NULL; // unbind gang from task
aoqi@0 198 }
aoqi@0 199
aoqi@0 200 void YieldingFlexibleWorkGang::yield() {
aoqi@0 201 assert(task() != NULL, "Inconsistency; should have task binding");
aoqi@0 202 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
aoqi@0 203 assert(yielded_workers() < active_workers(), "Consistency check");
aoqi@0 204 if (yielding_task()->status() == ABORTING) {
aoqi@0 205 // Do not yield; we need to abort as soon as possible
aoqi@0 206 // XXX NOTE: This can cause a performance pathology in the
aoqi@0 207 // current implementation in Mustang, as of today, and
aoqi@0 208 // pre-Mustang in that as soon as an overflow occurs,
aoqi@0 209 // yields will not be honoured. The right way to proceed
aoqi@0 210 // of course is to fix bug # TBF, so that abort's cause
aoqi@0 211 // us to return at each potential yield point.
aoqi@0 212 return;
aoqi@0 213 }
aoqi@0 214 if (++_yielded_workers + finished_workers() == active_workers()) {
aoqi@0 215 yielding_task()->set_status(YIELDED);
aoqi@0 216 monitor()->notify_all();
aoqi@0 217 } else {
aoqi@0 218 yielding_task()->set_status(YIELDING);
aoqi@0 219 }
aoqi@0 220
aoqi@0 221 while (true) {
aoqi@0 222 switch (yielding_task()->status()) {
aoqi@0 223 case YIELDING:
aoqi@0 224 case YIELDED: {
aoqi@0 225 monitor()->wait(Mutex::_no_safepoint_check_flag);
aoqi@0 226 break; // from switch
aoqi@0 227 }
aoqi@0 228 case ACTIVE:
aoqi@0 229 case ABORTING:
aoqi@0 230 case COMPLETING: {
aoqi@0 231 assert(_yielded_workers > 0, "Else why am i here?");
aoqi@0 232 _yielded_workers--;
aoqi@0 233 return;
aoqi@0 234 }
aoqi@0 235 case INACTIVE:
aoqi@0 236 case ABORTED:
aoqi@0 237 case COMPLETED:
aoqi@0 238 default: {
aoqi@0 239 ShouldNotReachHere();
aoqi@0 240 }
aoqi@0 241 }
aoqi@0 242 }
aoqi@0 243 // Only return is from inside switch statement above
aoqi@0 244 ShouldNotReachHere();
aoqi@0 245 }
aoqi@0 246
aoqi@0 247 void YieldingFlexibleWorkGang::abort() {
aoqi@0 248 assert(task() != NULL, "Inconsistency; should have task binding");
aoqi@0 249 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
aoqi@0 250 assert(yielded_workers() < active_workers(), "Consistency check");
aoqi@0 251 #ifndef PRODUCT
aoqi@0 252 switch (yielding_task()->status()) {
aoqi@0 253 // allowed states
aoqi@0 254 case ACTIVE:
aoqi@0 255 case ABORTING:
aoqi@0 256 case COMPLETING:
aoqi@0 257 case YIELDING:
aoqi@0 258 break;
aoqi@0 259 // not allowed states
aoqi@0 260 case INACTIVE:
aoqi@0 261 case ABORTED:
aoqi@0 262 case COMPLETED:
aoqi@0 263 case YIELDED:
aoqi@0 264 default:
aoqi@0 265 ShouldNotReachHere();
aoqi@0 266 }
aoqi@0 267 #endif // !PRODUCT
aoqi@0 268 Status prev_status = yielding_task()->status();
aoqi@0 269 yielding_task()->set_status(ABORTING);
aoqi@0 270 if (prev_status == YIELDING) {
aoqi@0 271 assert(yielded_workers() > 0, "Inconsistency");
aoqi@0 272 // At least one thread has yielded, wake it up
aoqi@0 273 // so it can go back to waiting stations ASAP.
aoqi@0 274 monitor()->notify_all();
aoqi@0 275 }
aoqi@0 276 }
aoqi@0 277
aoqi@0 278 ///////////////////////////////
aoqi@0 279 // YieldingFlexibleGangTask
aoqi@0 280 ///////////////////////////////
aoqi@0 281 void YieldingFlexibleGangTask::yield() {
aoqi@0 282 assert(gang() != NULL, "No gang to signal");
aoqi@0 283 gang()->yield();
aoqi@0 284 }
aoqi@0 285
aoqi@0 286 void YieldingFlexibleGangTask::abort() {
aoqi@0 287 assert(gang() != NULL, "No gang to signal");
aoqi@0 288 gang()->abort();
aoqi@0 289 }
aoqi@0 290
aoqi@0 291 ///////////////////////////////
aoqi@0 292 // YieldingFlexibleGangWorker
aoqi@0 293 ///////////////////////////////
aoqi@0 294 void YieldingFlexibleGangWorker::loop() {
aoqi@0 295 int previous_sequence_number = 0;
aoqi@0 296 Monitor* gang_monitor = gang()->monitor();
aoqi@0 297 MutexLockerEx ml(gang_monitor, Mutex::_no_safepoint_check_flag);
aoqi@0 298 WorkData data;
aoqi@0 299 int id;
aoqi@0 300 while (true) {
aoqi@0 301 // Check if there is work to do or if we have been asked
aoqi@0 302 // to terminate
aoqi@0 303 gang()->internal_worker_poll(&data);
aoqi@0 304 if (data.terminate()) {
aoqi@0 305 // We have been asked to terminate.
aoqi@0 306 assert(gang()->task() == NULL, "No task binding");
aoqi@0 307 // set_status(TERMINATED);
aoqi@0 308 return;
aoqi@0 309 } else if (data.task() != NULL &&
aoqi@0 310 data.sequence_number() != previous_sequence_number) {
aoqi@0 311 // There is work to be done.
aoqi@0 312 // First check if we need to become active or if there
aoqi@0 313 // are already the requisite number of workers
aoqi@0 314 if (gang()->started_workers() == yf_gang()->active_workers()) {
aoqi@0 315 // There are already enough workers, we do not need to
aoqi@0 316 // to run; fall through and wait on monitor.
aoqi@0 317 } else {
aoqi@0 318 // We need to pitch in and do the work.
aoqi@0 319 assert(gang()->started_workers() < yf_gang()->active_workers(),
aoqi@0 320 "Unexpected state");
aoqi@0 321 id = gang()->started_workers();
aoqi@0 322 gang()->internal_note_start();
aoqi@0 323 // Now, release the gang mutex and do the work.
aoqi@0 324 {
aoqi@0 325 MutexUnlockerEx mul(gang_monitor, Mutex::_no_safepoint_check_flag);
aoqi@0 326 data.task()->work(id); // This might include yielding
aoqi@0 327 }
aoqi@0 328 // Reacquire monitor and note completion of this worker
aoqi@0 329 gang()->internal_note_finish();
aoqi@0 330 // Update status of task based on whether all workers have
aoqi@0 331 // finished or some have yielded
aoqi@0 332 assert(data.task() == gang()->task(), "Confused task binding");
aoqi@0 333 if (gang()->finished_workers() == yf_gang()->active_workers()) {
aoqi@0 334 switch (data.yf_task()->status()) {
aoqi@0 335 case ABORTING: {
aoqi@0 336 data.yf_task()->set_status(ABORTED);
aoqi@0 337 break;
aoqi@0 338 }
aoqi@0 339 case ACTIVE:
aoqi@0 340 case COMPLETING: {
aoqi@0 341 data.yf_task()->set_status(COMPLETED);
aoqi@0 342 break;
aoqi@0 343 }
aoqi@0 344 default:
aoqi@0 345 ShouldNotReachHere();
aoqi@0 346 }
aoqi@0 347 gang_monitor->notify_all(); // Notify overseer
aoqi@0 348 } else { // at least one worker is still working or yielded
aoqi@0 349 assert(gang()->finished_workers() < yf_gang()->active_workers(),
aoqi@0 350 "Counts inconsistent");
aoqi@0 351 switch (data.yf_task()->status()) {
aoqi@0 352 case ACTIVE: {
aoqi@0 353 // first, but not only thread to complete
aoqi@0 354 data.yf_task()->set_status(COMPLETING);
aoqi@0 355 break;
aoqi@0 356 }
aoqi@0 357 case YIELDING: {
aoqi@0 358 if (gang()->finished_workers() + yf_gang()->yielded_workers()
aoqi@0 359 == yf_gang()->active_workers()) {
aoqi@0 360 data.yf_task()->set_status(YIELDED);
aoqi@0 361 gang_monitor->notify_all(); // notify overseer
aoqi@0 362 }
aoqi@0 363 break;
aoqi@0 364 }
aoqi@0 365 case ABORTING:
aoqi@0 366 case COMPLETING: {
aoqi@0 367 break; // nothing to do
aoqi@0 368 }
aoqi@0 369 default: // everything else: INACTIVE, YIELDED, ABORTED, COMPLETED
aoqi@0 370 ShouldNotReachHere();
aoqi@0 371 }
aoqi@0 372 }
aoqi@0 373 }
aoqi@0 374 }
aoqi@0 375 // Remember the sequence number
aoqi@0 376 previous_sequence_number = data.sequence_number();
aoqi@0 377 // Wait for more work
aoqi@0 378 gang_monitor->wait(Mutex::_no_safepoint_check_flag);
aoqi@0 379 }
aoqi@0 380 }

mercurial