comparison src/share/vm/utilities/taskqueue.hpp @ 1665:a93a9eda13f7

6962947: shared TaskQueue statistics Reviewed-by: tonyp, ysr
author jcoomes
date Fri, 16 Jul 2010 21:33:21 -0700
parents b2a00dd3117c
children 5f429ee79634
comparison
equal deleted inserted replaced
1657:1a1ce2076047 1665:a93a9eda13f7
20 * or visit www.oracle.com if you need additional information or have any 20 * or visit www.oracle.com if you need additional information or have any
21 * questions. 21 * questions.
22 * 22 *
23 */ 23 */
24 24
25 // Simple TaskQueue stats that are collected by default in debug builds.
26
27 #if !defined(TASKQUEUE_STATS) && defined(ASSERT)
28 #define TASKQUEUE_STATS 1
29 #elif !defined(TASKQUEUE_STATS)
30 #define TASKQUEUE_STATS 0
31 #endif
32
33 #if TASKQUEUE_STATS
34 #define TASKQUEUE_STATS_ONLY(code) code
35 #else
36 #define TASKQUEUE_STATS_ONLY(code)
37 #endif // TASKQUEUE_STATS
38
39 #if TASKQUEUE_STATS
40 class TaskQueueStats {
41 public:
42 enum StatId {
43 push, // number of taskqueue pushes
44 pop, // number of taskqueue pops
45 pop_slow, // subset of taskqueue pops that were done slow-path
46 steal_attempt, // number of taskqueue steal attempts
47 steal, // number of taskqueue steals
48 overflow, // number of overflow pushes
49 overflow_max_len, // max length of overflow stack
50 last_stat_id
51 };
52
53 public:
54 inline TaskQueueStats() { reset(); }
55
56 inline void record_push() { ++_stats[push]; }
57 inline void record_pop() { ++_stats[pop]; }
58 inline void record_pop_slow() { record_pop(); ++_stats[pop_slow]; }
59 inline void record_steal(bool success);
60 inline void record_overflow(size_t new_length);
61
62 inline size_t get(StatId id) const { return _stats[id]; }
63 inline const size_t* get() const { return _stats; }
64
65 inline void reset();
66
67 static void print_header(unsigned int line, outputStream* const stream = tty,
68 unsigned int width = 10);
69 void print(outputStream* const stream = tty, unsigned int width = 10) const;
70
71 private:
72 size_t _stats[last_stat_id];
73 static const char * const _names[last_stat_id];
74 };
75
76 void TaskQueueStats::record_steal(bool success) {
77 ++_stats[steal_attempt];
78 if (success) ++_stats[steal];
79 }
80
81 void TaskQueueStats::record_overflow(size_t new_len) {
82 ++_stats[overflow];
83 if (new_len > _stats[overflow_max_len]) _stats[overflow_max_len] = new_len;
84 }
85
86 void TaskQueueStats::reset() {
87 memset(_stats, 0, sizeof(_stats));
88 }
89 #endif // TASKQUEUE_STATS
90
25 template <unsigned int N> 91 template <unsigned int N>
26 class TaskQueueSuper: public CHeapObj { 92 class TaskQueueSuper: public CHeapObj {
27 protected: 93 protected:
28 // Internal type for indexing the queue; also used for the tag. 94 // Internal type for indexing the queue; also used for the tag.
29 typedef NOT_LP64(uint16_t) LP64_ONLY(uint32_t) idx_t; 95 typedef NOT_LP64(uint16_t) LP64_ONLY(uint32_t) idx_t;
133 // than the actual queue size, for somewhat complicated reasons. 199 // than the actual queue size, for somewhat complicated reasons.
134 uint max_elems() const { return N - 2; } 200 uint max_elems() const { return N - 2; }
135 201
136 // Total size of queue. 202 // Total size of queue.
137 static const uint total_size() { return N; } 203 static const uint total_size() { return N; }
204
205 TASKQUEUE_STATS_ONLY(TaskQueueStats stats;)
138 }; 206 };
139 207
140 template<class E, unsigned int N = TASKQUEUE_SIZE> 208 template<class E, unsigned int N = TASKQUEUE_SIZE>
141 class GenericTaskQueue: public TaskQueueSuper<N> { 209 class GenericTaskQueue: public TaskQueueSuper<N> {
142 protected: 210 protected:
150 using TaskQueueSuper<N>::dirty_size; 218 using TaskQueueSuper<N>::dirty_size;
151 219
152 public: 220 public:
153 using TaskQueueSuper<N>::max_elems; 221 using TaskQueueSuper<N>::max_elems;
154 using TaskQueueSuper<N>::size; 222 using TaskQueueSuper<N>::size;
223 TASKQUEUE_STATS_ONLY(using TaskQueueSuper<N>::stats;)
155 224
156 private: 225 private:
157 // Slow paths for push, pop_local. (pop_global has no fast path.) 226 // Slow paths for push, pop_local. (pop_global has no fast path.)
158 bool push_slow(E t, uint dirty_n_elems); 227 bool push_slow(E t, uint dirty_n_elems);
159 bool pop_local_slow(uint localBot, Age oldAge); 228 bool pop_local_slow(uint localBot, Age oldAge);
222 // Actually means 0, so do the push. 291 // Actually means 0, so do the push.
223 uint localBot = _bottom; 292 uint localBot = _bottom;
224 // g++ complains if the volatile result of the assignment is unused. 293 // g++ complains if the volatile result of the assignment is unused.
225 const_cast<E&>(_elems[localBot] = t); 294 const_cast<E&>(_elems[localBot] = t);
226 OrderAccess::release_store(&_bottom, increment_index(localBot)); 295 OrderAccess::release_store(&_bottom, increment_index(localBot));
296 TASKQUEUE_STATS_ONLY(stats.record_push());
227 return true; 297 return true;
228 } 298 }
229 return false; 299 return false;
230 } 300 }
231 301
232 template<class E, unsigned int N> 302 template<class E, unsigned int N>
233 bool GenericTaskQueue<E, N>:: 303 bool GenericTaskQueue<E, N>::pop_local_slow(uint localBot, Age oldAge) {
234 pop_local_slow(uint localBot, Age oldAge) {
235 // This queue was observed to contain exactly one element; either this 304 // This queue was observed to contain exactly one element; either this
236 // thread will claim it, or a competing "pop_global". In either case, 305 // thread will claim it, or a competing "pop_global". In either case,
237 // the queue will be logically empty afterwards. Create a new Age value 306 // the queue will be logically empty afterwards. Create a new Age value
238 // that represents the empty queue for the given value of "_bottom". (We 307 // that represents the empty queue for the given value of "_bottom". (We
239 // must also increment "tag" because of the case where "bottom == 1", 308 // must also increment "tag" because of the case where "bottom == 1",
249 // install new_age, thus claiming the element. 318 // install new_age, thus claiming the element.
250 Age tempAge = _age.cmpxchg(newAge, oldAge); 319 Age tempAge = _age.cmpxchg(newAge, oldAge);
251 if (tempAge == oldAge) { 320 if (tempAge == oldAge) {
252 // We win. 321 // We win.
253 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); 322 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
323 TASKQUEUE_STATS_ONLY(stats.record_pop_slow());
254 return true; 324 return true;
255 } 325 }
256 } 326 }
257 // We lose; a completing pop_global gets the element. But the queue is empty 327 // We lose; a completing pop_global gets the element. But the queue is empty
258 // and top is greater than bottom. Fix this representation of the empty queue 328 // and top is greater than bottom. Fix this representation of the empty queue
304 { 374 {
305 public: 375 public:
306 typedef GrowableArray<E> overflow_t; 376 typedef GrowableArray<E> overflow_t;
307 typedef GenericTaskQueue<E, N> taskqueue_t; 377 typedef GenericTaskQueue<E, N> taskqueue_t;
308 378
379 TASKQUEUE_STATS_ONLY(using taskqueue_t::stats;)
380
309 OverflowTaskQueue(); 381 OverflowTaskQueue();
310 ~OverflowTaskQueue(); 382 ~OverflowTaskQueue();
311 void initialize(); 383 void initialize();
312 384
313 inline overflow_t* overflow_stack() const { return _overflow_stack; } 385 inline overflow_t* overflow_stack() const { return _overflow_stack; }
354 template <class E, unsigned int N> 426 template <class E, unsigned int N>
355 bool OverflowTaskQueue<E, N>::push(E t) 427 bool OverflowTaskQueue<E, N>::push(E t)
356 { 428 {
357 if (!taskqueue_t::push(t)) { 429 if (!taskqueue_t::push(t)) {
358 overflow_stack()->push(t); 430 overflow_stack()->push(t);
431 TASKQUEUE_STATS_ONLY(stats.record_overflow(overflow_stack()->length()));
359 } 432 }
360 return true; 433 return true;
361 } 434 }
362 435
363 template <class E, unsigned int N> 436 template <class E, unsigned int N>
422 return _queues[i]; 495 return _queues[i];
423 } 496 }
424 497
425 template<class T> bool 498 template<class T> bool
426 GenericTaskQueueSet<T>::steal(uint queue_num, int* seed, E& t) { 499 GenericTaskQueueSet<T>::steal(uint queue_num, int* seed, E& t) {
427 for (uint i = 0; i < 2 * _n; i++) 500 for (uint i = 0; i < 2 * _n; i++) {
428 if (steal_best_of_2(queue_num, seed, t)) 501 if (steal_best_of_2(queue_num, seed, t)) {
502 TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(true));
429 return true; 503 return true;
504 }
505 }
506 TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(false));
430 return false; 507 return false;
431 } 508 }
432 509
433 template<class T> bool 510 template<class T> bool
434 GenericTaskQueueSet<T>::steal_best_of_all(uint queue_num, int* seed, E& t) { 511 GenericTaskQueueSet<T>::steal_best_of_all(uint queue_num, int* seed, E& t) {
572 assert(dirty_n_elems < N, "n_elems out of range."); 649 assert(dirty_n_elems < N, "n_elems out of range.");
573 if (dirty_n_elems < max_elems()) { 650 if (dirty_n_elems < max_elems()) {
574 // g++ complains if the volatile result of the assignment is unused. 651 // g++ complains if the volatile result of the assignment is unused.
575 const_cast<E&>(_elems[localBot] = t); 652 const_cast<E&>(_elems[localBot] = t);
576 OrderAccess::release_store(&_bottom, increment_index(localBot)); 653 OrderAccess::release_store(&_bottom, increment_index(localBot));
654 TASKQUEUE_STATS_ONLY(stats.record_push());
577 return true; 655 return true;
578 } else { 656 } else {
579 return push_slow(t, dirty_n_elems); 657 return push_slow(t, dirty_n_elems);
580 } 658 }
581 } 659 }
601 // "_bottom" and "age" we've read, then there can be no interference with 679 // "_bottom" and "age" we've read, then there can be no interference with
602 // a "pop_global" operation, and we're done. 680 // a "pop_global" operation, and we're done.
603 idx_t tp = _age.top(); // XXX 681 idx_t tp = _age.top(); // XXX
604 if (size(localBot, tp) > 0) { 682 if (size(localBot, tp) > 0) {
605 assert(dirty_size(localBot, tp) != N - 1, "sanity"); 683 assert(dirty_size(localBot, tp) != N - 1, "sanity");
684 TASKQUEUE_STATS_ONLY(stats.record_pop());
606 return true; 685 return true;
607 } else { 686 } else {
608 // Otherwise, the queue contained exactly one element; we take the slow 687 // Otherwise, the queue contained exactly one element; we take the slow
609 // path. 688 // path.
610 return pop_local_slow(localBot, _age.get()); 689 return pop_local_slow(localBot, _age.get());