Mercurial > hg > truffle
comparison src/share/vm/utilities/taskqueue.hpp @ 541:23673011938d
6787254: Work queue capacity can be increased substantially on some platforms
Summary: Increased the default and maximum size of the CMS marking stack and the size of the parallel workers' work queues in 64-bit mode. The latter was accomplished by an increase in the width of the Taskqueue's Age struct and its Tag field in 64-bit mode.
Reviewed-by: jmasa, tonyp
author | ysr |
---|---|
date | Fri, 30 Jan 2009 14:17:52 -0800 |
parents | 81cd571500b0 |
children | 05c6d52fa7a9 |
comparison
equal
deleted
inserted
replaced
536:5b39c489c39d | 541:23673011938d |
---|---|
20 * CA 95054 USA or visit www.sun.com if you need additional information or | 20 * CA 95054 USA or visit www.sun.com if you need additional information or |
21 * have any questions. | 21 * have any questions. |
22 * | 22 * |
23 */ | 23 */ |
24 | 24 |
25 #ifdef LP64 | |
26 typedef juint TAG_TYPE; | |
27 // for a taskqueue size of 4M | |
28 #define LOG_TASKQ_SIZE 22 | |
29 #else | |
30 typedef jushort TAG_TYPE; | |
31 // for a taskqueue size of 16K | |
32 #define LOG_TASKQ_SIZE 14 | |
33 #endif | |
34 | |
25 class TaskQueueSuper: public CHeapObj { | 35 class TaskQueueSuper: public CHeapObj { |
26 protected: | 36 protected: |
27 // The first free element after the last one pushed (mod _n). | 37 // The first free element after the last one pushed (mod _n). |
28 // (For now we'll assume only 32-bit CAS). | 38 volatile uint _bottom; |
29 volatile juint _bottom; | |
30 | 39 |
31 // log2 of the size of the queue. | 40 // log2 of the size of the queue. |
32 enum SomeProtectedConstants { | 41 enum SomeProtectedConstants { |
33 Log_n = 14 | 42 Log_n = LOG_TASKQ_SIZE |
34 }; | 43 }; |
44 #undef LOG_TASKQ_SIZE | |
35 | 45 |
36 // Size of the queue. | 46 // Size of the queue. |
37 juint n() { return (1 << Log_n); } | 47 uint n() { return (1 << Log_n); } |
38 // For computing "x mod n" efficiently. | 48 // For computing "x mod n" efficiently. |
39 juint n_mod_mask() { return n() - 1; } | 49 uint n_mod_mask() { return n() - 1; } |
40 | 50 |
41 struct Age { | 51 struct Age { |
42 jushort _top; | 52 TAG_TYPE _top; |
43 jushort _tag; | 53 TAG_TYPE _tag; |
44 | 54 |
45 jushort tag() const { return _tag; } | 55 TAG_TYPE tag() const { return _tag; } |
46 jushort top() const { return _top; } | 56 TAG_TYPE top() const { return _top; } |
47 | 57 |
48 Age() { _tag = 0; _top = 0; } | 58 Age() { _tag = 0; _top = 0; } |
49 | 59 |
50 friend bool operator ==(const Age& a1, const Age& a2) { | 60 friend bool operator ==(const Age& a1, const Age& a2) { |
51 return a1.tag() == a2.tag() && a1.top() == a2.top(); | 61 return a1.tag() == a2.tag() && a1.top() == a2.top(); |
52 } | 62 } |
53 | |
54 }; | 63 }; |
55 Age _age; | 64 Age _age; |
56 // These make sure we do single atomic reads and writes. | 65 // These make sure we do single atomic reads and writes. |
57 Age get_age() { | 66 Age get_age() { |
58 jint res = *(volatile jint*)(&_age); | 67 uint res = *(volatile uint*)(&_age); |
59 return *(Age*)(&res); | 68 return *(Age*)(&res); |
60 } | 69 } |
61 void set_age(Age a) { | 70 void set_age(Age a) { |
62 *(volatile jint*)(&_age) = *(int*)(&a); | 71 *(volatile uint*)(&_age) = *(uint*)(&a); |
63 } | 72 } |
64 | 73 |
65 jushort get_top() { | 74 TAG_TYPE get_top() { |
66 return get_age().top(); | 75 return get_age().top(); |
67 } | 76 } |
68 | 77 |
69 // These both operate mod _n. | 78 // These both operate mod _n. |
70 juint increment_index(juint ind) { | 79 uint increment_index(uint ind) { |
71 return (ind + 1) & n_mod_mask(); | 80 return (ind + 1) & n_mod_mask(); |
72 } | 81 } |
73 juint decrement_index(juint ind) { | 82 uint decrement_index(uint ind) { |
74 return (ind - 1) & n_mod_mask(); | 83 return (ind - 1) & n_mod_mask(); |
75 } | 84 } |
76 | 85 |
77 // Returns a number in the range [0.._n). If the result is "n-1", it | 86 // Returns a number in the range [0.._n). If the result is "n-1", it |
78 // should be interpreted as 0. | 87 // should be interpreted as 0. |
79 juint dirty_size(juint bot, juint top) { | 88 uint dirty_size(uint bot, uint top) { |
80 return ((jint)bot - (jint)top) & n_mod_mask(); | 89 return ((int)bot - (int)top) & n_mod_mask(); |
81 } | 90 } |
82 | 91 |
83 // Returns the size corresponding to the given "bot" and "top". | 92 // Returns the size corresponding to the given "bot" and "top". |
84 juint size(juint bot, juint top) { | 93 uint size(uint bot, uint top) { |
85 juint sz = dirty_size(bot, top); | 94 uint sz = dirty_size(bot, top); |
86 // Has the queue "wrapped", so that bottom is less than top? | 95 // Has the queue "wrapped", so that bottom is less than top? |
87 // There's a complicated special case here. A pair of threads could | 96 // There's a complicated special case here. A pair of threads could |
88 // perform pop_local and pop_global operations concurrently, starting | 97 // perform pop_local and pop_global operations concurrently, starting |
89 // from a state in which _bottom == _top+1. The pop_local could | 98 // from a state in which _bottom == _top+1. The pop_local could |
90 // succeed in decrementing _bottom, and the pop_global in incrementing | 99 // succeed in decrementing _bottom, and the pop_global in incrementing |
92 // queue element.) The resulting state must be interpreted as an empty | 101 // queue element.) The resulting state must be interpreted as an empty |
93 // queue. (We only need to worry about one such event: only the queue | 102 // queue. (We only need to worry about one such event: only the queue |
94 // owner performs pop_local's, and several concurrent threads | 103 // owner performs pop_local's, and several concurrent threads |
95 // attempting to perform the pop_global will all perform the same CAS, | 104 // attempting to perform the pop_global will all perform the same CAS, |
96 // and only one can succeed. Any stealing thread that reads after | 105 // and only one can succeed. Any stealing thread that reads after |
97 // either the increment or decrement will seen an empty queue, and will | 106 // either the increment or decrement will see an empty queue, and will |
98 // not join the competitors. The "sz == -1 || sz == _n-1" state will | 107 // not join the competitors. The "sz == -1 || sz == _n-1" state will |
99 // not be modified by concurrent queues, so the owner thread can reset | 108 // not be modified by concurrent queues, so the owner thread can reset |
100 // the state to _bottom == top so subsequent pushes will be performed | 109 // the state to _bottom == top so subsequent pushes will be performed |
101 // normally. | 110 // normally. |
102 if (sz == (n()-1)) return 0; | 111 if (sz == (n()-1)) return 0; |
110 bool peek(); | 119 bool peek(); |
111 | 120 |
112 // Return an estimate of the number of elements in the queue. | 121 // Return an estimate of the number of elements in the queue. |
113 // The "careful" version admits the possibility of pop_local/pop_global | 122 // The "careful" version admits the possibility of pop_local/pop_global |
114 // races. | 123 // races. |
115 juint size() { | 124 uint size() { |
116 return size(_bottom, get_top()); | 125 return size(_bottom, get_top()); |
117 } | 126 } |
118 | 127 |
119 juint dirty_size() { | 128 uint dirty_size() { |
120 return dirty_size(_bottom, get_top()); | 129 return dirty_size(_bottom, get_top()); |
121 } | 130 } |
122 | 131 |
123 void set_empty() { | 132 void set_empty() { |
124 _bottom = 0; | 133 _bottom = 0; |
125 _age = Age(); | 134 _age = Age(); |
126 } | 135 } |
127 | 136 |
128 // Maximum number of elements allowed in the queue. This is two less | 137 // Maximum number of elements allowed in the queue. This is two less |
129 // than the actual queue size, for somewhat complicated reasons. | 138 // than the actual queue size, for somewhat complicated reasons. |
130 juint max_elems() { return n() - 2; } | 139 uint max_elems() { return n() - 2; } |
131 | 140 |
132 }; | 141 }; |
133 | 142 |
134 template<class E> class GenericTaskQueue: public TaskQueueSuper { | 143 template<class E> class GenericTaskQueue: public TaskQueueSuper { |
135 private: | 144 private: |
136 // Slow paths for push, pop_local. (pop_global has no fast path.) | 145 // Slow paths for push, pop_local. (pop_global has no fast path.) |
137 bool push_slow(E t, juint dirty_n_elems); | 146 bool push_slow(E t, uint dirty_n_elems); |
138 bool pop_local_slow(juint localBot, Age oldAge); | 147 bool pop_local_slow(uint localBot, Age oldAge); |
139 | 148 |
140 public: | 149 public: |
141 // Initializes the queue to empty. | 150 // Initializes the queue to empty. |
142 GenericTaskQueue(); | 151 GenericTaskQueue(); |
143 | 152 |
168 volatile E* _elems; | 177 volatile E* _elems; |
169 }; | 178 }; |
170 | 179 |
171 template<class E> | 180 template<class E> |
172 GenericTaskQueue<E>::GenericTaskQueue():TaskQueueSuper() { | 181 GenericTaskQueue<E>::GenericTaskQueue():TaskQueueSuper() { |
173 assert(sizeof(Age) == sizeof(jint), "Depends on this."); | 182 assert(sizeof(Age) == sizeof(int), "Depends on this."); |
174 } | 183 } |
175 | 184 |
176 template<class E> | 185 template<class E> |
177 void GenericTaskQueue<E>::initialize() { | 186 void GenericTaskQueue<E>::initialize() { |
178 _elems = NEW_C_HEAP_ARRAY(E, n()); | 187 _elems = NEW_C_HEAP_ARRAY(E, n()); |
180 } | 189 } |
181 | 190 |
182 template<class E> | 191 template<class E> |
183 void GenericTaskQueue<E>::oops_do(OopClosure* f) { | 192 void GenericTaskQueue<E>::oops_do(OopClosure* f) { |
184 // tty->print_cr("START OopTaskQueue::oops_do"); | 193 // tty->print_cr("START OopTaskQueue::oops_do"); |
185 int iters = size(); | 194 uint iters = size(); |
186 juint index = _bottom; | 195 uint index = _bottom; |
187 for (int i = 0; i < iters; ++i) { | 196 for (uint i = 0; i < iters; ++i) { |
188 index = decrement_index(index); | 197 index = decrement_index(index); |
189 // tty->print_cr(" doing entry %d," INTPTR_T " -> " INTPTR_T, | 198 // tty->print_cr(" doing entry %d," INTPTR_T " -> " INTPTR_T, |
190 // index, &_elems[index], _elems[index]); | 199 // index, &_elems[index], _elems[index]); |
191 E* t = (E*)&_elems[index]; // cast away volatility | 200 E* t = (E*)&_elems[index]; // cast away volatility |
192 oop* p = (oop*)t; | 201 oop* p = (oop*)t; |
196 // tty->print_cr("END OopTaskQueue::oops_do"); | 205 // tty->print_cr("END OopTaskQueue::oops_do"); |
197 } | 206 } |
198 | 207 |
199 | 208 |
200 template<class E> | 209 template<class E> |
201 bool GenericTaskQueue<E>::push_slow(E t, juint dirty_n_elems) { | 210 bool GenericTaskQueue<E>::push_slow(E t, uint dirty_n_elems) { |
202 if (dirty_n_elems == n() - 1) { | 211 if (dirty_n_elems == n() - 1) { |
203 // Actually means 0, so do the push. | 212 // Actually means 0, so do the push. |
204 juint localBot = _bottom; | 213 uint localBot = _bottom; |
205 _elems[localBot] = t; | 214 _elems[localBot] = t; |
206 _bottom = increment_index(localBot); | 215 _bottom = increment_index(localBot); |
207 return true; | 216 return true; |
208 } else | 217 } else |
209 return false; | 218 return false; |
210 } | 219 } |
211 | 220 |
212 template<class E> | 221 template<class E> |
213 bool GenericTaskQueue<E>:: | 222 bool GenericTaskQueue<E>:: |
214 pop_local_slow(juint localBot, Age oldAge) { | 223 pop_local_slow(uint localBot, Age oldAge) { |
215 // This queue was observed to contain exactly one element; either this | 224 // This queue was observed to contain exactly one element; either this |
216 // thread will claim it, or a competing "pop_global". In either case, | 225 // thread will claim it, or a competing "pop_global". In either case, |
217 // the queue will be logically empty afterwards. Create a new Age value | 226 // the queue will be logically empty afterwards. Create a new Age value |
218 // that represents the empty queue for the given value of "_bottom". (We | 227 // that represents the empty queue for the given value of "_bottom". (We |
219 // must also increment "tag" because of the case where "bottom == 1", | 228 // must also increment "tag" because of the case where "bottom == 1", |
228 // case it wins the element. | 237 // case it wins the element. |
229 if (localBot == oldAge.top()) { | 238 if (localBot == oldAge.top()) { |
230 Age tempAge; | 239 Age tempAge; |
231 // No competing pop_global has yet incremented "top"; we'll try to | 240 // No competing pop_global has yet incremented "top"; we'll try to |
232 // install new_age, thus claiming the element. | 241 // install new_age, thus claiming the element. |
233 assert(sizeof(Age) == sizeof(jint) && sizeof(jint) == sizeof(juint), | 242 assert(sizeof(Age) == sizeof(int), "Assumption about CAS unit."); |
234 "Assumption about CAS unit."); | 243 *(uint*)&tempAge = Atomic::cmpxchg(*(uint*)&newAge, (volatile uint*)&_age, *(uint*)&oldAge); |
235 *(jint*)&tempAge = Atomic::cmpxchg(*(jint*)&newAge, (volatile jint*)&_age, *(jint*)&oldAge); | |
236 if (tempAge == oldAge) { | 244 if (tempAge == oldAge) { |
237 // We win. | 245 // We win. |
238 assert(dirty_size(localBot, get_top()) != n() - 1, | 246 assert(dirty_size(localBot, get_top()) != n() - 1, |
239 "Shouldn't be possible..."); | 247 "Shouldn't be possible..."); |
240 return true; | 248 return true; |
251 | 259 |
252 template<class E> | 260 template<class E> |
253 bool GenericTaskQueue<E>::pop_global(E& t) { | 261 bool GenericTaskQueue<E>::pop_global(E& t) { |
254 Age newAge; | 262 Age newAge; |
255 Age oldAge = get_age(); | 263 Age oldAge = get_age(); |
256 juint localBot = _bottom; | 264 uint localBot = _bottom; |
257 juint n_elems = size(localBot, oldAge.top()); | 265 uint n_elems = size(localBot, oldAge.top()); |
258 if (n_elems == 0) { | 266 if (n_elems == 0) { |
259 return false; | 267 return false; |
260 } | 268 } |
261 t = _elems[oldAge.top()]; | 269 t = _elems[oldAge.top()]; |
262 newAge = oldAge; | 270 newAge = oldAge; |
263 newAge._top = increment_index(newAge.top()); | 271 newAge._top = increment_index(newAge.top()); |
264 if ( newAge._top == 0 ) newAge._tag++; | 272 if ( newAge._top == 0 ) newAge._tag++; |
265 Age resAge; | 273 Age resAge; |
266 *(jint*)&resAge = Atomic::cmpxchg(*(jint*)&newAge, (volatile jint*)&_age, *(jint*)&oldAge); | 274 *(uint*)&resAge = Atomic::cmpxchg(*(uint*)&newAge, (volatile uint*)&_age, *(uint*)&oldAge); |
267 // Note that using "_bottom" here might fail, since a pop_local might | 275 // Note that using "_bottom" here might fail, since a pop_local might |
268 // have decremented it. | 276 // have decremented it. |
269 assert(dirty_size(localBot, newAge._top) != n() - 1, | 277 assert(dirty_size(localBot, newAge._top) != n() - 1, |
270 "Shouldn't be possible..."); | 278 "Shouldn't be possible..."); |
271 return (resAge == oldAge); | 279 return (resAge == oldAge); |
285 virtual bool peek() = 0; | 293 virtual bool peek() = 0; |
286 }; | 294 }; |
287 | 295 |
288 template<class E> class GenericTaskQueueSet: public TaskQueueSetSuper { | 296 template<class E> class GenericTaskQueueSet: public TaskQueueSetSuper { |
289 private: | 297 private: |
290 int _n; | 298 uint _n; |
291 GenericTaskQueue<E>** _queues; | 299 GenericTaskQueue<E>** _queues; |
292 | 300 |
293 public: | 301 public: |
294 GenericTaskQueueSet(int n) : _n(n) { | 302 GenericTaskQueueSet(int n) : _n(n) { |
295 typedef GenericTaskQueue<E>* GenericTaskQueuePtr; | 303 typedef GenericTaskQueue<E>* GenericTaskQueuePtr; |
298 for (int i = 0; i < n; i++) { | 306 for (int i = 0; i < n; i++) { |
299 _queues[i] = NULL; | 307 _queues[i] = NULL; |
300 } | 308 } |
301 } | 309 } |
302 | 310 |
303 bool steal_1_random(int queue_num, int* seed, E& t); | 311 bool steal_1_random(uint queue_num, int* seed, E& t); |
304 bool steal_best_of_2(int queue_num, int* seed, E& t); | 312 bool steal_best_of_2(uint queue_num, int* seed, E& t); |
305 bool steal_best_of_all(int queue_num, int* seed, E& t); | 313 bool steal_best_of_all(uint queue_num, int* seed, E& t); |
306 | 314 |
307 void register_queue(int i, GenericTaskQueue<E>* q); | 315 void register_queue(uint i, GenericTaskQueue<E>* q); |
308 | 316 |
309 GenericTaskQueue<E>* queue(int n); | 317 GenericTaskQueue<E>* queue(uint n); |
310 | 318 |
311 // The thread with queue number "queue_num" (and whose random number seed | 319 // The thread with queue number "queue_num" (and whose random number seed |
312 // is at "seed") is trying to steal a task from some other queue. (It | 320 // is at "seed") is trying to steal a task from some other queue. (It |
313 // may try several queues, according to some configuration parameter.) | 321 // may try several queues, according to some configuration parameter.) |
314 // If some steal succeeds, returns "true" and sets "t" the stolen task, | 322 // If some steal succeeds, returns "true" and sets "t" the stolen task, |
315 // otherwise returns false. | 323 // otherwise returns false. |
316 bool steal(int queue_num, int* seed, E& t); | 324 bool steal(uint queue_num, int* seed, E& t); |
317 | 325 |
318 bool peek(); | 326 bool peek(); |
319 }; | 327 }; |
320 | 328 |
321 template<class E> | 329 template<class E> |
322 void GenericTaskQueueSet<E>::register_queue(int i, GenericTaskQueue<E>* q) { | 330 void GenericTaskQueueSet<E>::register_queue(uint i, GenericTaskQueue<E>* q) { |
323 assert(0 <= i && i < _n, "index out of range."); | 331 assert(i < _n, "index out of range."); |
324 _queues[i] = q; | 332 _queues[i] = q; |
325 } | 333 } |
326 | 334 |
327 template<class E> | 335 template<class E> |
328 GenericTaskQueue<E>* GenericTaskQueueSet<E>::queue(int i) { | 336 GenericTaskQueue<E>* GenericTaskQueueSet<E>::queue(uint i) { |
329 return _queues[i]; | 337 return _queues[i]; |
330 } | 338 } |
331 | 339 |
332 template<class E> | 340 template<class E> |
333 bool GenericTaskQueueSet<E>::steal(int queue_num, int* seed, E& t) { | 341 bool GenericTaskQueueSet<E>::steal(uint queue_num, int* seed, E& t) { |
334 for (int i = 0; i < 2 * _n; i++) | 342 for (uint i = 0; i < 2 * _n; i++) |
335 if (steal_best_of_2(queue_num, seed, t)) | 343 if (steal_best_of_2(queue_num, seed, t)) |
336 return true; | 344 return true; |
337 return false; | 345 return false; |
338 } | 346 } |
339 | 347 |
340 template<class E> | 348 template<class E> |
341 bool GenericTaskQueueSet<E>::steal_best_of_all(int queue_num, int* seed, E& t) { | 349 bool GenericTaskQueueSet<E>::steal_best_of_all(uint queue_num, int* seed, E& t) { |
342 if (_n > 2) { | 350 if (_n > 2) { |
343 int best_k; | 351 int best_k; |
344 jint best_sz = 0; | 352 uint best_sz = 0; |
345 for (int k = 0; k < _n; k++) { | 353 for (uint k = 0; k < _n; k++) { |
346 if (k == queue_num) continue; | 354 if (k == queue_num) continue; |
347 jint sz = _queues[k]->size(); | 355 uint sz = _queues[k]->size(); |
348 if (sz > best_sz) { | 356 if (sz > best_sz) { |
349 best_sz = sz; | 357 best_sz = sz; |
350 best_k = k; | 358 best_k = k; |
351 } | 359 } |
352 } | 360 } |
360 return false; | 368 return false; |
361 } | 369 } |
362 } | 370 } |
363 | 371 |
364 template<class E> | 372 template<class E> |
365 bool GenericTaskQueueSet<E>::steal_1_random(int queue_num, int* seed, E& t) { | 373 bool GenericTaskQueueSet<E>::steal_1_random(uint queue_num, int* seed, E& t) { |
366 if (_n > 2) { | 374 if (_n > 2) { |
367 int k = queue_num; | 375 uint k = queue_num; |
368 while (k == queue_num) k = randomParkAndMiller(seed) % _n; | 376 while (k == queue_num) k = randomParkAndMiller(seed) % _n; |
369 return _queues[2]->pop_global(t); | 377 return _queues[2]->pop_global(t); |
370 } else if (_n == 2) { | 378 } else if (_n == 2) { |
371 // Just try the other one. | 379 // Just try the other one. |
372 int k = (queue_num + 1) % 2; | 380 int k = (queue_num + 1) % 2; |
376 return false; | 384 return false; |
377 } | 385 } |
378 } | 386 } |
379 | 387 |
380 template<class E> | 388 template<class E> |
381 bool GenericTaskQueueSet<E>::steal_best_of_2(int queue_num, int* seed, E& t) { | 389 bool GenericTaskQueueSet<E>::steal_best_of_2(uint queue_num, int* seed, E& t) { |
382 if (_n > 2) { | 390 if (_n > 2) { |
383 int k1 = queue_num; | 391 uint k1 = queue_num; |
384 while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n; | 392 while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n; |
385 int k2 = queue_num; | 393 uint k2 = queue_num; |
386 while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n; | 394 while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n; |
387 // Sample both and try the larger. | 395 // Sample both and try the larger. |
388 juint sz1 = _queues[k1]->size(); | 396 uint sz1 = _queues[k1]->size(); |
389 juint sz2 = _queues[k2]->size(); | 397 uint sz2 = _queues[k2]->size(); |
390 if (sz2 > sz1) return _queues[k2]->pop_global(t); | 398 if (sz2 > sz1) return _queues[k2]->pop_global(t); |
391 else return _queues[k1]->pop_global(t); | 399 else return _queues[k1]->pop_global(t); |
392 } else if (_n == 2) { | 400 } else if (_n == 2) { |
393 // Just try the other one. | 401 // Just try the other one. |
394 int k = (queue_num + 1) % 2; | 402 uint k = (queue_num + 1) % 2; |
395 return _queues[k]->pop_global(t); | 403 return _queues[k]->pop_global(t); |
396 } else { | 404 } else { |
397 assert(_n == 1, "can't be zero."); | 405 assert(_n == 1, "can't be zero."); |
398 return false; | 406 return false; |
399 } | 407 } |
400 } | 408 } |
401 | 409 |
402 template<class E> | 410 template<class E> |
403 bool GenericTaskQueueSet<E>::peek() { | 411 bool GenericTaskQueueSet<E>::peek() { |
404 // Try all the queues. | 412 // Try all the queues. |
405 for (int j = 0; j < _n; j++) { | 413 for (uint j = 0; j < _n; j++) { |
406 if (_queues[j]->peek()) | 414 if (_queues[j]->peek()) |
407 return true; | 415 return true; |
408 } | 416 } |
409 return false; | 417 return false; |
410 } | 418 } |
420 | 428 |
421 class ParallelTaskTerminator: public StackObj { | 429 class ParallelTaskTerminator: public StackObj { |
422 private: | 430 private: |
423 int _n_threads; | 431 int _n_threads; |
424 TaskQueueSetSuper* _queue_set; | 432 TaskQueueSetSuper* _queue_set; |
425 jint _offered_termination; | 433 int _offered_termination; |
426 | 434 |
427 bool peek_in_queue_set(); | 435 bool peek_in_queue_set(); |
428 protected: | 436 protected: |
429 virtual void yield(); | 437 virtual void yield(); |
430 void sleep(uint millis); | 438 void sleep(uint millis); |
458 | 466 |
459 #define SIMPLE_STACK 0 | 467 #define SIMPLE_STACK 0 |
460 | 468 |
461 template<class E> inline bool GenericTaskQueue<E>::push(E t) { | 469 template<class E> inline bool GenericTaskQueue<E>::push(E t) { |
462 #if SIMPLE_STACK | 470 #if SIMPLE_STACK |
463 juint localBot = _bottom; | 471 uint localBot = _bottom; |
464 if (_bottom < max_elems()) { | 472 if (_bottom < max_elems()) { |
465 _elems[localBot] = t; | 473 _elems[localBot] = t; |
466 _bottom = localBot + 1; | 474 _bottom = localBot + 1; |
467 return true; | 475 return true; |
468 } else { | 476 } else { |
469 return false; | 477 return false; |
470 } | 478 } |
471 #else | 479 #else |
472 juint localBot = _bottom; | 480 uint localBot = _bottom; |
473 assert((localBot >= 0) && (localBot < n()), "_bottom out of range."); | 481 assert((localBot >= 0) && (localBot < n()), "_bottom out of range."); |
474 jushort top = get_top(); | 482 TAG_TYPE top = get_top(); |
475 juint dirty_n_elems = dirty_size(localBot, top); | 483 uint dirty_n_elems = dirty_size(localBot, top); |
476 assert((dirty_n_elems >= 0) && (dirty_n_elems < n()), | 484 assert((dirty_n_elems >= 0) && (dirty_n_elems < n()), |
477 "n_elems out of range."); | 485 "n_elems out of range."); |
478 if (dirty_n_elems < max_elems()) { | 486 if (dirty_n_elems < max_elems()) { |
479 _elems[localBot] = t; | 487 _elems[localBot] = t; |
480 _bottom = increment_index(localBot); | 488 _bottom = increment_index(localBot); |
485 #endif | 493 #endif |
486 } | 494 } |
487 | 495 |
488 template<class E> inline bool GenericTaskQueue<E>::pop_local(E& t) { | 496 template<class E> inline bool GenericTaskQueue<E>::pop_local(E& t) { |
489 #if SIMPLE_STACK | 497 #if SIMPLE_STACK |
490 juint localBot = _bottom; | 498 uint localBot = _bottom; |
491 assert(localBot > 0, "precondition."); | 499 assert(localBot > 0, "precondition."); |
492 localBot--; | 500 localBot--; |
493 t = _elems[localBot]; | 501 t = _elems[localBot]; |
494 _bottom = localBot; | 502 _bottom = localBot; |
495 return true; | 503 return true; |
496 #else | 504 #else |
497 juint localBot = _bottom; | 505 uint localBot = _bottom; |
498 // This value cannot be n-1. That can only occur as a result of | 506 // This value cannot be n-1. That can only occur as a result of |
499 // the assignment to bottom in this method. If it does, this method | 507 // the assignment to bottom in this method. If it does, this method |
500 // resets the size( to 0 before the next call (which is sequential, | 508 // resets the size( to 0 before the next call (which is sequential, |
501 // since this is pop_local.) | 509 // since this is pop_local.) |
502 juint dirty_n_elems = dirty_size(localBot, get_top()); | 510 uint dirty_n_elems = dirty_size(localBot, get_top()); |
503 assert(dirty_n_elems != n() - 1, "Shouldn't be possible..."); | 511 assert(dirty_n_elems != n() - 1, "Shouldn't be possible..."); |
504 if (dirty_n_elems == 0) return false; | 512 if (dirty_n_elems == 0) return false; |
505 localBot = decrement_index(localBot); | 513 localBot = decrement_index(localBot); |
506 _bottom = localBot; | 514 _bottom = localBot; |
507 // This is necessary to prevent any read below from being reordered | 515 // This is necessary to prevent any read below from being reordered |
510 t = _elems[localBot]; | 518 t = _elems[localBot]; |
511 // This is a second read of "age"; the "size()" above is the first. | 519 // This is a second read of "age"; the "size()" above is the first. |
512 // If there's still at least one element in the queue, based on the | 520 // If there's still at least one element in the queue, based on the |
513 // "_bottom" and "age" we've read, then there can be no interference with | 521 // "_bottom" and "age" we've read, then there can be no interference with |
514 // a "pop_global" operation, and we're done. | 522 // a "pop_global" operation, and we're done. |
515 juint tp = get_top(); | 523 TAG_TYPE tp = get_top(); // XXX |
516 if (size(localBot, tp) > 0) { | 524 if (size(localBot, tp) > 0) { |
517 assert(dirty_size(localBot, tp) != n() - 1, | 525 assert(dirty_size(localBot, tp) != n() - 1, |
518 "Shouldn't be possible..."); | 526 "Shouldn't be possible..."); |
519 return true; | 527 return true; |
520 } else { | 528 } else { |
579 // Retrieve from overflow | 587 // Retrieve from overflow |
580 bool retrieve_from_overflow(RegionTask& region_index); | 588 bool retrieve_from_overflow(RegionTask& region_index); |
581 bool is_empty(); | 589 bool is_empty(); |
582 bool stealable_is_empty(); | 590 bool stealable_is_empty(); |
583 bool overflow_is_empty(); | 591 bool overflow_is_empty(); |
584 juint stealable_size() { return _region_queue.size(); } | 592 uint stealable_size() { return _region_queue.size(); } |
585 RegionTaskQueue* task_queue() { return &_region_queue; } | 593 RegionTaskQueue* task_queue() { return &_region_queue; } |
586 }; | 594 }; |
587 | 595 |
588 #define USE_RegionTaskQueueWithOverflow | 596 #define USE_RegionTaskQueueWithOverflow |