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

duke@435 1 /*
trims@1907 2 * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
duke@435 22 *
duke@435 23 */
duke@435 24
duke@435 25 # include "incls/_precompiled.incl"
duke@435 26 # include "incls/_taskqueue.cpp.incl"
duke@435 27
jmasa@981 28 #ifdef TRACESPINNING
jmasa@981 29 uint ParallelTaskTerminator::_total_yields = 0;
jmasa@981 30 uint ParallelTaskTerminator::_total_spins = 0;
jmasa@981 31 uint ParallelTaskTerminator::_total_peeks = 0;
jmasa@981 32 #endif
jmasa@981 33
duke@435 34 int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
duke@435 35 const int a = 16807;
duke@435 36 const int m = 2147483647;
duke@435 37 const int q = 127773; /* m div a */
duke@435 38 const int r = 2836; /* m mod a */
duke@435 39 assert(sizeof(int) == 4, "I think this relies on that");
duke@435 40 int seed = *seed0;
duke@435 41 int hi = seed / q;
duke@435 42 int lo = seed % q;
duke@435 43 int test = a * lo - r * hi;
duke@435 44 if (test > 0)
duke@435 45 seed = test;
duke@435 46 else
duke@435 47 seed = test + m;
duke@435 48 *seed0 = seed;
duke@435 49 return seed;
duke@435 50 }
duke@435 51
duke@435 52 ParallelTaskTerminator::
duke@435 53 ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set) :
duke@435 54 _n_threads(n_threads),
duke@435 55 _queue_set(queue_set),
duke@435 56 _offered_termination(0) {}
duke@435 57
duke@435 58 bool ParallelTaskTerminator::peek_in_queue_set() {
duke@435 59 return _queue_set->peek();
duke@435 60 }
duke@435 61
duke@435 62 void ParallelTaskTerminator::yield() {
ysr@1280 63 assert(_offered_termination <= _n_threads, "Invariant");
duke@435 64 os::yield();
duke@435 65 }
duke@435 66
duke@435 67 void ParallelTaskTerminator::sleep(uint millis) {
ysr@1280 68 assert(_offered_termination <= _n_threads, "Invariant");
duke@435 69 os::sleep(Thread::current(), millis, false);
duke@435 70 }
duke@435 71
ysr@777 72 bool
ysr@777 73 ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
ysr@1280 74 assert(_offered_termination < _n_threads, "Invariant");
duke@435 75 Atomic::inc(&_offered_termination);
duke@435 76
ysr@976 77 uint yield_count = 0;
jmasa@981 78 // Number of hard spin loops done since last yield
jmasa@981 79 uint hard_spin_count = 0;
jmasa@981 80 // Number of iterations in the hard spin loop.
jmasa@981 81 uint hard_spin_limit = WorkStealingHardSpins;
jmasa@981 82
jmasa@981 83 // If WorkStealingSpinToYieldRatio is 0, no hard spinning is done.
jmasa@981 84 // If it is greater than 0, then start with a small number
jmasa@981 85 // of spins and increase number with each turn at spinning until
jmasa@981 86 // the count of hard spins exceeds WorkStealingSpinToYieldRatio.
jmasa@981 87 // Then do a yield() call and start spinning afresh.
jmasa@981 88 if (WorkStealingSpinToYieldRatio > 0) {
jmasa@981 89 hard_spin_limit = WorkStealingHardSpins >> WorkStealingSpinToYieldRatio;
jmasa@981 90 hard_spin_limit = MAX2(hard_spin_limit, 1U);
jmasa@981 91 }
jmasa@981 92 // Remember the initial spin limit.
jmasa@981 93 uint hard_spin_start = hard_spin_limit;
jmasa@981 94
jmasa@981 95 // Loop waiting for all threads to offer termination or
jmasa@981 96 // more work.
duke@435 97 while (true) {
ysr@1280 98 assert(_offered_termination <= _n_threads, "Invariant");
jmasa@981 99 // Are all threads offering termination?
duke@435 100 if (_offered_termination == _n_threads) {
duke@435 101 return true;
duke@435 102 } else {
jmasa@981 103 // Look for more work.
jmasa@981 104 // Periodically sleep() instead of yield() to give threads
jmasa@981 105 // waiting on the cores the chance to grab this code
duke@435 106 if (yield_count <= WorkStealingYieldsBeforeSleep) {
jmasa@981 107 // Do a yield or hardspin. For purposes of deciding whether
jmasa@981 108 // to sleep, count this as a yield.
duke@435 109 yield_count++;
jmasa@981 110
jmasa@981 111 // Periodically call yield() instead spinning
jmasa@981 112 // After WorkStealingSpinToYieldRatio spins, do a yield() call
jmasa@981 113 // and reset the counts and starting limit.
jmasa@981 114 if (hard_spin_count > WorkStealingSpinToYieldRatio) {
jmasa@981 115 yield();
jmasa@981 116 hard_spin_count = 0;
jmasa@981 117 hard_spin_limit = hard_spin_start;
jmasa@981 118 #ifdef TRACESPINNING
jmasa@981 119 _total_yields++;
jmasa@981 120 #endif
jmasa@981 121 } else {
jmasa@981 122 // Hard spin this time
jmasa@981 123 // Increase the hard spinning period but only up to a limit.
jmasa@981 124 hard_spin_limit = MIN2(2*hard_spin_limit,
jmasa@981 125 (uint) WorkStealingHardSpins);
jmasa@981 126 for (uint j = 0; j < hard_spin_limit; j++) {
jmasa@981 127 SpinPause();
jmasa@981 128 }
jmasa@981 129 hard_spin_count++;
jmasa@981 130 #ifdef TRACESPINNING
jmasa@981 131 _total_spins++;
jmasa@981 132 #endif
jmasa@981 133 }
duke@435 134 } else {
duke@435 135 if (PrintGCDetails && Verbose) {
duke@435 136 gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() "
duke@435 137 "thread %d sleeps after %d yields",
duke@435 138 Thread::current(), yield_count);
duke@435 139 }
duke@435 140 yield_count = 0;
duke@435 141 // A sleep will cause this processor to seek work on another processor's
duke@435 142 // runqueue, if it has nothing else to run (as opposed to the yield
duke@435 143 // which may only move the thread to the end of the this processor's
duke@435 144 // runqueue).
duke@435 145 sleep(WorkStealingSleepMillis);
duke@435 146 }
duke@435 147
jmasa@981 148 #ifdef TRACESPINNING
jmasa@981 149 _total_peeks++;
jmasa@981 150 #endif
ysr@777 151 if (peek_in_queue_set() ||
ysr@777 152 (terminator != NULL && terminator->should_exit_termination())) {
duke@435 153 Atomic::dec(&_offered_termination);
ysr@1280 154 assert(_offered_termination < _n_threads, "Invariant");
duke@435 155 return false;
duke@435 156 }
duke@435 157 }
duke@435 158 }
duke@435 159 }
duke@435 160
jmasa@981 161 #ifdef TRACESPINNING
jmasa@981 162 void ParallelTaskTerminator::print_termination_counts() {
jmasa@981 163 gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %lld "
jmasa@981 164 "Total spins: %lld Total peeks: %lld",
jmasa@981 165 total_yields(),
jmasa@981 166 total_spins(),
jmasa@981 167 total_peeks());
jmasa@981 168 }
jmasa@981 169 #endif
jmasa@981 170
duke@435 171 void ParallelTaskTerminator::reset_for_reuse() {
duke@435 172 if (_offered_termination != 0) {
duke@435 173 assert(_offered_termination == _n_threads,
duke@435 174 "Terminator may still be in use");
duke@435 175 _offered_termination = 0;
duke@435 176 }
duke@435 177 }
duke@435 178
jcoomes@1746 179 #ifdef ASSERT
jcoomes@1746 180 bool ObjArrayTask::is_valid() const {
jcoomes@1746 181 return _obj != NULL && _obj->is_objArray() && _index > 0 &&
jcoomes@1746 182 _index < objArrayOop(_obj)->length();
jcoomes@1746 183 }
jcoomes@1746 184 #endif // ASSERT
jcoomes@1746 185
jcoomes@810 186 bool RegionTaskQueueWithOverflow::is_empty() {
jcoomes@810 187 return (_region_queue.size() == 0) &&
duke@435 188 (_overflow_stack->length() == 0);
duke@435 189 }
duke@435 190
jcoomes@810 191 bool RegionTaskQueueWithOverflow::stealable_is_empty() {
jcoomes@810 192 return _region_queue.size() == 0;
duke@435 193 }
duke@435 194
jcoomes@810 195 bool RegionTaskQueueWithOverflow::overflow_is_empty() {
duke@435 196 return _overflow_stack->length() == 0;
duke@435 197 }
duke@435 198
jcoomes@810 199 void RegionTaskQueueWithOverflow::initialize() {
jcoomes@810 200 _region_queue.initialize();
duke@435 201 assert(_overflow_stack == 0, "Creating memory leak");
duke@435 202 _overflow_stack =
jcoomes@810 203 new (ResourceObj::C_HEAP) GrowableArray<RegionTask>(10, true);
duke@435 204 }
duke@435 205
jcoomes@810 206 void RegionTaskQueueWithOverflow::save(RegionTask t) {
jcoomes@810 207 if (TraceRegionTasksQueuing && Verbose) {
duke@435 208 gclog_or_tty->print_cr("CTQ: save " PTR_FORMAT, t);
duke@435 209 }
jcoomes@810 210 if(!_region_queue.push(t)) {
duke@435 211 _overflow_stack->push(t);
duke@435 212 }
duke@435 213 }
duke@435 214
jcoomes@810 215 // Note that using this method will retrieve all regions
duke@435 216 // that have been saved but that it will always check
duke@435 217 // the overflow stack. It may be more efficient to
duke@435 218 // check the stealable queue and the overflow stack
duke@435 219 // separately.
jcoomes@810 220 bool RegionTaskQueueWithOverflow::retrieve(RegionTask& region_task) {
jcoomes@810 221 bool result = retrieve_from_overflow(region_task);
duke@435 222 if (!result) {
jcoomes@810 223 result = retrieve_from_stealable_queue(region_task);
duke@435 224 }
jcoomes@810 225 if (TraceRegionTasksQueuing && Verbose && result) {
duke@435 226 gclog_or_tty->print_cr(" CTQ: retrieve " PTR_FORMAT, result);
duke@435 227 }
duke@435 228 return result;
duke@435 229 }
duke@435 230
jcoomes@810 231 bool RegionTaskQueueWithOverflow::retrieve_from_stealable_queue(
jcoomes@810 232 RegionTask& region_task) {
jcoomes@810 233 bool result = _region_queue.pop_local(region_task);
jcoomes@810 234 if (TraceRegionTasksQueuing && Verbose) {
jcoomes@810 235 gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task);
duke@435 236 }
duke@435 237 return result;
duke@435 238 }
duke@435 239
jcoomes@810 240 bool
jcoomes@810 241 RegionTaskQueueWithOverflow::retrieve_from_overflow(RegionTask& region_task) {
duke@435 242 bool result;
duke@435 243 if (!_overflow_stack->is_empty()) {
jcoomes@810 244 region_task = _overflow_stack->pop();
duke@435 245 result = true;
duke@435 246 } else {
jcoomes@810 247 region_task = (RegionTask) NULL;
duke@435 248 result = false;
duke@435 249 }
jcoomes@810 250 if (TraceRegionTasksQueuing && Verbose) {
jcoomes@810 251 gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task);
duke@435 252 }
duke@435 253 return result;
duke@435 254 }

mercurial