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