1 #![feature(test)]
2 
3 extern crate test;
4 
5 use std::cell::RefCell;
6 use std::future::Future;
7 use std::pin::Pin;
8 use std::task::{Context, Poll, Waker};
9 
10 use crossbeam::sync::Parker;
11 use test::Bencher;
12 
13 /// Runs a future to completion on the current thread.
block_on<F: Future>(future: F) -> F::Output14 fn block_on<F: Future>(future: F) -> F::Output {
15     // Pin the future on the stack.
16     futures::pin_mut!(future);
17 
18     thread_local! {
19         // Parker and waker associated with the current thread.
20         static CACHE: RefCell<(Parker, Waker)> = {
21             let parker = Parker::new();
22             let unparker = parker.unparker().clone();
23             let waker = async_task::waker_fn(move || unparker.unpark());
24             RefCell::new((parker, waker))
25         };
26     }
27 
28     CACHE.with(|cache| {
29         // Panic if `block_on()` is called recursively.
30         let (parker, waker) = &mut *cache.try_borrow_mut().ok().expect("recursive `block_on`");
31 
32         // Create the task context.
33         let cx = &mut Context::from_waker(&waker);
34 
35         // Keep polling the future until completion.
36         loop {
37             match future.as_mut().poll(cx) {
38                 Poll::Ready(output) => return output,
39                 Poll::Pending => parker.park(),
40             }
41         }
42     })
43 }
44 
45 #[bench]
custom_block_on_0_yields(b: &mut Bencher)46 fn custom_block_on_0_yields(b: &mut Bencher) {
47     b.iter(|| block_on(Yields(0)));
48 }
49 
50 #[bench]
custom_block_on_10_yields(b: &mut Bencher)51 fn custom_block_on_10_yields(b: &mut Bencher) {
52     b.iter(|| block_on(Yields(10)));
53 }
54 
55 #[bench]
custom_block_on_50_yields(b: &mut Bencher)56 fn custom_block_on_50_yields(b: &mut Bencher) {
57     b.iter(|| block_on(Yields(50)));
58 }
59 
60 #[bench]
futures_block_on_0_yields(b: &mut Bencher)61 fn futures_block_on_0_yields(b: &mut Bencher) {
62     b.iter(|| futures::executor::block_on(Yields(0)));
63 }
64 
65 #[bench]
futures_block_on_10_yields(b: &mut Bencher)66 fn futures_block_on_10_yields(b: &mut Bencher) {
67     b.iter(|| futures::executor::block_on(Yields(10)));
68 }
69 
70 #[bench]
futures_block_on_50_yields(b: &mut Bencher)71 fn futures_block_on_50_yields(b: &mut Bencher) {
72     b.iter(|| futures::executor::block_on(Yields(50)));
73 }
74 
75 struct Yields(u32);
76 
77 impl Future for Yields {
78     type Output = ();
79 
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>80     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
81         if self.0 == 0 {
82             Poll::Ready(())
83         } else {
84             self.0 -= 1;
85             cx.waker().wake_by_ref();
86             Poll::Pending
87         }
88     }
89 }
90