1.1 --- a/src/share/vm/utilities/taskqueue.hpp Fri Jul 16 10:09:15 2010 -0700 1.2 +++ b/src/share/vm/utilities/taskqueue.hpp Fri Jul 16 21:33:21 2010 -0700 1.3 @@ -22,6 +22,72 @@ 1.4 * 1.5 */ 1.6 1.7 +// Simple TaskQueue stats that are collected by default in debug builds. 1.8 + 1.9 +#if !defined(TASKQUEUE_STATS) && defined(ASSERT) 1.10 +#define TASKQUEUE_STATS 1 1.11 +#elif !defined(TASKQUEUE_STATS) 1.12 +#define TASKQUEUE_STATS 0 1.13 +#endif 1.14 + 1.15 +#if TASKQUEUE_STATS 1.16 +#define TASKQUEUE_STATS_ONLY(code) code 1.17 +#else 1.18 +#define TASKQUEUE_STATS_ONLY(code) 1.19 +#endif // TASKQUEUE_STATS 1.20 + 1.21 +#if TASKQUEUE_STATS 1.22 +class TaskQueueStats { 1.23 +public: 1.24 + enum StatId { 1.25 + push, // number of taskqueue pushes 1.26 + pop, // number of taskqueue pops 1.27 + pop_slow, // subset of taskqueue pops that were done slow-path 1.28 + steal_attempt, // number of taskqueue steal attempts 1.29 + steal, // number of taskqueue steals 1.30 + overflow, // number of overflow pushes 1.31 + overflow_max_len, // max length of overflow stack 1.32 + last_stat_id 1.33 + }; 1.34 + 1.35 +public: 1.36 + inline TaskQueueStats() { reset(); } 1.37 + 1.38 + inline void record_push() { ++_stats[push]; } 1.39 + inline void record_pop() { ++_stats[pop]; } 1.40 + inline void record_pop_slow() { record_pop(); ++_stats[pop_slow]; } 1.41 + inline void record_steal(bool success); 1.42 + inline void record_overflow(size_t new_length); 1.43 + 1.44 + inline size_t get(StatId id) const { return _stats[id]; } 1.45 + inline const size_t* get() const { return _stats; } 1.46 + 1.47 + inline void reset(); 1.48 + 1.49 + static void print_header(unsigned int line, outputStream* const stream = tty, 1.50 + unsigned int width = 10); 1.51 + void print(outputStream* const stream = tty, unsigned int width = 10) const; 1.52 + 1.53 +private: 1.54 + size_t _stats[last_stat_id]; 1.55 + static const char * const _names[last_stat_id]; 1.56 +}; 1.57 + 1.58 +void TaskQueueStats::record_steal(bool success) { 1.59 + ++_stats[steal_attempt]; 1.60 + if (success) ++_stats[steal]; 1.61 +} 1.62 + 1.63 +void TaskQueueStats::record_overflow(size_t new_len) { 1.64 + ++_stats[overflow]; 1.65 + if (new_len > _stats[overflow_max_len]) _stats[overflow_max_len] = new_len; 1.66 +} 1.67 + 1.68 +void TaskQueueStats::reset() { 1.69 + memset(_stats, 0, sizeof(_stats)); 1.70 +} 1.71 +#endif // TASKQUEUE_STATS 1.72 + 1.73 template <unsigned int N> 1.74 class TaskQueueSuper: public CHeapObj { 1.75 protected: 1.76 @@ -135,6 +201,8 @@ 1.77 1.78 // Total size of queue. 1.79 static const uint total_size() { return N; } 1.80 + 1.81 + TASKQUEUE_STATS_ONLY(TaskQueueStats stats;) 1.82 }; 1.83 1.84 template<class E, unsigned int N = TASKQUEUE_SIZE> 1.85 @@ -152,6 +220,7 @@ 1.86 public: 1.87 using TaskQueueSuper<N>::max_elems; 1.88 using TaskQueueSuper<N>::size; 1.89 + TASKQUEUE_STATS_ONLY(using TaskQueueSuper<N>::stats;) 1.90 1.91 private: 1.92 // Slow paths for push, pop_local. (pop_global has no fast path.) 1.93 @@ -224,14 +293,14 @@ 1.94 // g++ complains if the volatile result of the assignment is unused. 1.95 const_cast<E&>(_elems[localBot] = t); 1.96 OrderAccess::release_store(&_bottom, increment_index(localBot)); 1.97 + TASKQUEUE_STATS_ONLY(stats.record_push()); 1.98 return true; 1.99 } 1.100 return false; 1.101 } 1.102 1.103 template<class E, unsigned int N> 1.104 -bool GenericTaskQueue<E, N>:: 1.105 -pop_local_slow(uint localBot, Age oldAge) { 1.106 +bool GenericTaskQueue<E, N>::pop_local_slow(uint localBot, Age oldAge) { 1.107 // This queue was observed to contain exactly one element; either this 1.108 // thread will claim it, or a competing "pop_global". In either case, 1.109 // the queue will be logically empty afterwards. Create a new Age value 1.110 @@ -251,6 +320,7 @@ 1.111 if (tempAge == oldAge) { 1.112 // We win. 1.113 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); 1.114 + TASKQUEUE_STATS_ONLY(stats.record_pop_slow()); 1.115 return true; 1.116 } 1.117 } 1.118 @@ -306,6 +376,8 @@ 1.119 typedef GrowableArray<E> overflow_t; 1.120 typedef GenericTaskQueue<E, N> taskqueue_t; 1.121 1.122 + TASKQUEUE_STATS_ONLY(using taskqueue_t::stats;) 1.123 + 1.124 OverflowTaskQueue(); 1.125 ~OverflowTaskQueue(); 1.126 void initialize(); 1.127 @@ -356,6 +428,7 @@ 1.128 { 1.129 if (!taskqueue_t::push(t)) { 1.130 overflow_stack()->push(t); 1.131 + TASKQUEUE_STATS_ONLY(stats.record_overflow(overflow_stack()->length())); 1.132 } 1.133 return true; 1.134 } 1.135 @@ -424,9 +497,13 @@ 1.136 1.137 template<class T> bool 1.138 GenericTaskQueueSet<T>::steal(uint queue_num, int* seed, E& t) { 1.139 - for (uint i = 0; i < 2 * _n; i++) 1.140 - if (steal_best_of_2(queue_num, seed, t)) 1.141 + for (uint i = 0; i < 2 * _n; i++) { 1.142 + if (steal_best_of_2(queue_num, seed, t)) { 1.143 + TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(true)); 1.144 return true; 1.145 + } 1.146 + } 1.147 + TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(false)); 1.148 return false; 1.149 } 1.150 1.151 @@ -574,6 +651,7 @@ 1.152 // g++ complains if the volatile result of the assignment is unused. 1.153 const_cast<E&>(_elems[localBot] = t); 1.154 OrderAccess::release_store(&_bottom, increment_index(localBot)); 1.155 + TASKQUEUE_STATS_ONLY(stats.record_push()); 1.156 return true; 1.157 } else { 1.158 return push_slow(t, dirty_n_elems); 1.159 @@ -603,6 +681,7 @@ 1.160 idx_t tp = _age.top(); // XXX 1.161 if (size(localBot, tp) > 0) { 1.162 assert(dirty_size(localBot, tp) != N - 1, "sanity"); 1.163 + TASKQUEUE_STATS_ONLY(stats.record_pop()); 1.164 return true; 1.165 } else { 1.166 // Otherwise, the queue contained exactly one element; we take the slow