|  | #![feature(test)] | 
|  |  | 
|  | extern crate test; | 
|  |  | 
|  | use std::cell::RefCell; | 
|  | use std::future::Future; | 
|  | use std::pin::Pin; | 
|  | use std::task::{Context, Poll, Waker}; | 
|  |  | 
|  | use crossbeam::sync::Parker; | 
|  | use test::Bencher; | 
|  |  | 
|  | /// Runs a future to completion on the current thread. | 
|  | fn block_on<F: Future>(future: F) -> F::Output { | 
|  | // Pin the future on the stack. | 
|  | futures::pin_mut!(future); | 
|  |  | 
|  | thread_local! { | 
|  | // Parker and waker associated with the current thread. | 
|  | static CACHE: RefCell<(Parker, Waker)> = { | 
|  | let parker = Parker::new(); | 
|  | let unparker = parker.unparker().clone(); | 
|  | let waker = async_task::waker_fn(move || unparker.unpark()); | 
|  | RefCell::new((parker, waker)) | 
|  | }; | 
|  | } | 
|  |  | 
|  | CACHE.with(|cache| { | 
|  | // Panic if `block_on()` is called recursively. | 
|  | let (parker, waker) = &mut *cache.try_borrow_mut().ok().expect("recursive `block_on`"); | 
|  |  | 
|  | // Create the task context. | 
|  | let cx = &mut Context::from_waker(&waker); | 
|  |  | 
|  | // Keep polling the future until completion. | 
|  | loop { | 
|  | match future.as_mut().poll(cx) { | 
|  | Poll::Ready(output) => return output, | 
|  | Poll::Pending => parker.park(), | 
|  | } | 
|  | } | 
|  | }) | 
|  | } | 
|  |  | 
|  | #[bench] | 
|  | fn custom_block_on_0_yields(b: &mut Bencher) { | 
|  | b.iter(|| block_on(Yields(0))); | 
|  | } | 
|  |  | 
|  | #[bench] | 
|  | fn custom_block_on_10_yields(b: &mut Bencher) { | 
|  | b.iter(|| block_on(Yields(10))); | 
|  | } | 
|  |  | 
|  | #[bench] | 
|  | fn custom_block_on_50_yields(b: &mut Bencher) { | 
|  | b.iter(|| block_on(Yields(50))); | 
|  | } | 
|  |  | 
|  | #[bench] | 
|  | fn futures_block_on_0_yields(b: &mut Bencher) { | 
|  | b.iter(|| futures::executor::block_on(Yields(0))); | 
|  | } | 
|  |  | 
|  | #[bench] | 
|  | fn futures_block_on_10_yields(b: &mut Bencher) { | 
|  | b.iter(|| futures::executor::block_on(Yields(10))); | 
|  | } | 
|  |  | 
|  | #[bench] | 
|  | fn futures_block_on_50_yields(b: &mut Bencher) { | 
|  | b.iter(|| futures::executor::block_on(Yields(50))); | 
|  | } | 
|  |  | 
|  | struct Yields(u32); | 
|  |  | 
|  | impl Future for Yields { | 
|  | type Output = (); | 
|  |  | 
|  | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | 
|  | if self.0 == 0 { | 
|  | Poll::Ready(()) | 
|  | } else { | 
|  | self.0 -= 1; | 
|  | cx.waker().wake_by_ref(); | 
|  | Poll::Pending | 
|  | } | 
|  | } | 
|  | } |