diff --git a/Cargo.lock b/Cargo.lock index db50e852..6f8bb87b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,6 +204,16 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode-next" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe9e7e6d14aeb39557f226bff158a30e367fac279d0e69b8b42fb41999f9a86" +dependencies = [ + "serde", + "unty-next", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -883,6 +893,16 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +[[package]] +name = "either-or-both" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717164c227120ba9ddf3e2b32305fc0122741d3ee41a54968eae7573ee01933" +dependencies = [ + "indexmap", + "serde", +] + [[package]] name = "embedded-io" version = "0.4.0" @@ -1285,6 +1305,44 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "gungraun" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9300d38d30facf6870c15bc9e243edcc47e5ddc270c9d2c1ae824a00b1faea79" +dependencies = [ + "bincode-next", + "derive_more", + "gungraun-macros", + "gungraun-runner", +] + +[[package]] +name = "gungraun-macros" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f3214bae6cfd6739f4f29edb262bae439c6393a7b7b12c4eeb96417c2e50df" +dependencies = [ + "derive_more", + "proc-macro-error3", + "proc-macro2", + "quote", + "rustc_version", + "serde", + "serde_json", + "syn 2.0.119", +] + +[[package]] +name = "gungraun-runner" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c68c92812da579a2510a2cc702d5aa3251992b9662d4a98502ca46e0cbe16e" +dependencies = [ + "either-or-both", + "serde", +] + [[package]] name = "h2" version = "0.4.19" @@ -1548,42 +1606,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "iai-callgrind" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b1e4910d3a9137442723dfb772c32dc10674c4181ca078d2fd227cd5dce9db0" -dependencies = [ - "bincode", - "derive_more", - "iai-callgrind-macros", - "iai-callgrind-runner", -] - -[[package]] -name = "iai-callgrind-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d03775318d3f9f01b39ac6612b01464006dc397a654a89dd57df2fd34fb68c3" -dependencies = [ - "derive_more", - "proc-macro-error2", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn 2.0.119", -] - -[[package]] -name = "iai-callgrind-runner" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74c9743c00c3bca4aaffc69c87cae56837796cd362438daf354a3f785788c68" -dependencies = [ - "serde", -] - [[package]] name = "iana-time-zone" version = "0.1.65" @@ -2179,8 +2201,8 @@ dependencies = [ "flate2", "foyer", "futures", + "gungraun", "hickory-resolver", - "iai-callgrind", "memchr", "moka", "nutype", @@ -2624,25 +2646,25 @@ dependencies = [ ] [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "proc-macro-error-attr3" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "9e564d14133360e1ae169ffde5da25881b5fa47261665b8e5713c212c27799da" dependencies = [ "proc-macro2", "quote", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "proc-macro-error3" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "8f0d4471b3436c22106b21913b1dda531558918ae9b7ec55d58aa84b43552233" dependencies = [ - "proc-macro-error-attr2", + "proc-macro-error-attr3", "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] @@ -3974,6 +3996,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16062d030850f35054e37746427b9febb74a2f24c9c6dd6fa2d0c13c5f53221e" + [[package]] name = "url" version = "2.5.8" diff --git a/Cargo.toml b/Cargo.toml index c108ef37..bb8be67b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,7 +103,7 @@ proptest = "1.11" # Property-based testing for comprehensive coverage yenc = "0.2.2" # For benchmark comparison only [target.'cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "aarch64")))'.dev-dependencies] -iai-callgrind = "0.16.1" # Instruction-count benchmarking for hot path comparisons +gungraun = "0.19.4" # Callgrind instruction/branch/cache benchmarking [features] default = [] diff --git a/benches/cache_miss_roundtrip_callgrind.rs b/benches/cache_miss_roundtrip_callgrind.rs index e0ac7561..9cef278f 100644 --- a/benches/cache_miss_roundtrip_callgrind.rs +++ b/benches/cache_miss_roundtrip_callgrind.rs @@ -1,4 +1,4 @@ -//! Callgrind benchmarks for the real cache-miss proxy roundtrip path. +//! Gungraun benchmarks for the real cache-miss proxy roundtrip path. //! //! These benches drive a client socket through a live per-command proxy with //! metadata-only cache enabled or no configured cache. Each `ARTICLE` request @@ -17,7 +17,7 @@ macro_rules! supported { } supported! { - use iai_callgrind::{ + use gungraun::{ Callgrind, LibraryBenchmarkConfig, library_benchmark, library_benchmark_group, main, }; use nntp_proxy::config::{Cache, Config, Server}; diff --git a/benches/request_classifier_callgrind.rs b/benches/request_classifier_callgrind.rs index 882ca055..1283b69c 100644 --- a/benches/request_classifier_callgrind.rs +++ b/benches/request_classifier_callgrind.rs @@ -1,4 +1,4 @@ -//! Callgrind benchmarks for NNTP request verb classification. +//! Gungraun benchmarks for NNTP request verb classification. //! //! The `request_line_*` benches exercise the current borrowed request-line parser. //! @@ -14,7 +14,7 @@ macro_rules! supported { } supported! { - use iai_callgrind::{ + use gungraun::{ Callgrind, EntryPoint, LibraryBenchmarkConfig, library_benchmark, library_benchmark_group, main, }; use nntp_proxy::protocol::{RequestContext, RequestKind}; diff --git a/benches/request_serialization.rs b/benches/request_serialization.rs index 2820d204..bfcdaddc 100644 --- a/benches/request_serialization.rs +++ b/benches/request_serialization.rs @@ -47,8 +47,7 @@ impl FixedSink { } #[inline] -fn write_request_slices(sink: &mut FixedSink, request: &RequestContext) -> usize { - sink.clear(); +fn append_request_slices(sink: &mut FixedSink, request: &RequestContext) -> usize { sink.write(request.verb()); if !request.args().is_empty() { sink.write(b" "); @@ -58,6 +57,12 @@ fn write_request_slices(sink: &mut FixedSink, request: &RequestContext) -> usize sink.len() } +#[inline] +fn write_request_slices(sink: &mut FixedSink, request: &RequestContext) -> usize { + sink.clear(); + append_request_slices(sink, request) +} + fn request_context(line: &[u8]) -> RequestContext { RequestContext::parse(line).expect("valid request line") } @@ -126,6 +131,48 @@ mod mixed_batch { } } +mod upstream_window { + use super::{Bencher, FixedSink, append_request_slices, black_box, request_context}; + + const WINDOW: &[&str] = &[ + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + "ARTICLE \r\n", + ]; + + #[divan::bench(sample_count = 1000, sample_size = 100)] + fn sixteen_article_window(bencher: Bencher) { + let requests = WINDOW + .iter() + .map(|line| request_context(line.as_bytes())) + .collect::>(); + + bencher + .counter(divan::counter::ItemsCount::new(requests.len())) + .bench(|| { + let mut sink = FixedSink::default(); + sink.clear(); + requests + .iter() + .map(|request| append_request_slices(black_box(&mut sink), black_box(request))) + .sum::() + }); + } +} + mod response_shape { use super::{Bencher, StatusCode, black_box, request_context}; diff --git a/flake.nix b/flake.nix index 300dd341..92d169a2 100644 --- a/flake.nix +++ b/flake.nix @@ -132,6 +132,21 @@ package = import ./nix/package.nix { inherit pkgs craneLib cargoToml; }; + + gungraunRunner = pkgs.rustPlatform.buildRustPackage rec { + pname = "gungraun-runner"; + version = "0.19.4"; + src = pkgs.fetchFromGitHub { + owner = "gungraun"; + repo = "gungraun"; + rev = "v${version}"; + hash = "sha256-KWQ4wMNIdKY9FTmPd9ZdlSuCpQQBFhIKD2Ereo3JQaI="; + }; + cargoHash = "sha256-+3toaUDLCmExC3EvNv1GEdUbHSBeShurp2Y+zvE/t0k="; + cargoBuildFlags = ["-p" pname]; + cargoInstallFlags = ["-p" pname]; + doCheck = false; + }; in { apps.default = (flake-utils.lib.mkApp { @@ -142,7 +157,7 @@ }; devShells.default = pkgs.mkShell { - nativeBuildInputs = basicNativeBuildInputs; + nativeBuildInputs = basicNativeBuildInputs ++ [gungraunRunner]; buildInputs = devBuildInputs; shellHook = '' diff --git a/scripts/audit-advisories b/scripts/audit-advisories index df265ef0..8e808e3b 100755 --- a/scripts/audit-advisories +++ b/scripts/audit-advisories @@ -41,9 +41,10 @@ run cargo deny check advisories tree_for bincode tree_for paste -tree_for proc-macro-error2 +tree_for proc-macro-error3 +tree_for gungraun echo echo "Upstream projects to watch:" echo "- foyer: https://github.com/foyer-rs/foyer" -echo "- iai-callgrind: https://github.com/iai-callgrind/iai-callgrind" +echo "- gungraun: https://github.com/gungraun/gungraun"