src/share/vm/utilities/taskqueue.cpp

Thu, 27 May 2010 19:08:38 -0700

author
trims
date
Thu, 27 May 2010 19:08:38 -0700
changeset 1907
c18cbe5936b8
parent 1746
2a1472c30599
child 1993
b2a00dd3117c
permissions
-rw-r--r--

6941466: Oracle rebranding changes for Hotspot repositories
Summary: Change all the Sun copyrights to Oracle copyright
Reviewed-by: ohair

     1 /*
     2  * Copyright (c) 2001, 2009, 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 "incls/_precompiled.incl"
    26 # include "incls/_taskqueue.cpp.incl"
    28 #ifdef TRACESPINNING
    29 uint ParallelTaskTerminator::_total_yields = 0;
    30 uint ParallelTaskTerminator::_total_spins = 0;
    31 uint ParallelTaskTerminator::_total_peeks = 0;
    32 #endif
    34 int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
    35   const int a =      16807;
    36   const int m = 2147483647;
    37   const int q =     127773;  /* m div a */
    38   const int r =       2836;  /* m mod a */
    39   assert(sizeof(int) == 4, "I think this relies on that");
    40   int seed = *seed0;
    41   int hi   = seed / q;
    42   int lo   = seed % q;
    43   int test = a * lo - r * hi;
    44   if (test > 0)
    45     seed = test;
    46   else
    47     seed = test + m;
    48   *seed0 = seed;
    49   return seed;
    50 }
    52 ParallelTaskTerminator::
    53 ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set) :
    54   _n_threads(n_threads),
    55   _queue_set(queue_set),
    56   _offered_termination(0) {}
    58 bool ParallelTaskTerminator::peek_in_queue_set() {
    59   return _queue_set->peek();
    60 }
    62 void ParallelTaskTerminator::yield() {
    63   assert(_offered_termination <= _n_threads, "Invariant");
    64   os::yield();
    65 }
    67 void ParallelTaskTerminator::sleep(uint millis) {
    68   assert(_offered_termination <= _n_threads, "Invariant");
    69   os::sleep(Thread::current(), millis, false);
    70 }
    72 bool
    73 ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
    74   assert(_offered_termination < _n_threads, "Invariant");
    75   Atomic::inc(&_offered_termination);
    77   uint yield_count = 0;
    78   // Number of hard spin loops done since last yield
    79   uint hard_spin_count = 0;
    80   // Number of iterations in the hard spin loop.
    81   uint hard_spin_limit = WorkStealingHardSpins;
    83   // If WorkStealingSpinToYieldRatio is 0, no hard spinning is done.
    84   // If it is greater than 0, then start with a small number
    85   // of spins and increase number with each turn at spinning until
    86   // the count of hard spins exceeds WorkStealingSpinToYieldRatio.
    87   // Then do a yield() call and start spinning afresh.
    88   if (WorkStealingSpinToYieldRatio > 0) {
    89     hard_spin_limit = WorkStealingHardSpins >> WorkStealingSpinToYieldRatio;
    90     hard_spin_limit = MAX2(hard_spin_limit, 1U);
    91   }
    92   // Remember the initial spin limit.
    93   uint hard_spin_start = hard_spin_limit;
    95   // Loop waiting for all threads to offer termination or
    96   // more work.
    97   while (true) {
    98     assert(_offered_termination <= _n_threads, "Invariant");
    99     // Are all threads offering termination?
   100     if (_offered_termination == _n_threads) {
   101       return true;
   102     } else {
   103       // Look for more work.
   104       // Periodically sleep() instead of yield() to give threads
   105       // waiting on the cores the chance to grab this code
   106       if (yield_count <= WorkStealingYieldsBeforeSleep) {
   107         // Do a yield or hardspin.  For purposes of deciding whether
   108         // to sleep, count this as a yield.
   109         yield_count++;
   111         // Periodically call yield() instead spinning
   112         // After WorkStealingSpinToYieldRatio spins, do a yield() call
   113         // and reset the counts and starting limit.
   114         if (hard_spin_count > WorkStealingSpinToYieldRatio) {
   115           yield();
   116           hard_spin_count = 0;
   117           hard_spin_limit = hard_spin_start;
   118 #ifdef TRACESPINNING
   119           _total_yields++;
   120 #endif
   121         } else {
   122           // Hard spin this time
   123           // Increase the hard spinning period but only up to a limit.
   124           hard_spin_limit = MIN2(2*hard_spin_limit,
   125                                  (uint) WorkStealingHardSpins);
   126           for (uint j = 0; j < hard_spin_limit; j++) {
   127             SpinPause();
   128           }
   129           hard_spin_count++;
   130 #ifdef TRACESPINNING
   131           _total_spins++;
   132 #endif
   133         }
   134       } else {
   135         if (PrintGCDetails && Verbose) {
   136          gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() "
   137            "thread %d sleeps after %d yields",
   138            Thread::current(), yield_count);
   139         }
   140         yield_count = 0;
   141         // A sleep will cause this processor to seek work on another processor's
   142         // runqueue, if it has nothing else to run (as opposed to the yield
   143         // which may only move the thread to the end of the this processor's
   144         // runqueue).
   145         sleep(WorkStealingSleepMillis);
   146       }
   148 #ifdef TRACESPINNING
   149       _total_peeks++;
   150 #endif
   151       if (peek_in_queue_set() ||
   152           (terminator != NULL && terminator->should_exit_termination())) {
   153         Atomic::dec(&_offered_termination);
   154         assert(_offered_termination < _n_threads, "Invariant");
   155         return false;
   156       }
   157     }
   158   }
   159 }
   161 #ifdef TRACESPINNING
   162 void ParallelTaskTerminator::print_termination_counts() {
   163   gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %lld  "
   164     "Total spins: %lld  Total peeks: %lld",
   165     total_yields(),
   166     total_spins(),
   167     total_peeks());
   168 }
   169 #endif
   171 void ParallelTaskTerminator::reset_for_reuse() {
   172   if (_offered_termination != 0) {
   173     assert(_offered_termination == _n_threads,
   174            "Terminator may still be in use");
   175     _offered_termination = 0;
   176   }
   177 }
   179 #ifdef ASSERT
   180 bool ObjArrayTask::is_valid() const {
   181   return _obj != NULL && _obj->is_objArray() && _index > 0 &&
   182     _index < objArrayOop(_obj)->length();
   183 }
   184 #endif // ASSERT
   186 bool RegionTaskQueueWithOverflow::is_empty() {
   187   return (_region_queue.size() == 0) &&
   188          (_overflow_stack->length() == 0);
   189 }
   191 bool RegionTaskQueueWithOverflow::stealable_is_empty() {
   192   return _region_queue.size() == 0;
   193 }
   195 bool RegionTaskQueueWithOverflow::overflow_is_empty() {
   196   return _overflow_stack->length() == 0;
   197 }
   199 void RegionTaskQueueWithOverflow::initialize() {
   200   _region_queue.initialize();
   201   assert(_overflow_stack == 0, "Creating memory leak");
   202   _overflow_stack =
   203     new (ResourceObj::C_HEAP) GrowableArray<RegionTask>(10, true);
   204 }
   206 void RegionTaskQueueWithOverflow::save(RegionTask t) {
   207   if (TraceRegionTasksQueuing && Verbose) {
   208     gclog_or_tty->print_cr("CTQ: save " PTR_FORMAT, t);
   209   }
   210   if(!_region_queue.push(t)) {
   211     _overflow_stack->push(t);
   212   }
   213 }
   215 // Note that using this method will retrieve all regions
   216 // that have been saved but that it will always check
   217 // the overflow stack.  It may be more efficient to
   218 // check the stealable queue and the overflow stack
   219 // separately.
   220 bool RegionTaskQueueWithOverflow::retrieve(RegionTask& region_task) {
   221   bool result = retrieve_from_overflow(region_task);
   222   if (!result) {
   223     result = retrieve_from_stealable_queue(region_task);
   224   }
   225   if (TraceRegionTasksQueuing && Verbose && result) {
   226     gclog_or_tty->print_cr("  CTQ: retrieve " PTR_FORMAT, result);
   227   }
   228   return result;
   229 }
   231 bool RegionTaskQueueWithOverflow::retrieve_from_stealable_queue(
   232                                    RegionTask& region_task) {
   233   bool result = _region_queue.pop_local(region_task);
   234   if (TraceRegionTasksQueuing && Verbose) {
   235     gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task);
   236   }
   237   return result;
   238 }
   240 bool
   241 RegionTaskQueueWithOverflow::retrieve_from_overflow(RegionTask& region_task) {
   242   bool result;
   243   if (!_overflow_stack->is_empty()) {
   244     region_task = _overflow_stack->pop();
   245     result = true;
   246   } else {
   247     region_task = (RegionTask) NULL;
   248     result = false;
   249   }
   250   if (TraceRegionTasksQueuing && Verbose) {
   251     gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task);
   252   }
   253   return result;
   254 }

mercurial