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