src/share/vm/utilities/taskqueue.cpp

Mon, 09 Mar 2009 13:28:46 -0700

author
xdono
date
Mon, 09 Mar 2009 13:28:46 -0700
changeset 1014
0fbdb4381b99
parent 981
05c6d52fa7a9
child 1280
df6caf649ff7
permissions
-rw-r--r--

6814575: Update copyright year
Summary: Update copyright for files that have been modified in 2009, up to 03/09
Reviewed-by: katleman, tbell, ohair

duke@435 1 /*
xdono@1014 2 * Copyright 2001-2009 Sun Microsystems, Inc. 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 *
duke@435 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@435 20 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@435 21 * have any 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 bool TaskQueueSuper::peek() {
duke@435 35 return _bottom != _age.top();
duke@435 36 }
duke@435 37
duke@435 38 int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
duke@435 39 const int a = 16807;
duke@435 40 const int m = 2147483647;
duke@435 41 const int q = 127773; /* m div a */
duke@435 42 const int r = 2836; /* m mod a */
duke@435 43 assert(sizeof(int) == 4, "I think this relies on that");
duke@435 44 int seed = *seed0;
duke@435 45 int hi = seed / q;
duke@435 46 int lo = seed % q;
duke@435 47 int test = a * lo - r * hi;
duke@435 48 if (test > 0)
duke@435 49 seed = test;
duke@435 50 else
duke@435 51 seed = test + m;
duke@435 52 *seed0 = seed;
duke@435 53 return seed;
duke@435 54 }
duke@435 55
duke@435 56 ParallelTaskTerminator::
duke@435 57 ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set) :
duke@435 58 _n_threads(n_threads),
duke@435 59 _queue_set(queue_set),
duke@435 60 _offered_termination(0) {}
duke@435 61
duke@435 62 bool ParallelTaskTerminator::peek_in_queue_set() {
duke@435 63 return _queue_set->peek();
duke@435 64 }
duke@435 65
duke@435 66 void ParallelTaskTerminator::yield() {
duke@435 67 os::yield();
duke@435 68 }
duke@435 69
duke@435 70 void ParallelTaskTerminator::sleep(uint millis) {
duke@435 71 os::sleep(Thread::current(), millis, false);
duke@435 72 }
duke@435 73
ysr@777 74 bool
ysr@777 75 ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
duke@435 76 Atomic::inc(&_offered_termination);
duke@435 77
ysr@976 78 uint yield_count = 0;
jmasa@981 79 // Number of hard spin loops done since last yield
jmasa@981 80 uint hard_spin_count = 0;
jmasa@981 81 // Number of iterations in the hard spin loop.
jmasa@981 82 uint hard_spin_limit = WorkStealingHardSpins;
jmasa@981 83
jmasa@981 84 // If WorkStealingSpinToYieldRatio is 0, no hard spinning is done.
jmasa@981 85 // If it is greater than 0, then start with a small number
jmasa@981 86 // of spins and increase number with each turn at spinning until
jmasa@981 87 // the count of hard spins exceeds WorkStealingSpinToYieldRatio.
jmasa@981 88 // Then do a yield() call and start spinning afresh.
jmasa@981 89 if (WorkStealingSpinToYieldRatio > 0) {
jmasa@981 90 hard_spin_limit = WorkStealingHardSpins >> WorkStealingSpinToYieldRatio;
jmasa@981 91 hard_spin_limit = MAX2(hard_spin_limit, 1U);
jmasa@981 92 }
jmasa@981 93 // Remember the initial spin limit.
jmasa@981 94 uint hard_spin_start = hard_spin_limit;
jmasa@981 95
jmasa@981 96 // Loop waiting for all threads to offer termination or
jmasa@981 97 // more work.
duke@435 98 while (true) {
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);
duke@435 154 return false;
duke@435 155 }
duke@435 156 }
duke@435 157 }
duke@435 158 }
duke@435 159
jmasa@981 160 #ifdef TRACESPINNING
jmasa@981 161 void ParallelTaskTerminator::print_termination_counts() {
jmasa@981 162 gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %lld "
jmasa@981 163 "Total spins: %lld Total peeks: %lld",
jmasa@981 164 total_yields(),
jmasa@981 165 total_spins(),
jmasa@981 166 total_peeks());
jmasa@981 167 }
jmasa@981 168 #endif
jmasa@981 169
duke@435 170 void ParallelTaskTerminator::reset_for_reuse() {
duke@435 171 if (_offered_termination != 0) {
duke@435 172 assert(_offered_termination == _n_threads,
duke@435 173 "Terminator may still be in use");
duke@435 174 _offered_termination = 0;
duke@435 175 }
duke@435 176 }
duke@435 177
jcoomes@810 178 bool RegionTaskQueueWithOverflow::is_empty() {
jcoomes@810 179 return (_region_queue.size() == 0) &&
duke@435 180 (_overflow_stack->length() == 0);
duke@435 181 }
duke@435 182
jcoomes@810 183 bool RegionTaskQueueWithOverflow::stealable_is_empty() {
jcoomes@810 184 return _region_queue.size() == 0;
duke@435 185 }
duke@435 186
jcoomes@810 187 bool RegionTaskQueueWithOverflow::overflow_is_empty() {
duke@435 188 return _overflow_stack->length() == 0;
duke@435 189 }
duke@435 190
jcoomes@810 191 void RegionTaskQueueWithOverflow::initialize() {
jcoomes@810 192 _region_queue.initialize();
duke@435 193 assert(_overflow_stack == 0, "Creating memory leak");
duke@435 194 _overflow_stack =
jcoomes@810 195 new (ResourceObj::C_HEAP) GrowableArray<RegionTask>(10, true);
duke@435 196 }
duke@435 197
jcoomes@810 198 void RegionTaskQueueWithOverflow::save(RegionTask t) {
jcoomes@810 199 if (TraceRegionTasksQueuing && Verbose) {
duke@435 200 gclog_or_tty->print_cr("CTQ: save " PTR_FORMAT, t);
duke@435 201 }
jcoomes@810 202 if(!_region_queue.push(t)) {
duke@435 203 _overflow_stack->push(t);
duke@435 204 }
duke@435 205 }
duke@435 206
jcoomes@810 207 // Note that using this method will retrieve all regions
duke@435 208 // that have been saved but that it will always check
duke@435 209 // the overflow stack. It may be more efficient to
duke@435 210 // check the stealable queue and the overflow stack
duke@435 211 // separately.
jcoomes@810 212 bool RegionTaskQueueWithOverflow::retrieve(RegionTask& region_task) {
jcoomes@810 213 bool result = retrieve_from_overflow(region_task);
duke@435 214 if (!result) {
jcoomes@810 215 result = retrieve_from_stealable_queue(region_task);
duke@435 216 }
jcoomes@810 217 if (TraceRegionTasksQueuing && Verbose && result) {
duke@435 218 gclog_or_tty->print_cr(" CTQ: retrieve " PTR_FORMAT, result);
duke@435 219 }
duke@435 220 return result;
duke@435 221 }
duke@435 222
jcoomes@810 223 bool RegionTaskQueueWithOverflow::retrieve_from_stealable_queue(
jcoomes@810 224 RegionTask& region_task) {
jcoomes@810 225 bool result = _region_queue.pop_local(region_task);
jcoomes@810 226 if (TraceRegionTasksQueuing && Verbose) {
jcoomes@810 227 gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task);
duke@435 228 }
duke@435 229 return result;
duke@435 230 }
duke@435 231
jcoomes@810 232 bool
jcoomes@810 233 RegionTaskQueueWithOverflow::retrieve_from_overflow(RegionTask& region_task) {
duke@435 234 bool result;
duke@435 235 if (!_overflow_stack->is_empty()) {
jcoomes@810 236 region_task = _overflow_stack->pop();
duke@435 237 result = true;
duke@435 238 } else {
jcoomes@810 239 region_task = (RegionTask) NULL;
duke@435 240 result = false;
duke@435 241 }
jcoomes@810 242 if (TraceRegionTasksQueuing && Verbose) {
jcoomes@810 243 gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task);
duke@435 244 }
duke@435 245 return result;
duke@435 246 }

mercurial