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  */
  24 
  25 #include "precompiled.hpp"
  26 #include "oops/oop.inline.hpp"
  27 #include "runtime/os.hpp"
  28 #include "utilities/debug.hpp"
  29 #include "utilities/taskqueue.hpp"
  30 #ifdef TARGET_OS_FAMILY_linux
  31 # include "thread_linux.inline.hpp"
  32 #endif
  33 #ifdef TARGET_OS_FAMILY_solaris
  34 # include "thread_solaris.inline.hpp"
  35 #endif
  36 #ifdef TARGET_OS_FAMILY_windows
  37 # include "thread_windows.inline.hpp"
  38 #endif
  39 
  40 #ifdef TRACESPINNING
  41 uint ParallelTaskTerminator::_total_yields = 0;
  42 uint ParallelTaskTerminator::_total_spins = 0;
  43 uint ParallelTaskTerminator::_total_peeks = 0;
  44 #endif
  45 
  46 #if TASKQUEUE_STATS
  47 const char * const TaskQueueStats::_names[last_stat_id] = {
  48   "qpush", "qpop", "qpop-s", "qattempt", "qsteal", "opush", "omax"
  49 };
  50 
  51 TaskQueueStats & TaskQueueStats::operator +=(const TaskQueueStats & addend)
  52 {
  53   for (unsigned int i = 0; i < last_stat_id; ++i) {
  54     _stats[i] += addend._stats[i];
  55   }
  56   return *this;
  57 }
  58 
  59 void TaskQueueStats::print_header(unsigned int line, outputStream* const stream,
  60                                   unsigned int width)
  61 {
  62   // Use a width w: 1 <= w <= max_width
  63   const unsigned int max_width = 40;
  64   const unsigned int w = MAX2(MIN2(width, max_width), 1U);
  65 
  66   if (line == 0) { // spaces equal in width to the header
  67     const unsigned int hdr_width = w * last_stat_id + last_stat_id - 1;
  68     stream->print("%*s", hdr_width, " ");
  69   } else if (line == 1) { // labels
  70     stream->print("%*s", w, _names[0]);
  71     for (unsigned int i = 1; i < last_stat_id; ++i) {
  72       stream->print(" %*s", w, _names[i]);
  73     }
  74   } else if (line == 2) { // dashed lines
  75     char dashes[max_width + 1];
  76     memset(dashes, '-', w);
  77     dashes[w] = '\0';
  78     stream->print("%s", dashes);
  79     for (unsigned int i = 1; i < last_stat_id; ++i) {
  80       stream->print(" %s", dashes);
  81     }
  82   }
  83 }
  84 
  85 void TaskQueueStats::print(outputStream* stream, unsigned int width) const
  86 {
  87   #define FMT SIZE_FORMAT_W(*)
  88   stream->print(FMT, width, _stats[0]);
  89   for (unsigned int i = 1; i < last_stat_id; ++i) {
  90     stream->print(" " FMT, width, _stats[i]);
  91   }
  92   #undef FMT
  93 }
  94 
  95 #ifdef ASSERT
  96 // Invariants which should hold after a TaskQueue has been emptied and is
  97 // quiescent; they do not hold at arbitrary times.
  98 void TaskQueueStats::verify() const
  99 {
 100   assert(get(push) == get(pop) + get(steal),
 101          err_msg("push=" SIZE_FORMAT " pop=" SIZE_FORMAT " steal=" SIZE_FORMAT,
 102                  get(push), get(pop), get(steal)));
 103   assert(get(pop_slow) <= get(pop),
 104          err_msg("pop_slow=" SIZE_FORMAT " pop=" SIZE_FORMAT,
 105                  get(pop_slow), get(pop)));
 106   assert(get(steal) <= get(steal_attempt),
 107          err_msg("steal=" SIZE_FORMAT " steal_attempt=" SIZE_FORMAT,
 108                  get(steal), get(steal_attempt)));
 109   assert(get(overflow) == 0 || get(push) != 0,
 110          err_msg("overflow=" SIZE_FORMAT " push=" SIZE_FORMAT,
 111                  get(overflow), get(push)));
 112   assert(get(overflow_max_len) == 0 || get(overflow) != 0,
 113          err_msg("overflow_max_len=" SIZE_FORMAT " overflow=" SIZE_FORMAT,
 114                  get(overflow_max_len), get(overflow)));
 115 }
 116 #endif // ASSERT
 117 #endif // TASKQUEUE_STATS
 118 
 119 int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
 120   const int a =      16807;
 121   const int m = 2147483647;
 122   const int q =     127773;  /* m div a */
 123   const int r =       2836;  /* m mod a */
 124   assert(sizeof(int) == 4, "I think this relies on that");
 125   int seed = *seed0;
 126   int hi   = seed / q;
 127   int lo   = seed % q;
 128   int test = a * lo - r * hi;
 129   if (test > 0)
 130     seed = test;
 131   else
 132     seed = test + m;
 133   *seed0 = seed;
 134   return seed;
 135 }
 136 
 137 ParallelTaskTerminator::
 138 ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set) :
 139   _n_threads(n_threads),
 140   _queue_set(queue_set),
 141   _offered_termination(0) {}
 142 
 143 bool ParallelTaskTerminator::peek_in_queue_set() {
 144   return _queue_set->peek();
 145 }
 146 
 147 void ParallelTaskTerminator::yield() {
 148   assert(_offered_termination <= _n_threads, "Invariant");
 149   os::yield();
 150 }
 151 
 152 void ParallelTaskTerminator::sleep(uint millis) {
 153   assert(_offered_termination <= _n_threads, "Invariant");
 154   os::sleep(Thread::current(), millis, false);
 155 }
 156 
 157 bool
 158 ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
 159   assert(_offered_termination < _n_threads, "Invariant");
 160   Atomic::inc(&_offered_termination);
 161 
 162   uint yield_count = 0;
 163   // Number of hard spin loops done since last yield
 164   uint hard_spin_count = 0;
 165   // Number of iterations in the hard spin loop.
 166   uint hard_spin_limit = WorkStealingHardSpins;
 167 
 168   // If WorkStealingSpinToYieldRatio is 0, no hard spinning is done.
 169   // If it is greater than 0, then start with a small number
 170   // of spins and increase number with each turn at spinning until
 171   // the count of hard spins exceeds WorkStealingSpinToYieldRatio.
 172   // Then do a yield() call and start spinning afresh.
 173   if (WorkStealingSpinToYieldRatio > 0) {
 174     hard_spin_limit = WorkStealingHardSpins >> WorkStealingSpinToYieldRatio;
 175     hard_spin_limit = MAX2(hard_spin_limit, 1U);
 176   }
 177   // Remember the initial spin limit.
 178   uint hard_spin_start = hard_spin_limit;
 179 
 180   // Loop waiting for all threads to offer termination or
 181   // more work.
 182   while (true) {
 183     assert(_offered_termination <= _n_threads, "Invariant");
 184     // Are all threads offering termination?
 185     if (_offered_termination == _n_threads) {
 186       return true;
 187     } else {
 188       // Look for more work.
 189       // Periodically sleep() instead of yield() to give threads
 190       // waiting on the cores the chance to grab this code
 191       if (yield_count <= WorkStealingYieldsBeforeSleep) {
 192         // Do a yield or hardspin.  For purposes of deciding whether
 193         // to sleep, count this as a yield.
 194         yield_count++;
 195 
 196         // Periodically call yield() instead spinning
 197         // After WorkStealingSpinToYieldRatio spins, do a yield() call
 198         // and reset the counts and starting limit.
 199         if (hard_spin_count > WorkStealingSpinToYieldRatio) {
 200           yield();
 201           hard_spin_count = 0;
 202           hard_spin_limit = hard_spin_start;
 203 #ifdef TRACESPINNING
 204           _total_yields++;
 205 #endif
 206         } else {
 207           // Hard spin this time
 208           // Increase the hard spinning period but only up to a limit.
 209           hard_spin_limit = MIN2(2*hard_spin_limit,
 210                                  (uint) WorkStealingHardSpins);
 211           for (uint j = 0; j < hard_spin_limit; j++) {
 212             SpinPause();
 213           }
 214           hard_spin_count++;
 215 #ifdef TRACESPINNING
 216           _total_spins++;
 217 #endif
 218         }
 219       } else {
 220         if (PrintGCDetails && Verbose) {
 221          gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() "
 222            "thread %d sleeps after %d yields",
 223            Thread::current(), yield_count);
 224         }
 225         yield_count = 0;
 226         // A sleep will cause this processor to seek work on another processor's
 227         // runqueue, if it has nothing else to run (as opposed to the yield
 228         // which may only move the thread to the end of the this processor's
 229         // runqueue).
 230         sleep(WorkStealingSleepMillis);
 231       }
 232 
 233 #ifdef TRACESPINNING
 234       _total_peeks++;
 235 #endif
 236       if (peek_in_queue_set() ||
 237           (terminator != NULL && terminator->should_exit_termination())) {
 238         Atomic::dec(&_offered_termination);
 239         assert(_offered_termination < _n_threads, "Invariant");
 240         return false;
 241       }
 242     }
 243   }
 244 }
 245 
 246 #ifdef TRACESPINNING
 247 void ParallelTaskTerminator::print_termination_counts() {
 248   gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %lld  "
 249     "Total spins: %lld  Total peeks: %lld",
 250     total_yields(),
 251     total_spins(),
 252     total_peeks());
 253 }
 254 #endif
 255 
 256 void ParallelTaskTerminator::reset_for_reuse() {
 257   if (_offered_termination != 0) {
 258     assert(_offered_termination == _n_threads,
 259            "Terminator may still be in use");
 260     _offered_termination = 0;
 261   }
 262 }
 263 
 264 #ifdef ASSERT
 265 bool ObjArrayTask::is_valid() const {
 266   return _obj != NULL && _obj->is_objArray() && _index > 0 &&
 267     _index < objArrayOop(_obj)->length();
 268 }
 269 #endif // ASSERT