2021-05-24 21:38:40 +00:00
|
|
|
use std::collections::hash_set::HashSet;
|
|
|
|
|
2021-06-08 02:26:21 +00:00
|
|
|
use criterion::{criterion_group, Criterion};
|
2021-03-26 23:39:24 +00:00
|
|
|
|
2023-12-19 00:33:04 +00:00
|
|
|
use rocket::{route, config, Request, Data, Route, Config};
|
2021-03-26 23:39:24 +00:00
|
|
|
use rocket::http::{Method, RawStr, ContentType, Accept, Status};
|
|
|
|
use rocket::local::blocking::{Client, LocalRequest};
|
|
|
|
|
2021-06-08 09:13:02 +00:00
|
|
|
fn dummy_handler<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
|
2021-05-24 21:38:40 +00:00
|
|
|
route::Outcome::from(req, ()).pin()
|
2021-03-26 23:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_routes_table(table: &str) -> Vec<Route> {
|
|
|
|
let mut routes = vec![];
|
|
|
|
for line in table.split("\n").filter(|s| !s.is_empty()) {
|
|
|
|
let mut components = line.split(" ");
|
|
|
|
let method: Method = components.next().expect("c").parse().expect("method");
|
|
|
|
let uri: &str = components.next().unwrap();
|
|
|
|
|
|
|
|
let (mut rank, mut name, mut format) = (None, None, None);
|
|
|
|
for component in components {
|
|
|
|
match component {
|
|
|
|
c if c.starts_with('[') => rank = c.trim_matches(&['[', ']'][..]).parse().ok(),
|
|
|
|
c if c.starts_with('(') => name = Some(c.trim_matches(&['(', ')'][..])),
|
|
|
|
c => format = c.parse().ok(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut route = Route::new(method, uri, dummy_handler);
|
|
|
|
if let Some(rank) = rank {
|
|
|
|
route.rank = rank;
|
|
|
|
}
|
|
|
|
|
|
|
|
route.format = format;
|
|
|
|
route.name = name.map(|s| s.to_string().into());
|
|
|
|
routes.push(route);
|
|
|
|
}
|
|
|
|
|
|
|
|
routes
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_matching_requests<'c>(client: &'c Client, routes: &[Route]) -> Vec<LocalRequest<'c>> {
|
|
|
|
fn staticify_segment(segment: &RawStr) -> &str {
|
|
|
|
segment.as_str().trim_matches(&['<', '>', '.', '_'][..])
|
|
|
|
}
|
|
|
|
|
|
|
|
fn request_for_route<'c>(client: &'c Client, route: &Route) -> LocalRequest<'c> {
|
2023-04-10 19:31:17 +00:00
|
|
|
let path = route.uri.path()
|
2021-05-24 21:38:40 +00:00
|
|
|
.raw_segments()
|
2021-03-26 23:39:24 +00:00
|
|
|
.map(staticify_segment)
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("/");
|
|
|
|
|
2023-04-10 19:31:17 +00:00
|
|
|
let query = route.uri.query()
|
2021-05-24 21:38:40 +00:00
|
|
|
.map(|q| q.raw_segments())
|
|
|
|
.into_iter()
|
|
|
|
.flatten()
|
2021-03-26 23:39:24 +00:00
|
|
|
.map(staticify_segment)
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("&");
|
|
|
|
|
|
|
|
let uri = format!("/{}?{}", path, query);
|
|
|
|
let mut req = client.req(route.method, uri);
|
|
|
|
if let Some(ref format) = route.format {
|
2024-04-25 01:31:39 +00:00
|
|
|
if let Some(true) = route.method.allows_request_body() {
|
2021-03-26 23:39:24 +00:00
|
|
|
req.add_header(ContentType::from(format.clone()));
|
|
|
|
} else {
|
|
|
|
req.add_header(Accept::from(format.clone()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
req
|
|
|
|
}
|
|
|
|
|
|
|
|
routes.iter()
|
|
|
|
.map(|route| request_for_route(client, route))
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn client(routes: Vec<Route>) -> Client {
|
|
|
|
let config = Config {
|
|
|
|
profile: Config::RELEASE_PROFILE,
|
2024-05-03 02:12:25 +00:00
|
|
|
// log_level: rocket::config::LogLevel::Off,
|
2023-12-19 00:33:04 +00:00
|
|
|
cli_colors: config::CliColors::Never,
|
2024-03-19 03:19:00 +00:00
|
|
|
shutdown: config::ShutdownConfig {
|
2021-05-24 21:38:40 +00:00
|
|
|
ctrlc: false,
|
2021-06-08 02:26:21 +00:00
|
|
|
#[cfg(unix)]
|
2021-05-24 21:38:40 +00:00
|
|
|
signals: HashSet::new(),
|
|
|
|
..Default::default()
|
|
|
|
},
|
2021-03-26 23:39:24 +00:00
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
match Client::untracked(rocket::custom(config).mount("/", routes)) {
|
|
|
|
Ok(client) => client,
|
|
|
|
Err(e) => {
|
|
|
|
drop(e);
|
|
|
|
panic!("bad launch")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bench_rust_lang_routes(c: &mut Criterion) {
|
|
|
|
let table = include_str!("../static/rust-lang.routes");
|
|
|
|
let routes = parse_routes_table(table);
|
|
|
|
let client = client(routes.clone());
|
|
|
|
let requests = generate_matching_requests(&client, &routes);
|
|
|
|
c.bench_function("rust-lang.routes", |b| b.iter(|| {
|
|
|
|
for request in requests.clone() {
|
|
|
|
let response = request.dispatch();
|
|
|
|
assert_eq!(response.status(), Status::Ok);
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bench_bitwarden_routes(c: &mut Criterion) {
|
|
|
|
let table = include_str!("../static/bitwarden_rs.routes");
|
|
|
|
let routes = parse_routes_table(table);
|
|
|
|
let client = client(routes.clone());
|
|
|
|
let requests = generate_matching_requests(&client, &routes);
|
|
|
|
c.bench_function("bitwarden_rs.routes", |b| b.iter(|| {
|
|
|
|
for request in requests.clone() {
|
|
|
|
let response = request.dispatch();
|
|
|
|
assert_eq!(response.status(), Status::Ok);
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
2021-06-08 02:26:21 +00:00
|
|
|
|
|
|
|
criterion_group!(routing, bench_rust_lang_routes, bench_bitwarden_routes);
|