src/share/vm/utilities/yieldingWorkgroup.cpp

Wed, 14 Dec 2011 13:34:57 -0800

author
jmasa
date
Wed, 14 Dec 2011 13:34:57 -0800
changeset 3357
441e946dc1af
parent 3294
bca17e38de00
child 4542
db9981fd3124
permissions
-rw-r--r--

7121618: Change type of number of GC workers to unsigned int.
Summary: Change variables representing the number of GC workers to uint from int and size_t. Change the parameter in work(int i) to work(uint worker_id).
Reviewed-by: brutisso, tonyp

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

mercurial