src/share/vm/utilities/taskqueue.cpp

Thu, 01 Jul 2010 21:40:45 -0700

author
jcoomes
date
Thu, 01 Jul 2010 21:40:45 -0700
changeset 1993
b2a00dd3117c
parent 1907
c18cbe5936b8
child 2020
a93a9eda13f7
permissions
-rw-r--r--

6957084: simplify TaskQueue overflow handling
Reviewed-by: ysr, jmasa

     1 /*
     2  * Copyright (c) 2001, 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 "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

mercurial