Mercurial > hg > truffle
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()); |