crossbeam-utils/src/backoff.rs
Line | Count | Source |
1 | | use crate::primitive::sync::atomic; |
2 | | use core::cell::Cell; |
3 | | use core::fmt; |
4 | | |
5 | | const SPIN_LIMIT: u32 = 6; |
6 | | const YIELD_LIMIT: u32 = 10; |
7 | | |
8 | | /// Performs exponential backoff in spin loops. |
9 | | /// |
10 | | /// Backing off in spin loops reduces contention and improves overall performance. |
11 | | /// |
12 | | /// This primitive can execute *YIELD* and *PAUSE* instructions, yield the current thread to the OS |
13 | | /// scheduler, and tell when is a good time to block the thread using a different synchronization |
14 | | /// mechanism. Each step of the back off procedure takes roughly twice as long as the previous |
15 | | /// step. |
16 | | /// |
17 | | /// # Examples |
18 | | /// |
19 | | /// Backing off in a lock-free loop: |
20 | | /// |
21 | | /// ``` |
22 | | /// use crossbeam_utils::Backoff; |
23 | | /// use std::sync::atomic::AtomicUsize; |
24 | | /// use std::sync::atomic::Ordering::SeqCst; |
25 | | /// |
26 | | /// fn fetch_mul(a: &AtomicUsize, b: usize) -> usize { |
27 | | /// let backoff = Backoff::new(); |
28 | | /// loop { |
29 | | /// let val = a.load(SeqCst); |
30 | | /// if a.compare_exchange(val, val.wrapping_mul(b), SeqCst, SeqCst).is_ok() { |
31 | | /// return val; |
32 | | /// } |
33 | | /// backoff.spin(); |
34 | | /// } |
35 | | /// } |
36 | | /// ``` |
37 | | /// |
38 | | /// Waiting for an [`AtomicBool`] to become `true`: |
39 | | /// |
40 | | /// ``` |
41 | | /// use crossbeam_utils::Backoff; |
42 | | /// use std::sync::atomic::AtomicBool; |
43 | | /// use std::sync::atomic::Ordering::SeqCst; |
44 | | /// |
45 | | /// fn spin_wait(ready: &AtomicBool) { |
46 | | /// let backoff = Backoff::new(); |
47 | | /// while !ready.load(SeqCst) { |
48 | | /// backoff.snooze(); |
49 | | /// } |
50 | | /// } |
51 | | /// ``` |
52 | | /// |
53 | | /// Waiting for an [`AtomicBool`] to become `true` and parking the thread after a long wait. |
54 | | /// Note that whoever sets the atomic variable to `true` must notify the parked thread by calling |
55 | | /// [`unpark()`]: |
56 | | /// |
57 | | /// ``` |
58 | | /// use crossbeam_utils::Backoff; |
59 | | /// use std::sync::atomic::AtomicBool; |
60 | | /// use std::sync::atomic::Ordering::SeqCst; |
61 | | /// use std::thread; |
62 | | /// |
63 | | /// fn blocking_wait(ready: &AtomicBool) { |
64 | | /// let backoff = Backoff::new(); |
65 | | /// while !ready.load(SeqCst) { |
66 | | /// if backoff.is_completed() { |
67 | | /// thread::park(); |
68 | | /// } else { |
69 | | /// backoff.snooze(); |
70 | | /// } |
71 | | /// } |
72 | | /// } |
73 | | /// ``` |
74 | | /// |
75 | | /// [`is_completed`]: Backoff::is_completed |
76 | | /// [`std::thread::park()`]: std::thread::park |
77 | | /// [`Condvar`]: std::sync::Condvar |
78 | | /// [`AtomicBool`]: std::sync::atomic::AtomicBool |
79 | | /// [`unpark()`]: std::thread::Thread::unpark |
80 | | pub struct Backoff { |
81 | | step: Cell<u32>, |
82 | | } |
83 | | |
84 | | impl Backoff { |
85 | | /// Creates a new `Backoff`. |
86 | | /// |
87 | | /// # Examples |
88 | | /// |
89 | | /// ``` |
90 | | /// use crossbeam_utils::Backoff; |
91 | | /// |
92 | | /// let backoff = Backoff::new(); |
93 | | /// ``` |
94 | | #[inline] |
95 | 117M | pub fn new() -> Self { |
96 | 117M | Backoff { step: Cell::new(0) } |
97 | 117M | } <crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 1.44M | pub fn new() -> Self { | 96 | 1.44M | Backoff { step: Cell::new(0) } | 97 | 1.44M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 1.61M | pub fn new() -> Self { | 96 | 1.61M | Backoff { step: Cell::new(0) } | 97 | 1.61M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 226k | pub fn new() -> Self { | 96 | 226k | Backoff { step: Cell::new(0) } | 97 | 226k | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 1.74M | pub fn new() -> Self { | 96 | 1.74M | Backoff { step: Cell::new(0) } | 97 | 1.74M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 25.6M | pub fn new() -> Self { | 96 | 25.6M | Backoff { step: Cell::new(0) } | 97 | 25.6M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 605k | pub fn new() -> Self { | 96 | 605k | Backoff { step: Cell::new(0) } | 97 | 605k | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 2.77M | pub fn new() -> Self { | 96 | 2.77M | Backoff { step: Cell::new(0) } | 97 | 2.77M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 201 | pub fn new() -> Self { | 96 | 201 | Backoff { step: Cell::new(0) } | 97 | 201 | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 1 | pub fn new() -> Self { | 96 | 1 | Backoff { step: Cell::new(0) } | 97 | 1 | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 5 | pub fn new() -> Self { | 96 | 5 | Backoff { step: Cell::new(0) } | 97 | 5 | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 1 | pub fn new() -> Self { | 96 | 1 | Backoff { step: Cell::new(0) } | 97 | 1 | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 1.39M | pub fn new() -> Self { | 96 | 1.39M | Backoff { step: Cell::new(0) } | 97 | 1.39M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 13 | pub fn new() -> Self { | 96 | 13 | Backoff { step: Cell::new(0) } | 97 | 13 | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 6 | pub fn new() -> Self { | 96 | 6 | Backoff { step: Cell::new(0) } | 97 | 6 | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 40 | pub fn new() -> Self { | 96 | 40 | Backoff { step: Cell::new(0) } | 97 | 40 | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 2.84M | pub fn new() -> Self { | 96 | 2.84M | Backoff { step: Cell::new(0) } | 97 | 2.84M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 4.57M | pub fn new() -> Self { | 96 | 4.57M | Backoff { step: Cell::new(0) } | 97 | 4.57M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 73.5M | pub fn new() -> Self { | 96 | 73.5M | Backoff { step: Cell::new(0) } | 97 | 73.5M | } |
<crossbeam_utils::backoff::Backoff>::new Line | Count | Source | 95 | 726k | pub fn new() -> Self { | 96 | 726k | Backoff { step: Cell::new(0) } | 97 | 726k | } |
|
98 | | |
99 | | /// Resets the `Backoff`. |
100 | | /// |
101 | | /// # Examples |
102 | | /// |
103 | | /// ``` |
104 | | /// use crossbeam_utils::Backoff; |
105 | | /// |
106 | | /// let backoff = Backoff::new(); |
107 | | /// backoff.reset(); |
108 | | /// ``` |
109 | | #[inline] |
110 | | pub fn reset(&self) { |
111 | | self.step.set(0); |
112 | | } |
113 | | |
114 | | /// Backs off in a lock-free loop. |
115 | | /// |
116 | | /// This method should be used when we need to retry an operation because another thread made |
117 | | /// progress. |
118 | | /// |
119 | | /// The processor may yield using the *YIELD* or *PAUSE* instruction. |
120 | | /// |
121 | | /// # Examples |
122 | | /// |
123 | | /// Backing off in a lock-free loop: |
124 | | /// |
125 | | /// ``` |
126 | | /// use crossbeam_utils::Backoff; |
127 | | /// use std::sync::atomic::AtomicUsize; |
128 | | /// use std::sync::atomic::Ordering::SeqCst; |
129 | | /// |
130 | | /// fn fetch_mul(a: &AtomicUsize, b: usize) -> usize { |
131 | | /// let backoff = Backoff::new(); |
132 | | /// loop { |
133 | | /// let val = a.load(SeqCst); |
134 | | /// if a.compare_exchange(val, val.wrapping_mul(b), SeqCst, SeqCst).is_ok() { |
135 | | /// return val; |
136 | | /// } |
137 | | /// backoff.spin(); |
138 | | /// } |
139 | | /// } |
140 | | /// |
141 | | /// let a = AtomicUsize::new(7); |
142 | | /// assert_eq!(fetch_mul(&a, 8), 7); |
143 | | /// assert_eq!(a.load(SeqCst), 56); |
144 | | /// ``` |
145 | | #[inline] |
146 | 684k | pub fn spin(&self) { |
147 | 3.19M | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)684k { |
148 | 3.19M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, |
149 | 3.19M | // use [`core::hint::spin_loop`] instead. |
150 | 3.19M | #[allow(deprecated)] |
151 | 3.19M | atomic::spin_loop_hint(); |
152 | 3.19M | } |
153 | | |
154 | 696k | if self.step.get() <= SPIN_LIMIT { |
155 | 636k | self.step.set(self.step.get() + 1); |
156 | 636k | }59.5k |
157 | 696k | } <crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 1.20k | pub fn spin(&self) { | 147 | 73.0k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)1.20k { | 148 | 73.0k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 73.0k | // use [`core::hint::spin_loop`] instead. | 150 | 73.0k | #[allow(deprecated)] | 151 | 73.0k | atomic::spin_loop_hint(); | 152 | 73.0k | } | 153 | | | 154 | 1.20k | if self.step.get() <= SPIN_LIMIT { | 155 | 81 | self.step.set(self.step.get() + 1); | 156 | 1.12k | } | 157 | 1.20k | } |
<crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 262 | pub fn spin(&self) { | 147 | 262 | for _ in 0..1 << self.step.get().min(SPIN_LIMIT) { | 148 | 262 | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 262 | // use [`core::hint::spin_loop`] instead. | 150 | 262 | #[allow(deprecated)] | 151 | 262 | atomic::spin_loop_hint(); | 152 | 262 | } | 153 | | | 154 | 262 | if self.step.get() <= SPIN_LIMIT { | 155 | 262 | self.step.set(self.step.get() + 1); | 156 | 262 | }0 | 157 | 262 | } |
<crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 16.9k | pub fn spin(&self) { | 147 | 605k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)16.9k { | 148 | 605k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 605k | // use [`core::hint::spin_loop`] instead. | 150 | 605k | #[allow(deprecated)] | 151 | 605k | atomic::spin_loop_hint(); | 152 | 605k | } | 153 | | | 154 | 17.0k | if self.step.get() <= SPIN_LIMIT { | 155 | 1.71k | self.step.set(self.step.get() + 1); | 156 | 15.3k | } | 157 | 17.0k | } |
<crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 34.0k | pub fn spin(&self) { | 147 | 35.1k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)34.0k { | 148 | 35.1k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 35.1k | // use [`core::hint::spin_loop`] instead. | 150 | 35.1k | #[allow(deprecated)] | 151 | 35.1k | atomic::spin_loop_hint(); | 152 | 35.1k | } | 153 | | | 154 | 34.1k | if self.step.get() <= SPIN_LIMIT { | 155 | 34.1k | self.step.set(self.step.get() + 1); | 156 | 34.1k | }4 | 157 | 34.1k | } |
<crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 18.5k | pub fn spin(&self) { | 147 | 495k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)18.5k { | 148 | 495k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 495k | // use [`core::hint::spin_loop`] instead. | 150 | 495k | #[allow(deprecated)] | 151 | 495k | atomic::spin_loop_hint(); | 152 | 495k | } | 153 | | | 154 | 18.5k | if self.step.get() <= SPIN_LIMIT { | 155 | 1.60k | self.step.set(self.step.get() + 1); | 156 | 16.9k | } | 157 | 18.5k | } |
Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::spin <crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 151k | pub fn spin(&self) { | 147 | 266k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)151k { | 148 | 266k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 266k | // use [`core::hint::spin_loop`] instead. | 150 | 266k | #[allow(deprecated)] | 151 | 266k | atomic::spin_loop_hint(); | 152 | 266k | } | 153 | | | 154 | 152k | if self.step.get() <= SPIN_LIMIT { | 155 | 151k | self.step.set(self.step.get() + 1); | 156 | 151k | }883 | 157 | 152k | } |
<crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 1 | pub fn spin(&self) { | 147 | 1 | for _ in 0..1 << self.step.get().min(SPIN_LIMIT) { | 148 | 1 | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 1 | // use [`core::hint::spin_loop`] instead. | 150 | 1 | #[allow(deprecated)] | 151 | 1 | atomic::spin_loop_hint(); | 152 | 1 | } | 153 | | | 154 | 1 | if self.step.get() <= SPIN_LIMIT { | 155 | 1 | self.step.set(self.step.get() + 1); | 156 | 1 | }0 | 157 | 1 | } |
Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::spin Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::spin Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::spin <crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 86.8k | pub fn spin(&self) { | 147 | 269k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)86.8k { | 148 | 269k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 269k | // use [`core::hint::spin_loop`] instead. | 150 | 269k | #[allow(deprecated)] | 151 | 269k | atomic::spin_loop_hint(); | 152 | 269k | } | 153 | | | 154 | 87.7k | if self.step.get() <= SPIN_LIMIT { | 155 | 86.2k | self.step.set(self.step.get() + 1); | 156 | 86.2k | }1.49k | 157 | 87.7k | } |
Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::spin Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::spin <crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 37.9k | pub fn spin(&self) { | 147 | 992k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)37.9k { | 148 | 992k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 992k | // use [`core::hint::spin_loop`] instead. | 150 | 992k | #[allow(deprecated)] | 151 | 992k | atomic::spin_loop_hint(); | 152 | 992k | } | 153 | | | 154 | 38.2k | if self.step.get() <= SPIN_LIMIT { | 155 | 17.3k | self.step.set(self.step.get() + 1); | 156 | 20.9k | } | 157 | 38.2k | } |
<crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 232k | pub fn spin(&self) { | 147 | 348k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)232k { | 148 | 348k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 348k | // use [`core::hint::spin_loop`] instead. | 150 | 348k | #[allow(deprecated)] | 151 | 348k | atomic::spin_loop_hint(); | 152 | 348k | } | 153 | | | 154 | 241k | if self.step.get() <= SPIN_LIMIT { | 155 | 238k | self.step.set(self.step.get() + 1); | 156 | 238k | }2.77k | 157 | 241k | } |
<crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 99.4k | pub fn spin(&self) { | 147 | 100k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)99.4k { | 148 | 100k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 100k | // use [`core::hint::spin_loop`] instead. | 150 | 100k | #[allow(deprecated)] | 151 | 100k | atomic::spin_loop_hint(); | 152 | 100k | } | 153 | | | 154 | 99.4k | if self.step.get() <= SPIN_LIMIT { | 155 | 99.4k | self.step.set(self.step.get() + 1); | 156 | 99.4k | }16 | 157 | 99.4k | } |
<crossbeam_utils::backoff::Backoff>::spin Line | Count | Source | 146 | 5.40k | pub fn spin(&self) { | 147 | 6.51k | for _ in 0..1 << self.step.get().min(SPIN_LIMIT)5.40k { | 148 | 6.51k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 149 | 6.51k | // use [`core::hint::spin_loop`] instead. | 150 | 6.51k | #[allow(deprecated)] | 151 | 6.51k | atomic::spin_loop_hint(); | 152 | 6.51k | } | 153 | | | 154 | 5.41k | if self.step.get() <= SPIN_LIMIT { | 155 | 5.40k | self.step.set(self.step.get() + 1); | 156 | 5.40k | }5 | 157 | 5.41k | } |
|
158 | | |
159 | | /// Backs off in a blocking loop. |
160 | | /// |
161 | | /// This method should be used when we need to wait for another thread to make progress. |
162 | | /// |
163 | | /// The processor may yield using the *YIELD* or *PAUSE* instruction and the current thread |
164 | | /// may yield by giving up a timeslice to the OS scheduler. |
165 | | /// |
166 | | /// In `#[no_std]` environments, this method is equivalent to [`spin`]. |
167 | | /// |
168 | | /// If possible, use [`is_completed`] to check when it is advised to stop using backoff and |
169 | | /// block the current thread using a different synchronization mechanism instead. |
170 | | /// |
171 | | /// [`spin`]: Backoff::spin |
172 | | /// [`is_completed`]: Backoff::is_completed |
173 | | /// |
174 | | /// # Examples |
175 | | /// |
176 | | /// Waiting for an [`AtomicBool`] to become `true`: |
177 | | /// |
178 | | /// ``` |
179 | | /// use crossbeam_utils::Backoff; |
180 | | /// use std::sync::Arc; |
181 | | /// use std::sync::atomic::AtomicBool; |
182 | | /// use std::sync::atomic::Ordering::SeqCst; |
183 | | /// use std::thread; |
184 | | /// use std::time::Duration; |
185 | | /// |
186 | | /// fn spin_wait(ready: &AtomicBool) { |
187 | | /// let backoff = Backoff::new(); |
188 | | /// while !ready.load(SeqCst) { |
189 | | /// backoff.snooze(); |
190 | | /// } |
191 | | /// } |
192 | | /// |
193 | | /// let ready = Arc::new(AtomicBool::new(false)); |
194 | | /// let ready2 = ready.clone(); |
195 | | /// |
196 | | /// thread::spawn(move || { |
197 | | /// thread::sleep(Duration::from_millis(100)); |
198 | | /// ready2.store(true, SeqCst); |
199 | | /// }); |
200 | | /// |
201 | | /// assert_eq!(ready.load(SeqCst), false); |
202 | | /// spin_wait(&ready); |
203 | | /// assert_eq!(ready.load(SeqCst), true); |
204 | | /// ``` |
205 | | /// |
206 | | /// [`AtomicBool`]: std::sync::atomic::AtomicBool |
207 | | #[inline] |
208 | 19.2M | pub fn snooze(&self) { |
209 | 19.2M | if self.step.get() <= SPIN_LIMIT { |
210 | 46.0M | for _ in 0..1 << self.step.get()18.7M { |
211 | 46.0M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, |
212 | 46.0M | // use [`core::hint::spin_loop`] instead. |
213 | 46.0M | #[allow(deprecated)] |
214 | 46.0M | atomic::spin_loop_hint(); |
215 | 46.0M | } |
216 | 505k | } else { |
217 | 505k | #[cfg(not(feature = "std"))] |
218 | 505k | for _ in 0..1 << self.step.get() { |
219 | 505k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, |
220 | 505k | // use [`core::hint::spin_loop`] instead. |
221 | 505k | #[allow(deprecated)] |
222 | 505k | atomic::spin_loop_hint(); |
223 | 505k | } |
224 | 505k | |
225 | 505k | #[cfg(feature = "std")] |
226 | 505k | ::std::thread::yield_now(); |
227 | 505k | } |
228 | | |
229 | 20.1M | if self.step.get() <= YIELD_LIMIT { |
230 | 19.8M | self.step.set(self.step.get() + 1); |
231 | 19.8M | }319k |
232 | 20.1M | } <crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 5.88k | pub fn snooze(&self) { | 209 | 5.88k | if self.step.get() <= SPIN_LIMIT { | 210 | 8.02k | for _ in 0..1 << self.step.get()5.89k { | 211 | 8.02k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 8.02k | // use [`core::hint::spin_loop`] instead. | 213 | 8.02k | #[allow(deprecated)] | 214 | 8.02k | atomic::spin_loop_hint(); | 215 | 8.02k | } | 216 | 18.4E | } else { | 217 | 18.4E | #[cfg(not(feature = "std"))] | 218 | 18.4E | for _ in 0..1 << self.step.get() { | 219 | 18.4E | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 18.4E | // use [`core::hint::spin_loop`] instead. | 221 | 18.4E | #[allow(deprecated)] | 222 | 18.4E | atomic::spin_loop_hint(); | 223 | 18.4E | } | 224 | 18.4E | | 225 | 18.4E | #[cfg(feature = "std")] | 226 | 18.4E | ::std::thread::yield_now(); | 227 | 18.4E | } | 228 | | | 229 | 6.63k | if self.step.get() <= YIELD_LIMIT { | 230 | 6.54k | self.step.set(self.step.get() + 1); | 231 | 6.54k | }90 | 232 | 6.63k | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 2.35M | pub fn snooze(&self) { | 209 | 2.35M | if self.step.get() <= SPIN_LIMIT { | 210 | 6.31M | for _ in 0..1 << self.step.get()2.15M { | 211 | 6.31M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 6.31M | // use [`core::hint::spin_loop`] instead. | 213 | 6.31M | #[allow(deprecated)] | 214 | 6.31M | atomic::spin_loop_hint(); | 215 | 6.31M | } | 216 | 198k | } else { | 217 | 198k | #[cfg(not(feature = "std"))] | 218 | 198k | for _ in 0..1 << self.step.get() { | 219 | 198k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 198k | // use [`core::hint::spin_loop`] instead. | 221 | 198k | #[allow(deprecated)] | 222 | 198k | atomic::spin_loop_hint(); | 223 | 198k | } | 224 | 198k | | 225 | 198k | #[cfg(feature = "std")] | 226 | 198k | ::std::thread::yield_now(); | 227 | 198k | } | 228 | | | 229 | 2.48M | if self.step.get() <= YIELD_LIMIT { | 230 | 2.27M | self.step.set(self.step.get() + 1); | 231 | 2.27M | }203k | 232 | 2.48M | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 277k | pub fn snooze(&self) { | 209 | 277k | if self.step.get() <= SPIN_LIMIT { | 210 | 2.27M | for _ in 0..1 << self.step.get()256k { | 211 | 2.27M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 2.27M | // use [`core::hint::spin_loop`] instead. | 213 | 2.27M | #[allow(deprecated)] | 214 | 2.27M | atomic::spin_loop_hint(); | 215 | 2.27M | } | 216 | 21.6k | } else { | 217 | 21.6k | #[cfg(not(feature = "std"))] | 218 | 21.6k | for _ in 0..1 << self.step.get() { | 219 | 21.6k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 21.6k | // use [`core::hint::spin_loop`] instead. | 221 | 21.6k | #[allow(deprecated)] | 222 | 21.6k | atomic::spin_loop_hint(); | 223 | 21.6k | } | 224 | 21.6k | | 225 | 21.6k | #[cfg(feature = "std")] | 226 | 21.6k | ::std::thread::yield_now(); | 227 | 21.6k | } | 228 | | | 229 | 278k | if self.step.get() <= YIELD_LIMIT { | 230 | 278k | self.step.set(self.step.get() + 1); | 231 | 278k | }43 | 232 | 278k | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 312 | pub fn snooze(&self) { | 209 | 312 | if self.step.get() <= SPIN_LIMIT { | 210 | 533 | for _ in 0..1 << self.step.get()67 { | 211 | 533 | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 533 | // use [`core::hint::spin_loop`] instead. | 213 | 533 | #[allow(deprecated)] | 214 | 533 | atomic::spin_loop_hint(); | 215 | 533 | } | 216 | 245 | } else { | 217 | 245 | #[cfg(not(feature = "std"))] | 218 | 245 | for _ in 0..1 << self.step.get() { | 219 | 245 | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 245 | // use [`core::hint::spin_loop`] instead. | 221 | 245 | #[allow(deprecated)] | 222 | 245 | atomic::spin_loop_hint(); | 223 | 245 | } | 224 | 245 | | 225 | 245 | #[cfg(feature = "std")] | 226 | 245 | ::std::thread::yield_now(); | 227 | 245 | } | 228 | | | 229 | 312 | if self.step.get() <= YIELD_LIMIT { | 230 | 303 | self.step.set(self.step.get() + 1); | 231 | 303 | }9 | 232 | 312 | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 8.37M | pub fn snooze(&self) { | 209 | 8.37M | if self.step.get() <= SPIN_LIMIT { | 210 | 13.6M | for _ in 0..1 << self.step.get()8.34M { | 211 | 13.6M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 13.6M | // use [`core::hint::spin_loop`] instead. | 213 | 13.6M | #[allow(deprecated)] | 214 | 13.6M | atomic::spin_loop_hint(); | 215 | 13.6M | } | 216 | 26.4k | } else { | 217 | 26.4k | #[cfg(not(feature = "std"))] | 218 | 26.4k | for _ in 0..1 << self.step.get() { | 219 | 26.4k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 26.4k | // use [`core::hint::spin_loop`] instead. | 221 | 26.4k | #[allow(deprecated)] | 222 | 26.4k | atomic::spin_loop_hint(); | 223 | 26.4k | } | 224 | 26.4k | | 225 | 26.4k | #[cfg(feature = "std")] | 226 | 26.4k | ::std::thread::yield_now(); | 227 | 26.4k | } | 228 | | | 229 | 8.68M | if self.step.get() <= YIELD_LIMIT { | 230 | 8.58M | self.step.set(self.step.get() + 1); | 231 | 8.58M | }92.0k | 232 | 8.68M | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 217k | pub fn snooze(&self) { | 209 | 217k | if self.step.get() <= SPIN_LIMIT { | 210 | 651k | for _ in 0..1 << self.step.get()212k { | 211 | 651k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 651k | // use [`core::hint::spin_loop`] instead. | 213 | 651k | #[allow(deprecated)] | 214 | 651k | atomic::spin_loop_hint(); | 215 | 651k | } | 216 | 4.68k | } else { | 217 | 4.68k | #[cfg(not(feature = "std"))] | 218 | 4.68k | for _ in 0..1 << self.step.get() { | 219 | 4.68k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 4.68k | // use [`core::hint::spin_loop`] instead. | 221 | 4.68k | #[allow(deprecated)] | 222 | 4.68k | atomic::spin_loop_hint(); | 223 | 4.68k | } | 224 | 4.68k | | 225 | 4.68k | #[cfg(feature = "std")] | 226 | 4.68k | ::std::thread::yield_now(); | 227 | 4.68k | } | 228 | | | 229 | 234k | if self.step.get() <= YIELD_LIMIT { | 230 | 229k | self.step.set(self.step.get() + 1); | 231 | 229k | }4.67k | 232 | 234k | } |
Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze <crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 196k | pub fn snooze(&self) { | 209 | 196k | if self.step.get() <= SPIN_LIMIT { | 210 | 1.68M | for _ in 0..1 << self.step.get()191k { | 211 | 1.68M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 1.68M | // use [`core::hint::spin_loop`] instead. | 213 | 1.68M | #[allow(deprecated)] | 214 | 1.68M | atomic::spin_loop_hint(); | 215 | 1.68M | } | 216 | 5.53k | } else { | 217 | 5.53k | #[cfg(not(feature = "std"))] | 218 | 5.53k | for _ in 0..1 << self.step.get() { | 219 | 5.53k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 5.53k | // use [`core::hint::spin_loop`] instead. | 221 | 5.53k | #[allow(deprecated)] | 222 | 5.53k | atomic::spin_loop_hint(); | 223 | 5.53k | } | 224 | 5.53k | | 225 | 5.53k | #[cfg(feature = "std")] | 226 | 5.53k | ::std::thread::yield_now(); | 227 | 5.53k | } | 228 | | | 229 | 197k | if self.step.get() <= YIELD_LIMIT { | 230 | 197k | self.step.set(self.step.get() + 1); | 231 | 197k | }408 | 232 | 197k | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 47 | pub fn snooze(&self) { | 209 | 47 | if self.step.get() <= SPIN_LIMIT { | 210 | 412 | for _ in 0..1 << self.step.get()33 { | 211 | 412 | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 412 | // use [`core::hint::spin_loop`] instead. | 213 | 412 | #[allow(deprecated)] | 214 | 412 | atomic::spin_loop_hint(); | 215 | 412 | } | 216 | 14 | } else { | 217 | 14 | #[cfg(not(feature = "std"))] | 218 | 14 | for _ in 0..1 << self.step.get() { | 219 | 14 | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 14 | // use [`core::hint::spin_loop`] instead. | 221 | 14 | #[allow(deprecated)] | 222 | 14 | atomic::spin_loop_hint(); | 223 | 14 | } | 224 | 14 | | 225 | 14 | #[cfg(feature = "std")] | 226 | 14 | ::std::thread::yield_now(); | 227 | 14 | } | 228 | | | 229 | 45 | if self.step.get() <= YIELD_LIMIT { | 230 | 45 | self.step.set(self.step.get() + 1); | 231 | 45 | }0 | 232 | 45 | } |
Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze <crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 19.1k | pub fn snooze(&self) { | 209 | 19.1k | if self.step.get() <= SPIN_LIMIT { | 210 | 167k | for _ in 0..1 << self.step.get()17.1k { | 211 | 167k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 167k | // use [`core::hint::spin_loop`] instead. | 213 | 167k | #[allow(deprecated)] | 214 | 167k | atomic::spin_loop_hint(); | 215 | 167k | } | 216 | 2.01k | } else { | 217 | 2.01k | #[cfg(not(feature = "std"))] | 218 | 2.01k | for _ in 0..1 << self.step.get() { | 219 | 2.01k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 2.01k | // use [`core::hint::spin_loop`] instead. | 221 | 2.01k | #[allow(deprecated)] | 222 | 2.01k | atomic::spin_loop_hint(); | 223 | 2.01k | } | 224 | 2.01k | | 225 | 2.01k | #[cfg(feature = "std")] | 226 | 2.01k | ::std::thread::yield_now(); | 227 | 2.01k | } | 228 | | | 229 | 19.3k | if self.step.get() <= YIELD_LIMIT { | 230 | 19.1k | self.step.set(self.step.get() + 1); | 231 | 19.1k | }127 | 232 | 19.3k | } |
Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze Unexecuted instantiation: <crossbeam_utils::backoff::Backoff>::snooze <crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 151k | pub fn snooze(&self) { | 209 | 151k | if self.step.get() <= SPIN_LIMIT { | 210 | 1.41M | for _ in 0..1 << self.step.get()124k { | 211 | 1.41M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 1.41M | // use [`core::hint::spin_loop`] instead. | 213 | 1.41M | #[allow(deprecated)] | 214 | 1.41M | atomic::spin_loop_hint(); | 215 | 1.41M | } | 216 | 26.8k | } else { | 217 | 26.8k | #[cfg(not(feature = "std"))] | 218 | 26.8k | for _ in 0..1 << self.step.get() { | 219 | 26.8k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 26.8k | // use [`core::hint::spin_loop`] instead. | 221 | 26.8k | #[allow(deprecated)] | 222 | 26.8k | atomic::spin_loop_hint(); | 223 | 26.8k | } | 224 | 26.8k | | 225 | 26.8k | #[cfg(feature = "std")] | 226 | 26.8k | ::std::thread::yield_now(); | 227 | 26.8k | } | 228 | | | 229 | 151k | if self.step.get() <= YIELD_LIMIT { | 230 | 151k | self.step.set(self.step.get() + 1); | 231 | 151k | }33 | 232 | 151k | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 1.78M | pub fn snooze(&self) { | 209 | 1.78M | if self.step.get() <= SPIN_LIMIT { | 210 | 8.76M | for _ in 0..1 << self.step.get()1.57M { | 211 | 8.76M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 8.76M | // use [`core::hint::spin_loop`] instead. | 213 | 8.76M | #[allow(deprecated)] | 214 | 8.76M | atomic::spin_loop_hint(); | 215 | 8.76M | } | 216 | 205k | } else { | 217 | 205k | #[cfg(not(feature = "std"))] | 218 | 205k | for _ in 0..1 << self.step.get() { | 219 | 205k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 205k | // use [`core::hint::spin_loop`] instead. | 221 | 205k | #[allow(deprecated)] | 222 | 205k | atomic::spin_loop_hint(); | 223 | 205k | } | 224 | 205k | | 225 | 205k | #[cfg(feature = "std")] | 226 | 205k | ::std::thread::yield_now(); | 227 | 205k | } | 228 | | | 229 | 1.86M | if self.step.get() <= YIELD_LIMIT1.84M { | 230 | 1.86M | self.step.set(self.step.get() + 1); | 231 | 18.4E | } | 232 | 1.84M | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 5.57M | pub fn snooze(&self) { | 209 | 5.57M | if self.step.get() <= SPIN_LIMIT { | 210 | 10.2M | for _ in 0..1 << self.step.get()5.56M { | 211 | 10.2M | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 10.2M | // use [`core::hint::spin_loop`] instead. | 213 | 10.2M | #[allow(deprecated)] | 214 | 10.2M | atomic::spin_loop_hint(); | 215 | 10.2M | } | 216 | 13.7k | } else { | 217 | 13.7k | #[cfg(not(feature = "std"))] | 218 | 13.7k | for _ in 0..1 << self.step.get() { | 219 | 13.7k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 13.7k | // use [`core::hint::spin_loop`] instead. | 221 | 13.7k | #[allow(deprecated)] | 222 | 13.7k | atomic::spin_loop_hint(); | 223 | 13.7k | } | 224 | 13.7k | | 225 | 13.7k | #[cfg(feature = "std")] | 226 | 13.7k | ::std::thread::yield_now(); | 227 | 13.7k | } | 228 | | | 229 | 5.89M | if self.step.get() <= YIELD_LIMIT { | 230 | 5.85M | self.step.set(self.step.get() + 1); | 231 | 5.85M | }36.2k | 232 | 5.89M | } |
<crossbeam_utils::backoff::Backoff>::snooze Line | Count | Source | 208 | 323k | pub fn snooze(&self) { | 209 | 323k | if self.step.get() <= SPIN_LIMIT { | 210 | 915k | for _ in 0..1 << self.step.get()322k { | 211 | 915k | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 212 | 915k | // use [`core::hint::spin_loop`] instead. | 213 | 915k | #[allow(deprecated)] | 214 | 915k | atomic::spin_loop_hint(); | 215 | 915k | } | 216 | 782 | } else { | 217 | 782 | #[cfg(not(feature = "std"))] | 218 | 782 | for _ in 0..1 << self.step.get() { | 219 | 782 | // TODO(taiki-e): once we bump the minimum required Rust version to 1.49+, | 220 | 782 | // use [`core::hint::spin_loop`] instead. | 221 | 782 | #[allow(deprecated)] | 222 | 782 | atomic::spin_loop_hint(); | 223 | 782 | } | 224 | 782 | | 225 | 782 | #[cfg(feature = "std")] | 226 | 782 | ::std::thread::yield_now(); | 227 | 782 | } | 228 | | | 229 | 343k | if self.step.get() <= YIELD_LIMIT { | 230 | 340k | self.step.set(self.step.get() + 1); | 231 | 340k | }3.64k | 232 | 343k | } |
|
233 | | |
234 | | /// Returns `true` if exponential backoff has completed and blocking the thread is advised. |
235 | | /// |
236 | | /// # Examples |
237 | | /// |
238 | | /// Waiting for an [`AtomicBool`] to become `true` and parking the thread after a long wait: |
239 | | /// |
240 | | /// ``` |
241 | | /// use crossbeam_utils::Backoff; |
242 | | /// use std::sync::Arc; |
243 | | /// use std::sync::atomic::AtomicBool; |
244 | | /// use std::sync::atomic::Ordering::SeqCst; |
245 | | /// use std::thread; |
246 | | /// use std::time::Duration; |
247 | | /// |
248 | | /// fn blocking_wait(ready: &AtomicBool) { |
249 | | /// let backoff = Backoff::new(); |
250 | | /// while !ready.load(SeqCst) { |
251 | | /// if backoff.is_completed() { |
252 | | /// thread::park(); |
253 | | /// } else { |
254 | | /// backoff.snooze(); |
255 | | /// } |
256 | | /// } |
257 | | /// } |
258 | | /// |
259 | | /// let ready = Arc::new(AtomicBool::new(false)); |
260 | | /// let ready2 = ready.clone(); |
261 | | /// let waiter = thread::current(); |
262 | | /// |
263 | | /// thread::spawn(move || { |
264 | | /// thread::sleep(Duration::from_millis(100)); |
265 | | /// ready2.store(true, SeqCst); |
266 | | /// waiter.unpark(); |
267 | | /// }); |
268 | | /// |
269 | | /// assert_eq!(ready.load(SeqCst), false); |
270 | | /// blocking_wait(&ready); |
271 | | /// assert_eq!(ready.load(SeqCst), true); |
272 | | /// ``` |
273 | | /// |
274 | | /// [`AtomicBool`]: std::sync::atomic::AtomicBool |
275 | | #[inline] |
276 | 7.55M | pub fn is_completed(&self) -> bool { |
277 | 7.55M | self.step.get() > YIELD_LIMIT |
278 | 7.55M | } <crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 1.02M | pub fn is_completed(&self) -> bool { | 277 | 1.02M | self.step.get() > YIELD_LIMIT | 278 | 1.02M | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 281k | pub fn is_completed(&self) -> bool { | 277 | 281k | self.step.get() > YIELD_LIMIT | 278 | 281k | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 1.96M | pub fn is_completed(&self) -> bool { | 277 | 1.96M | self.step.get() > YIELD_LIMIT | 278 | 1.96M | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 129k | pub fn is_completed(&self) -> bool { | 277 | 129k | self.step.get() > YIELD_LIMIT | 278 | 129k | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 192k | pub fn is_completed(&self) -> bool { | 277 | 192k | self.step.get() > YIELD_LIMIT | 278 | 192k | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 51 | pub fn is_completed(&self) -> bool { | 277 | 51 | self.step.get() > YIELD_LIMIT | 278 | 51 | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 148k | pub fn is_completed(&self) -> bool { | 277 | 148k | self.step.get() > YIELD_LIMIT | 278 | 148k | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 1.63M | pub fn is_completed(&self) -> bool { | 277 | 1.63M | self.step.get() > YIELD_LIMIT | 278 | 1.63M | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 2.00M | pub fn is_completed(&self) -> bool { | 277 | 2.00M | self.step.get() > YIELD_LIMIT | 278 | 2.00M | } |
<crossbeam_utils::backoff::Backoff>::is_completed Line | Count | Source | 276 | 177k | pub fn is_completed(&self) -> bool { | 277 | 177k | self.step.get() > YIELD_LIMIT | 278 | 177k | } |
|
279 | | } |
280 | | |
281 | | impl fmt::Debug for Backoff { |
282 | | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
283 | | f.debug_struct("Backoff") |
284 | | .field("step", &self.step) |
285 | | .field("is_completed", &self.is_completed()) |
286 | | .finish() |
287 | | } |
288 | | } |
289 | | |
290 | | impl Default for Backoff { |
291 | | fn default() -> Backoff { |
292 | | Backoff::new() |
293 | | } |
294 | | } |