src/share/vm/utilities/yieldingWorkgroup.cpp

Thu, 14 Feb 2013 11:07:24 -0500

author
jprovino
date
Thu, 14 Feb 2013 11:07:24 -0500
changeset 4626
cf9a2071eeac
parent 4542
db9981fd3124
child 6198
55fb97c4c58d
permissions
-rw-r--r--

8006878: Some non-existent GC source files are in the minimalVM exclude list.
Summary: cmsPermGen.cpp, psPermGen.cpp have been removed. yieldWorkingGroup.cpp typo is fixed. immutableSpace.cpp was in the list twice.
Reviewed-by: dholmes, jmasa

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

mercurial