From 79f970c7fffc189b32b2740c1437111bf28caa4c Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Thu, 25 Oct 2018 17:15:06 -0700 Subject: [PATCH] test(benches): clean up end_to_end benchmark configuration --- benches/end_to_end.rs | 204 +++++++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 92 deletions(-) diff --git a/benches/end_to_end.rs b/benches/end_to_end.rs index 6e1c0348..43d4515b 100644 --- a/benches/end_to_end.rs +++ b/benches/end_to_end.rs @@ -11,144 +11,164 @@ use std::net::SocketAddr; use futures::{Future, Stream}; use tokio::runtime::current_thread::Runtime; -use tokio::net::TcpListener; -use hyper::{Body, Method, Request, Response, Version}; +use hyper::{Body, Method, Request, Response, Server}; use hyper::client::HttpConnector; -use hyper::server::conn::Http; #[bench] fn http1_get(b: &mut test::Bencher) { - bench_with(b, Version::HTTP_11, || { - Request::new(Body::empty()) - }); + opts() + .bench(b) } #[bench] fn http1_post(b: &mut test::Bencher) { - bench_with(b, Version::HTTP_11, || { - let mut req = Request::new("foo bar baz quux".into()); - *req.method_mut() = Method::POST; - req - }); + opts() + .method(Method::POST) + .request_body(b"foo bar baz quux") + .bench(b) } #[bench] fn http1_get_parallel(b: &mut test::Bencher) { - bench_parallel_with(b, Version::HTTP_11, || { - Request::new(Body::empty()) - }); + opts() + .parallel(10) + .bench(b) } #[bench] fn http2_get(b: &mut test::Bencher) { - bench_with(b, Version::HTTP_2, || { - Request::new(Body::empty()) - }); + opts() + .http2() + .bench(b) } #[bench] fn http2_post(b: &mut test::Bencher) { - bench_with(b, Version::HTTP_2, || { - let mut req = Request::new("foo bar baz quux".into()); - *req.method_mut() = Method::POST; - req - }); + opts() + .http2() + .method(Method::POST) + .request_body(b"foo bar baz quux") + .bench(b) } #[bench] fn http2_get_parallel(b: &mut test::Bencher) { - bench_parallel_with(b, Version::HTTP_2, || { - Request::new(Body::empty()) - }); + opts() + .http2() + .parallel(10) + .bench(b) } -fn bench_with(b: &mut test::Bencher, version: Version, make_request: F) -where - F: Fn() -> Request, -{ - let _ = pretty_env_logger::try_init(); - let mut rt = Runtime::new().unwrap(); - let body = b"Hello"; - let addr = spawn_hello(&mut rt, body); +// ==== Benchmark Options ===== - let connector = HttpConnector::new(1); - let client = hyper::Client::builder() - .http2_only(version == Version::HTTP_2) - .build::<_, Body>(connector); - - let url: hyper::Uri = format!("http://{}/hello", addr).parse().unwrap(); - - b.bytes = body.len() as u64; - b.iter(move || { - let mut req = make_request(); - *req.uri_mut() = url.clone(); - rt.block_on(client.request(req).and_then(|res| { - res.into_body().for_each(|_chunk| { - Ok(()) - }) - })).expect("client wait"); - }); +struct Opts { + http2: bool, + parallel_cnt: u32, + request_method: Method, + request_body: Option<&'static [u8]>, + response_body: &'static [u8], } -fn bench_parallel_with(b: &mut test::Bencher, version: Version, make_request: F) -where - F: Fn() -> Request, -{ - let _ = pretty_env_logger::try_init(); - let mut rt = Runtime::new().unwrap(); - let body = b"Hello"; - let addr = spawn_hello(&mut rt, body); +fn opts() -> Opts { + Opts { + http2: false, + parallel_cnt: 1, + request_method: Method::GET, + request_body: None, + response_body: b"Hello", + } +} - let connector = HttpConnector::new(1); - let client = hyper::Client::builder() - .http2_only(version == Version::HTTP_2) - .build::<_, Body>(connector); +impl Opts { + fn http2(mut self) -> Self { + self.http2 = true; + self + } - let url: hyper::Uri = format!("http://{}/hello", addr).parse().unwrap(); + fn method(mut self, m: Method) -> Self { + self.request_method = m; + self + } - b.bytes = body.len() as u64; - b.iter(move || { - let futs = (0..10) - .into_iter() - .map(|_| { + fn request_body(mut self, body: &'static [u8]) -> Self { + self.request_body = Some(body); + self + } + + fn parallel(mut self, cnt: u32) -> Self { + assert!(cnt > 0, "parallel count must be larger than 0"); + self.parallel_cnt = cnt; + self + } + + fn bench(self, b: &mut test::Bencher) { + let _ = pretty_env_logger::try_init(); + let mut rt = Runtime::new().unwrap(); + let addr = spawn_hello(&mut rt, self.response_body); + + let connector = HttpConnector::new(1); + let client = hyper::Client::builder() + .http2_only(self.http2) + .build::<_, Body>(connector); + + let url: hyper::Uri = format!("http://{}/hello", addr).parse().unwrap(); + + let make_request = || { + let body = self + .request_body + .map(Body::from) + .unwrap_or_else(|| Body::empty()); + let mut req = Request::new(body); + *req.method_mut() = self.request_method.clone(); + req + }; + + if self.parallel_cnt == 1 { + b.iter(move || { let mut req = make_request(); *req.uri_mut() = url.clone(); - client.request(req).and_then(|res| { + rt.block_on(client.request(req).and_then(|res| { res.into_body().for_each(|_chunk| { Ok(()) }) - }).map_err(|_e| ()) + })).expect("client wait"); }); - let _ = rt.block_on(::futures::future::join_all(futs)); - }); + } else { + b.iter(|| { + let futs = (0..self.parallel_cnt) + .into_iter() + .map(|_| { + let mut req = make_request(); + *req.uri_mut() = url.clone(); + client.request(req).and_then(|res| { + res.into_body().for_each(|_chunk| { + Ok(()) + }) + }).map_err(|e| panic!("client error: {}", e)) + }); + let _ = rt.block_on(::futures::future::join_all(futs)); + }); + } + } } fn spawn_hello(rt: &mut Runtime, body: &'static [u8]) -> SocketAddr { use hyper::service::{service_fn}; let addr = "127.0.0.1:0".parse().unwrap(); - let listener = TcpListener::bind(&addr).unwrap(); - let addr = listener.local_addr().unwrap(); - let http = Http::new(); - - let service = service_fn(move |req: Request| { - req.into_body() - .concat2() - .map(move |_| { - Response::new(Body::from(body)) + let srv = Server::bind(&addr) + .serve(move || { + service_fn(move |req: Request| { + req.into_body() + .concat2() + .map(move |_| { + Response::new(Body::from(body)) + }) }) - }); - - // Specifically only accept 1 connection. - let srv = listener.incoming() - .into_future() - .map_err(|(e, _inc)| panic!("accept error: {}", e)) - .and_then(move |(accepted, _inc)| { - let socket = accepted.expect("accepted socket"); - http.serve_connection(socket, service) - .map_err(|_| ()) }); - rt.spawn(srv); + let addr = srv.local_addr(); + let fut = srv.map_err(|err| panic!("server error: {}", err)); + rt.spawn(fut); return addr }