|
| 1 | +// Copyright (c) Microsoft Corporation. |
| 2 | +// Licensed under the MIT License. |
| 3 | + |
| 4 | +//! Callgrind benchmarks for [`Router::resolve_request_uri`], the per-request routing step. |
| 5 | +//! |
| 6 | +//! For every outgoing request (and again per retry/hedge attempt) the router picks the |
| 7 | +//! [`BaseUri`] and materializes the request's `http::Uri`. This benchmark isolates that step |
| 8 | +//! on a request built through [`HttpRequestBuilder`] (so the build-time path rendering is |
| 9 | +//! cached and reused) for both a root and a prefixed base path. |
| 10 | +//! |
| 11 | +//! Paired with `router_resolve.rs`, which covers the same operation under wall-clock |
| 12 | +//! (Criterion) measurement. |
| 13 | +
|
| 14 | +#![allow(missing_docs, reason = "no need for API documentation on benchmark code")] |
| 15 | +#![allow( |
| 16 | + clippy::needless_pass_by_value, |
| 17 | + clippy::unwrap_used, |
| 18 | + reason = "gungraun benchmark inputs are passed and returned by value by the framework" |
| 19 | +)] |
| 20 | +#![cfg_attr( |
| 21 | + target_os = "linux", |
| 22 | + expect( |
| 23 | + clippy::exit, |
| 24 | + clippy::missing_docs_in_private_items, |
| 25 | + unused_qualifications, |
| 26 | + reason = "Triggered by Gungraun macro expansion. Upstream tracking issues are pending." |
| 27 | + ) |
| 28 | +)] |
| 29 | + |
| 30 | +#[cfg(not(target_os = "linux"))] |
| 31 | +fn main() { |
| 32 | + // Gungraun requires Valgrind, which is Linux-only. |
| 33 | +} |
| 34 | + |
| 35 | +#[cfg(target_os = "linux")] |
| 36 | +mod linux { |
| 37 | + use std::hint::black_box; |
| 38 | + |
| 39 | + use gungraun::{library_benchmark, library_benchmark_group}; |
| 40 | + use http_extensions::routing::{Router, RouterContext}; |
| 41 | + use http_extensions::{HttpRequest, HttpRequestBuilder}; |
| 42 | + use templated_uri::BaseUri; |
| 43 | + |
| 44 | + fn setup(base: &'static str) -> (Router, HttpRequest) { |
| 45 | + let router = Router::fixed(BaseUri::from_static(base)); |
| 46 | + let request = HttpRequestBuilder::new_fake() |
| 47 | + .get("/users/42/posts/hello-world?active=true") |
| 48 | + .build() |
| 49 | + .unwrap(); |
| 50 | + (router, request) |
| 51 | + } |
| 52 | + |
| 53 | + // Fixed endpoint, root base path (common case): the reused rendered path is returned |
| 54 | + // without a re-validation scan. |
| 55 | + #[library_benchmark] |
| 56 | + #[bench::root(setup("https://api.example.com"))] |
| 57 | + fn resolve_root(input: (Router, HttpRequest)) -> HttpRequest { |
| 58 | + let (router, mut request) = input; |
| 59 | + router.resolve_request_uri(RouterContext::new(), black_box(&mut request)).unwrap(); |
| 60 | + request |
| 61 | + } |
| 62 | + |
| 63 | + // Fixed endpoint, non-root base path: the join concatenates and re-validates. |
| 64 | + #[library_benchmark] |
| 65 | + #[bench::prefixed(setup("https://api.example.com/v1/"))] |
| 66 | + fn resolve_prefixed(input: (Router, HttpRequest)) -> HttpRequest { |
| 67 | + let (router, mut request) = input; |
| 68 | + router.resolve_request_uri(RouterContext::new(), black_box(&mut request)).unwrap(); |
| 69 | + request |
| 70 | + } |
| 71 | + |
| 72 | + library_benchmark_group!( |
| 73 | + name = router_resolve; |
| 74 | + benchmarks = resolve_root, resolve_prefixed |
| 75 | + ); |
| 76 | +} |
| 77 | + |
| 78 | +#[cfg(target_os = "linux")] |
| 79 | +use gungraun::{Callgrind, LibraryBenchmarkConfig}; |
| 80 | +#[cfg(target_os = "linux")] |
| 81 | +pub use linux::router_resolve; |
| 82 | + |
| 83 | +#[cfg(target_os = "linux")] |
| 84 | +gungraun::main!( |
| 85 | + config = LibraryBenchmarkConfig::default() |
| 86 | + .tool(Callgrind::with_args(["--branch-sim=yes"])); |
| 87 | + library_benchmark_groups = router_resolve |
| 88 | +); |
0 commit comments