Wed, 03 Jul 2019 20:42:37 +0800
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 | } |