comparison src/share/vm/utilities/taskqueue.cpp @ 546:05c6d52fa7a9

6690928: Use spinning in combination with yields for workstealing termination. Summary: Substitute a spin loop for most calls to yield() to reduce the stress on the system. Reviewed-by: tonyp
author jmasa
date Sun, 08 Feb 2009 13:18:01 -0800
parents 23673011938d
children 0fbdb4381b99
comparison
equal deleted inserted replaced
545:58054a18d735 546:05c6d52fa7a9
22 * 22 *
23 */ 23 */
24 24
25 # include "incls/_precompiled.incl" 25 # include "incls/_precompiled.incl"
26 # include "incls/_taskqueue.cpp.incl" 26 # include "incls/_taskqueue.cpp.incl"
27
28 #ifdef TRACESPINNING
29 uint ParallelTaskTerminator::_total_yields = 0;
30 uint ParallelTaskTerminator::_total_spins = 0;
31 uint ParallelTaskTerminator::_total_peeks = 0;
32 #endif
27 33
28 bool TaskQueueSuper::peek() { 34 bool TaskQueueSuper::peek() {
29 return _bottom != _age.top(); 35 return _bottom != _age.top();
30 } 36 }
31 37
68 bool 74 bool
69 ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) { 75 ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
70 Atomic::inc(&_offered_termination); 76 Atomic::inc(&_offered_termination);
71 77
72 uint yield_count = 0; 78 uint yield_count = 0;
79 // Number of hard spin loops done since last yield
80 uint hard_spin_count = 0;
81 // Number of iterations in the hard spin loop.
82 uint hard_spin_limit = WorkStealingHardSpins;
83
84 // If WorkStealingSpinToYieldRatio is 0, no hard spinning is done.
85 // If it is greater than 0, then start with a small number
86 // of spins and increase number with each turn at spinning until
87 // the count of hard spins exceeds WorkStealingSpinToYieldRatio.
88 // Then do a yield() call and start spinning afresh.
89 if (WorkStealingSpinToYieldRatio > 0) {
90 hard_spin_limit = WorkStealingHardSpins >> WorkStealingSpinToYieldRatio;
91 hard_spin_limit = MAX2(hard_spin_limit, 1U);
92 }
93 // Remember the initial spin limit.
94 uint hard_spin_start = hard_spin_limit;
95
96 // Loop waiting for all threads to offer termination or
97 // more work.
73 while (true) { 98 while (true) {
99 // Are all threads offering termination?
74 if (_offered_termination == _n_threads) { 100 if (_offered_termination == _n_threads) {
75 //inner_termination_loop();
76 return true; 101 return true;
77 } else { 102 } else {
103 // Look for more work.
104 // Periodically sleep() instead of yield() to give threads
105 // waiting on the cores the chance to grab this code
78 if (yield_count <= WorkStealingYieldsBeforeSleep) { 106 if (yield_count <= WorkStealingYieldsBeforeSleep) {
107 // Do a yield or hardspin. For purposes of deciding whether
108 // to sleep, count this as a yield.
79 yield_count++; 109 yield_count++;
80 yield(); 110
111 // Periodically call yield() instead spinning
112 // After WorkStealingSpinToYieldRatio spins, do a yield() call
113 // and reset the counts and starting limit.
114 if (hard_spin_count > WorkStealingSpinToYieldRatio) {
115 yield();
116 hard_spin_count = 0;
117 hard_spin_limit = hard_spin_start;
118 #ifdef TRACESPINNING
119 _total_yields++;
120 #endif
121 } else {
122 // Hard spin this time
123 // Increase the hard spinning period but only up to a limit.
124 hard_spin_limit = MIN2(2*hard_spin_limit,
125 (uint) WorkStealingHardSpins);
126 for (uint j = 0; j < hard_spin_limit; j++) {
127 SpinPause();
128 }
129 hard_spin_count++;
130 #ifdef TRACESPINNING
131 _total_spins++;
132 #endif
133 }
81 } else { 134 } else {
82 if (PrintGCDetails && Verbose) { 135 if (PrintGCDetails && Verbose) {
83 gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() " 136 gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() "
84 "thread %d sleeps after %d yields", 137 "thread %d sleeps after %d yields",
85 Thread::current(), yield_count); 138 Thread::current(), yield_count);
90 // which may only move the thread to the end of the this processor's 143 // which may only move the thread to the end of the this processor's
91 // runqueue). 144 // runqueue).
92 sleep(WorkStealingSleepMillis); 145 sleep(WorkStealingSleepMillis);
93 } 146 }
94 147
148 #ifdef TRACESPINNING
149 _total_peeks++;
150 #endif
95 if (peek_in_queue_set() || 151 if (peek_in_queue_set() ||
96 (terminator != NULL && terminator->should_exit_termination())) { 152 (terminator != NULL && terminator->should_exit_termination())) {
97 Atomic::dec(&_offered_termination); 153 Atomic::dec(&_offered_termination);
98 return false; 154 return false;
99 } 155 }
100 } 156 }
101 } 157 }
102 } 158 }
159
160 #ifdef TRACESPINNING
161 void ParallelTaskTerminator::print_termination_counts() {
162 gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %lld "
163 "Total spins: %lld Total peeks: %lld",
164 total_yields(),
165 total_spins(),
166 total_peeks());
167 }
168 #endif
103 169
104 void ParallelTaskTerminator::reset_for_reuse() { 170 void ParallelTaskTerminator::reset_for_reuse() {
105 if (_offered_termination != 0) { 171 if (_offered_termination != 0) {
106 assert(_offered_termination == _n_threads, 172 assert(_offered_termination == _n_threads,
107 "Terminator may still be in use"); 173 "Terminator may still be in use");