Skip to content

Commit 4bbddb8

Browse files
authored
Merge pull request #492 from stepancheg/bilock
BiLock bench and speed up
2 parents f6518de + 4ba6679 commit 4bbddb8

File tree

2 files changed

+99
-15
lines changed

2 files changed

+99
-15
lines changed

benches/bilock.rs

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#![feature(test)]
2+
3+
extern crate futures;
4+
extern crate test;
5+
6+
use futures::Async;
7+
use futures::executor;
8+
use futures::executor::{Notify, NotifyHandle};
9+
use futures::sync::BiLock;
10+
11+
12+
use test::Bencher;
13+
14+
fn notify_noop() -> NotifyHandle {
15+
struct Noop;
16+
17+
impl Notify for Noop {
18+
fn notify(&self, _id: usize) {}
19+
}
20+
21+
const NOOP : &'static Noop = &Noop;
22+
23+
NotifyHandle::from(NOOP)
24+
}
25+
26+
#[bench]
27+
fn contended(b: &mut Bencher) {
28+
b.iter(|| {
29+
let mut t = BiLock::new(1);
30+
for _ in 0..1000 {
31+
let (x, y) = t;
32+
let x_lock = match executor::spawn(x.lock()).poll_future_notify(&notify_noop(), 11).unwrap() {
33+
Async::Ready(lock) => lock,
34+
Async::NotReady => panic!(),
35+
};
36+
37+
// Try poll second lock while first lock still holds the lock
38+
let mut y = executor::spawn(y.lock());
39+
match y.poll_future_notify(&notify_noop(), 11).unwrap() {
40+
Async::Ready(_) => panic!(),
41+
Async::NotReady => (),
42+
};
43+
44+
let x = x_lock.unlock();
45+
46+
let y_lock = match y.poll_future_notify(&notify_noop(), 11).unwrap() {
47+
Async::Ready(lock) => lock,
48+
Async::NotReady => panic!(),
49+
};
50+
51+
let y = y_lock.unlock();
52+
t = (x, y);
53+
}
54+
t
55+
});
56+
}
57+
58+
#[bench]
59+
fn lock_unlock(b: &mut Bencher) {
60+
b.iter(|| {
61+
let mut t = BiLock::new(1);
62+
for _ in 0..1000 {
63+
let (x, y) = t;
64+
let x_lock = match executor::spawn(x.lock()).poll_future_notify(&notify_noop(), 11).unwrap() {
65+
Async::Ready(lock) => lock,
66+
Async::NotReady => panic!(),
67+
};
68+
69+
let x = x_lock.unlock();
70+
71+
let mut y = executor::spawn(y.lock());
72+
let y_lock = match y.poll_future_notify(&notify_noop(), 11).unwrap() {
73+
Async::Ready(lock) => lock,
74+
Async::NotReady => panic!(),
75+
};
76+
77+
let y = y_lock.unlock();
78+
t = (x, y);
79+
}
80+
t
81+
})
82+
}

src/sync/bilock.rs

+17-15
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ impl<T> BiLock<T> {
127127
/// Note that the returned future will never resolve to an error.
128128
pub fn lock(self) -> BiLockAcquire<T> {
129129
BiLockAcquire {
130-
inner: self,
130+
inner: Some(self),
131131
}
132132
}
133133

@@ -188,23 +188,21 @@ impl<'a, T> Drop for BiLockGuard<'a, T> {
188188
/// acquired.
189189
#[derive(Debug)]
190190
pub struct BiLockAcquire<T> {
191-
inner: BiLock<T>,
191+
inner: Option<BiLock<T>>,
192192
}
193193

194194
impl<T> Future for BiLockAcquire<T> {
195195
type Item = BiLockAcquired<T>;
196196
type Error = ();
197197

198198
fn poll(&mut self) -> Poll<BiLockAcquired<T>, ()> {
199-
match self.inner.poll_lock() {
199+
match self.inner.as_ref().expect("cannot poll after Ready").poll_lock() {
200200
Async::Ready(r) => {
201201
mem::forget(r);
202-
Ok(BiLockAcquired {
203-
inner: BiLock { inner: self.inner.inner.clone() },
204-
}.into())
205202
}
206-
Async::NotReady => Ok(Async::NotReady),
203+
Async::NotReady => return Ok(Async::NotReady),
207204
}
205+
Ok(Async::Ready(BiLockAcquired { inner: self.inner.take() }))
208206
}
209207
}
210208

@@ -216,33 +214,37 @@ impl<T> Future for BiLockAcquire<T> {
216214
/// `unlock` method.
217215
#[derive(Debug)]
218216
pub struct BiLockAcquired<T> {
219-
inner: BiLock<T>,
217+
inner: Option<BiLock<T>>,
220218
}
221219

222220
impl<T> BiLockAcquired<T> {
223221
/// Recovers the original `BiLock<T>`, unlocking this lock.
224-
pub fn unlock(self) -> BiLock<T> {
225-
// note that unlocked is implemented in `Drop`, so we don't do anything
226-
// here other than creating a new handle to return.
227-
BiLock { inner: self.inner.inner.clone() }
222+
pub fn unlock(mut self) -> BiLock<T> {
223+
let bi_lock = self.inner.take().unwrap();
224+
225+
bi_lock.unlock();
226+
227+
bi_lock
228228
}
229229
}
230230

231231
impl<T> Deref for BiLockAcquired<T> {
232232
type Target = T;
233233
fn deref(&self) -> &T {
234-
unsafe { &*self.inner.inner.inner.get() }
234+
unsafe { &*self.inner.as_ref().unwrap().inner.inner.get() }
235235
}
236236
}
237237

238238
impl<T> DerefMut for BiLockAcquired<T> {
239239
fn deref_mut(&mut self) -> &mut T {
240-
unsafe { &mut *self.inner.inner.inner.get() }
240+
unsafe { &mut *self.inner.as_mut().unwrap().inner.inner.get() }
241241
}
242242
}
243243

244244
impl<T> Drop for BiLockAcquired<T> {
245245
fn drop(&mut self) {
246-
self.inner.unlock();
246+
if let Some(ref bi_lock) = self.inner {
247+
bi_lock.unlock();
248+
}
247249
}
248250
}

0 commit comments

Comments
 (0)