• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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