2020-01-24 23:05:25 +00:00
|
|
|
use actix_service::Service;
|
|
|
|
use actix_web::dev::{ServiceRequest, ServiceResponse};
|
|
|
|
use actix_web::{web, App, Error, HttpResponse};
|
|
|
|
use criterion::{criterion_main, Criterion};
|
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
use actix_web::test::{init_service, ok_service, TestRequest};
|
|
|
|
|
|
|
|
/// Criterion Benchmark for async Service
|
|
|
|
/// Should be used from within criterion group:
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// let mut criterion: ::criterion::Criterion<_> =
|
|
|
|
/// ::criterion::Criterion::default().configure_from_args();
|
|
|
|
/// bench_async_service(&mut criterion, ok_service(), "async_service_direct");
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Usable for benching Service wrappers:
|
|
|
|
/// Using minimum service code implementation we first measure
|
|
|
|
/// time to run minimum service, then measure time with wrapper.
|
|
|
|
///
|
|
|
|
/// Sample output
|
|
|
|
/// async_service_direct time: [1.0908 us 1.1656 us 1.2613 us]
|
|
|
|
pub fn bench_async_service<S>(c: &mut Criterion, srv: S, name: &str)
|
|
|
|
where
|
2021-01-03 23:47:04 +00:00
|
|
|
S: Service<ServiceRequest, Response = ServiceResponse, Error = Error> + 'static,
|
2020-01-24 23:05:25 +00:00
|
|
|
{
|
2021-01-03 23:47:04 +00:00
|
|
|
let rt = actix_rt::System::new("test");
|
2020-01-24 23:05:25 +00:00
|
|
|
let srv = Rc::new(RefCell::new(srv));
|
|
|
|
|
|
|
|
let req = TestRequest::default().to_srv_request();
|
|
|
|
assert!(rt
|
|
|
|
.block_on(srv.borrow_mut().call(req))
|
|
|
|
.unwrap()
|
|
|
|
.status()
|
|
|
|
.is_success());
|
|
|
|
|
|
|
|
// start benchmark loops
|
|
|
|
c.bench_function(name, move |b| {
|
|
|
|
b.iter_custom(|iters| {
|
|
|
|
let srv = srv.clone();
|
|
|
|
// exclude request generation, it appears it takes significant time vs call (3us vs 1us)
|
2021-01-03 23:47:04 +00:00
|
|
|
let futs = (0..iters)
|
2020-01-24 23:05:25 +00:00
|
|
|
.map(|_| TestRequest::default().to_srv_request())
|
2021-01-03 23:47:04 +00:00
|
|
|
.map(|req| srv.borrow_mut().call(req));
|
|
|
|
|
2020-01-24 23:05:25 +00:00
|
|
|
let start = std::time::Instant::now();
|
|
|
|
// benchmark body
|
|
|
|
rt.block_on(async move {
|
2021-01-03 23:47:04 +00:00
|
|
|
for fut in futs {
|
|
|
|
fut.await.unwrap();
|
2020-01-24 23:05:25 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
let elapsed = start.elapsed();
|
|
|
|
// check that at least first request succeeded
|
|
|
|
elapsed
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn index(req: ServiceRequest) -> Result<ServiceResponse, Error> {
|
|
|
|
Ok(req.into_response(HttpResponse::Ok().finish()))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Benchmark basic WebService directly
|
|
|
|
// this approach is usable for benching WebService, though it adds some time to direct service call:
|
|
|
|
// Sample results on MacBook Pro '14
|
|
|
|
// time: [2.0724 us 2.1345 us 2.2074 us]
|
|
|
|
fn async_web_service(c: &mut Criterion) {
|
2021-01-03 23:47:04 +00:00
|
|
|
let rt = actix_rt::System::new("test");
|
2020-01-24 23:05:25 +00:00
|
|
|
let srv = Rc::new(RefCell::new(rt.block_on(init_service(
|
|
|
|
App::new().service(web::service("/").finish(index)),
|
|
|
|
))));
|
|
|
|
|
|
|
|
let req = TestRequest::get().uri("/").to_request();
|
|
|
|
assert!(rt
|
|
|
|
.block_on(srv.borrow_mut().call(req))
|
|
|
|
.unwrap()
|
|
|
|
.status()
|
|
|
|
.is_success());
|
|
|
|
|
|
|
|
// start benchmark loops
|
|
|
|
c.bench_function("async_web_service_direct", move |b| {
|
|
|
|
b.iter_custom(|iters| {
|
|
|
|
let srv = srv.clone();
|
2021-01-03 23:47:04 +00:00
|
|
|
let futs = (0..iters)
|
|
|
|
.map(|_| TestRequest::get().uri("/").to_request())
|
|
|
|
.map(|req| srv.borrow_mut().call(req));
|
2020-01-24 23:05:25 +00:00
|
|
|
let start = std::time::Instant::now();
|
|
|
|
// benchmark body
|
|
|
|
rt.block_on(async move {
|
2021-01-03 23:47:04 +00:00
|
|
|
for fut in futs {
|
|
|
|
fut.await.unwrap();
|
2020-01-24 23:05:25 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
let elapsed = start.elapsed();
|
|
|
|
// check that at least first request succeeded
|
|
|
|
elapsed
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn service_benches() {
|
|
|
|
let mut criterion: ::criterion::Criterion<_> =
|
|
|
|
::criterion::Criterion::default().configure_from_args();
|
|
|
|
bench_async_service(&mut criterion, ok_service(), "async_service_direct");
|
|
|
|
async_web_service(&mut criterion);
|
|
|
|
}
|
|
|
|
criterion_main!(service_benches);
|