1 #![feature(test)] 2 3 #[cfg(feature = "bilock")] 4 mod bench { 5 use futures::executor::LocalPool; 6 use futures::task::{Context, Waker}; 7 use futures_util::lock::BiLock; 8 use futures_util::lock::BiLockAcquire; 9 use futures_util::lock::BiLockAcquired; 10 use futures_util::task::ArcWake; 11 12 use std::sync::Arc; 13 use test::Bencher; 14 notify_noop() -> Waker15 fn notify_noop() -> Waker { 16 struct Noop; 17 18 impl ArcWake for Noop { 19 fn wake(_: &Arc<Self>) {} 20 } 21 22 ArcWake::into_waker(Arc::new(Noop)) 23 } 24 25 /// Pseudo-stream which simply calls `lock.poll()` on `poll` 26 struct LockStream { 27 lock: BiLockAcquire<u32>, 28 } 29 30 impl LockStream { new(lock: BiLock<u32>) -> Self31 fn new(lock: BiLock<u32>) -> Self { 32 Self { lock: lock.lock() } 33 } 34 35 /// Release a lock after it was acquired in `poll`, 36 /// so `poll` could be called again. release_lock(&mut self, guard: BiLockAcquired<u32>)37 fn release_lock(&mut self, guard: BiLockAcquired<u32>) { 38 self.lock = guard.unlock().lock() 39 } 40 } 41 42 impl Stream for LockStream { 43 type Item = BiLockAcquired<u32>; 44 type Error = (); 45 poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>, Self::Error>46 fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>, Self::Error> { 47 self.lock.poll(cx).map(|a| a.map(Some)) 48 } 49 } 50 51 #[bench] contended(b: &mut Bencher)52 fn contended(b: &mut Bencher) { 53 let pool = LocalPool::new(); 54 let mut exec = pool.executor(); 55 let waker = notify_noop(); 56 let mut map = task::LocalMap::new(); 57 let mut waker = task::Context::new(&mut map, &waker, &mut exec); 58 59 b.iter(|| { 60 let (x, y) = BiLock::new(1); 61 62 let mut x = LockStream::new(x); 63 let mut y = LockStream::new(y); 64 65 for _ in 0..1000 { 66 let x_guard = match x.poll_next(&mut waker) { 67 Ok(Poll::Ready(Some(guard))) => guard, 68 _ => panic!(), 69 }; 70 71 // Try poll second lock while first lock still holds the lock 72 match y.poll_next(&mut waker) { 73 Ok(Poll::Pending) => (), 74 _ => panic!(), 75 }; 76 77 x.release_lock(x_guard); 78 79 let y_guard = match y.poll_next(&mut waker) { 80 Ok(Poll::Ready(Some(guard))) => guard, 81 _ => panic!(), 82 }; 83 84 y.release_lock(y_guard); 85 } 86 (x, y) 87 }); 88 } 89 90 #[bench] lock_unlock(b: &mut Bencher)91 fn lock_unlock(b: &mut Bencher) { 92 let pool = LocalPool::new(); 93 let mut exec = pool.executor(); 94 let waker = notify_noop(); 95 let mut map = task::LocalMap::new(); 96 let mut waker = task::Context::new(&mut map, &waker, &mut exec); 97 98 b.iter(|| { 99 let (x, y) = BiLock::new(1); 100 101 let mut x = LockStream::new(x); 102 let mut y = LockStream::new(y); 103 104 for _ in 0..1000 { 105 let x_guard = match x.poll_next(&mut waker) { 106 Ok(Poll::Ready(Some(guard))) => guard, 107 _ => panic!(), 108 }; 109 110 x.release_lock(x_guard); 111 112 let y_guard = match y.poll_next(&mut waker) { 113 Ok(Poll::Ready(Some(guard))) => guard, 114 _ => panic!(), 115 }; 116 117 y.release_lock(y_guard); 118 } 119 (x, y) 120 }) 121 } 122 } 123