Thu, 27 May 2010 19:08:38 -0700
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 }