diff --git a/TODO.md b/TODO.md index 541d7861..9804755a 100644 --- a/TODO.md +++ b/TODO.md @@ -2,11 +2,6 @@ ## High priority -* aquatic_bencher - * bench aquatic_udp with io_uring too - * test with SubsequentOnePerPair - * include chihaya with higher core counts? - ## Medium priority * stagger cleaning tasks? diff --git a/crates/bencher/Cargo.toml b/crates/bencher/Cargo.toml index 2be6137a..5704135f 100644 --- a/crates/bencher/Cargo.toml +++ b/crates/bencher/Cargo.toml @@ -19,7 +19,7 @@ default = ["udp"] udp = ["aquatic_udp", "aquatic_udp_load_test"] [dependencies] -aquatic_udp = { optional = true, workspace = true } +aquatic_udp = { optional = true, workspace = true, features = ["io-uring"] } aquatic_udp_load_test = { optional = true, workspace = true } anyhow = "1" diff --git a/crates/bencher/README.md b/crates/bencher/README.md index 224f638f..66524314 100644 --- a/crates/bencher/README.md +++ b/crates/bencher/README.md @@ -1,6 +1,8 @@ # aquatic_bencher -Automated benchmarking of aquatic and other BitTorrent trackers. Linux only. +Automated benchmarking of aquatic and other BitTorrent trackers. + +Requires Linux 6.0 or later. ## Supported trackers by protocol diff --git a/crates/bencher/src/common.rs b/crates/bencher/src/common.rs index 968e108a..a26862f1 100644 --- a/crates/bencher/src/common.rs +++ b/crates/bencher/src/common.rs @@ -167,21 +167,21 @@ impl TryFrom> for TaskSetCpuIndicator { #[derive(Debug, Clone, Copy, clap::ValueEnum)] pub enum CpuMode { - /// For 8 vCPU processor, use vCPU groups 0, 1, 2, 3, 4, 5, 6 and 7 - /// /// Suitable for bare-metal machines without hyperthreads/SMT. + /// + /// For 8 vCPU processor, uses vCPU groups 0, 1, 2, 3, 4, 5, 6 and 7 Subsequent, - /// For 8 vCPU processor, use vCPU groups 0 & 4, 1 & 5, 2 & 6 and 3 & 7 - /// /// Suitable for bare-metal machines with hyperthreads/SMT. + /// + /// For 8 vCPU processor, uses vCPU groups 0 & 4, 1 & 5, 2 & 6 and 3 & 7 SplitPairs, - /// For 8 vCPU processor, use vCPU groups 0 & 1, 2 & 3, 4 & 5 and 6 & 7 + /// For 8 vCPU processor, uses vCPU groups 0 & 1, 2 & 3, 4 & 5 and 6 & 7 SubsequentPairs, - /// For 8 vCPU processor, use vCPU groups 0, 2, 4 and 6 - /// /// Suitable for somewhat fairly comparing trackers on Hetzner virtual /// machines. Since in-VM hyperthreads aren't really hyperthreads, /// enabling them causes unpredictable performance. + /// + /// For 8 vCPU processor, uses vCPU groups 0, 2, 4 and 6 SubsequentOnePerPair, } diff --git a/crates/bencher/src/protocols/udp.rs b/crates/bencher/src/protocols/udp.rs index e93d1d03..e60d730c 100644 --- a/crates/bencher/src/protocols/udp.rs +++ b/crates/bencher/src/protocols/udp.rs @@ -20,6 +20,7 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum UdpTracker { Aquatic, + AquaticIoUring, OpenTracker, Chihaya, } @@ -28,6 +29,7 @@ impl Tracker for UdpTracker { fn name(&self) -> String { match self { Self::Aquatic => "aquatic_udp".into(), + Self::AquaticIoUring => "aquatic_udp (io_uring)".into(), Self::OpenTracker => "opentracker".into(), Self::Chihaya => "chihaya".into(), } @@ -65,14 +67,19 @@ impl UdpCommand { ], }, load_test_runs: simple_load_test_runs(cpu_mode, &[ + (8, Priority::Medium), (12, Priority::High) ]), }, 2 => SetConfig { implementations: indexmap! { UdpTracker::Aquatic => vec![ - AquaticUdpRunner::new(1, 1, Priority::Medium), - AquaticUdpRunner::new(2, 1, Priority::High), + AquaticUdpRunner::with_mio(1, 1, Priority::Medium), + AquaticUdpRunner::with_mio(2, 1, Priority::High), + ], + UdpTracker::AquaticIoUring => vec![ + AquaticUdpRunner::with_io_uring(1, 1, Priority::Medium), + AquaticUdpRunner::with_io_uring(2, 1, Priority::High), ], UdpTracker::OpenTracker => vec![ OpenTrackerUdpRunner::new(2, Priority::High), @@ -83,14 +90,19 @@ impl UdpCommand { ], }, load_test_runs: simple_load_test_runs(cpu_mode, &[ + (8, Priority::Medium), (12, Priority::High), ]), }, 4 => SetConfig { implementations: indexmap! { UdpTracker::Aquatic => vec![ - AquaticUdpRunner::new(3, 1, Priority::High), - AquaticUdpRunner::new(4, 1, Priority::Medium), + AquaticUdpRunner::with_mio(3, 1, Priority::High), + AquaticUdpRunner::with_mio(4, 1, Priority::Medium), + ], + UdpTracker::AquaticIoUring => vec![ + AquaticUdpRunner::with_io_uring(3, 1, Priority::High), + AquaticUdpRunner::with_io_uring(4, 1, Priority::Medium), ], UdpTracker::OpenTracker => vec![ OpenTrackerUdpRunner::new(4, Priority::High), @@ -100,13 +112,17 @@ impl UdpCommand { ], }, load_test_runs: simple_load_test_runs(cpu_mode, &[ + (8, Priority::Medium), (12, Priority::High), ]), }, 6 => SetConfig { implementations: indexmap! { UdpTracker::Aquatic => vec![ - AquaticUdpRunner::new(5, 1, Priority::High), + AquaticUdpRunner::with_mio(5, 1, Priority::High), + ], + UdpTracker::AquaticIoUring => vec![ + AquaticUdpRunner::with_io_uring(5, 1, Priority::High), ], UdpTracker::OpenTracker => vec![ OpenTrackerUdpRunner::new(6, Priority::High), @@ -116,13 +132,17 @@ impl UdpCommand { ], }, load_test_runs: simple_load_test_runs(cpu_mode, &[ + (8, Priority::Medium), (12, Priority::High), ]), }, 8 => SetConfig { implementations: indexmap! { UdpTracker::Aquatic => vec![ - AquaticUdpRunner::new(7, 1, Priority::High), + AquaticUdpRunner::with_mio(7, 1, Priority::High), + ], + UdpTracker::AquaticIoUring => vec![ + AquaticUdpRunner::with_io_uring(7, 1, Priority::High), ], UdpTracker::OpenTracker => vec![ OpenTrackerUdpRunner::new(8, Priority::High), @@ -132,14 +152,19 @@ impl UdpCommand { ], }, load_test_runs: simple_load_test_runs(cpu_mode, &[ + (8, Priority::Medium), (12, Priority::High), ]), }, 12 => SetConfig { implementations: indexmap! { UdpTracker::Aquatic => vec![ - AquaticUdpRunner::new(10, 2, Priority::High), - AquaticUdpRunner::new(9, 3, Priority::Medium), + AquaticUdpRunner::with_mio(10, 2, Priority::High), + AquaticUdpRunner::with_mio(9, 3, Priority::Medium), + ], + UdpTracker::AquaticIoUring => vec![ + AquaticUdpRunner::with_io_uring(10, 2, Priority::High), + AquaticUdpRunner::with_io_uring(9, 3, Priority::Medium), ], UdpTracker::OpenTracker => vec![ OpenTrackerUdpRunner::new(12, Priority::High), @@ -149,13 +174,17 @@ impl UdpCommand { ], }, load_test_runs: simple_load_test_runs(cpu_mode, &[ + (8, Priority::Medium), (12, Priority::High), ]), }, 16 => SetConfig { implementations: indexmap! { UdpTracker::Aquatic => vec![ - AquaticUdpRunner::new(13, 3, Priority::High), + AquaticUdpRunner::with_mio(13, 3, Priority::High), + ], + UdpTracker::AquaticIoUring => vec![ + AquaticUdpRunner::with_io_uring(13, 3, Priority::High), ], UdpTracker::OpenTracker => vec![ OpenTrackerUdpRunner::new(16, Priority::High), @@ -183,12 +212,24 @@ impl UdpCommand { struct AquaticUdpRunner { socket_workers: usize, swarm_workers: usize, + use_io_uring: bool, priority: Priority, } impl AquaticUdpRunner { - #[allow(clippy::new_ret_no_self)] - fn new( + fn with_mio( + socket_workers: usize, + swarm_workers: usize, + priority: Priority, + ) -> Rc> { + Rc::new(Self { + socket_workers, + swarm_workers, + use_io_uring: false, + priority, + }) + } + fn with_io_uring( socket_workers: usize, swarm_workers: usize, priority: Priority, @@ -196,6 +237,7 @@ impl AquaticUdpRunner { Rc::new(Self { socket_workers, swarm_workers, + use_io_uring: true, priority, }) } @@ -216,6 +258,7 @@ impl ProcessRunner for AquaticUdpRunner { c.socket_workers = self.socket_workers; c.swarm_workers = self.swarm_workers; c.network.address = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 3000)); + c.network.use_io_uring = self.use_io_uring; c.protocol.max_response_peers = 30; let c = toml::to_string_pretty(&c)?; diff --git a/crates/udp/src/config.rs b/crates/udp/src/config.rs index 7c209a65..df83279e 100644 --- a/crates/udp/src/config.rs +++ b/crates/udp/src/config.rs @@ -100,6 +100,8 @@ pub struct NetworkConfig { pub socket_recv_buffer_size: usize, /// Poll timeout in milliseconds (mio backend only) pub poll_timeout_ms: u64, + #[cfg(feature = "io-uring")] + pub use_io_uring: bool, /// Number of ring entries (io_uring backend only) /// /// Will be rounded to next power of two if not already one. @@ -131,6 +133,8 @@ impl Default for NetworkConfig { socket_recv_buffer_size: 8_000_000, poll_timeout_ms: 50, #[cfg(feature = "io-uring")] + use_io_uring: true, + #[cfg(feature = "io-uring")] ring_size: 128, resend_buffer_max_len: 0, } diff --git a/crates/udp/src/workers/socket/mod.rs b/crates/udp/src/workers/socket/mod.rs index f7241381..d55e69dd 100644 --- a/crates/udp/src/workers/socket/mod.rs +++ b/crates/udp/src/workers/socket/mod.rs @@ -49,24 +49,18 @@ pub fn run_socket_worker( priv_dropper: PrivilegeDropper, ) -> anyhow::Result<()> { #[cfg(all(target_os = "linux", feature = "io-uring"))] - match self::uring::supported_on_current_kernel() { - Ok(()) => { - return self::uring::SocketWorker::run( - config, - shared_state, - statistics, - validator, - request_sender, - response_receiver, - priv_dropper, - ); - } - Err(err) => { - ::log::warn!( - "Falling back to mio because of lacking kernel io_uring support: {:#}", - err - ); - } + if config.network.use_io_uring { + self::uring::supported_on_current_kernel().context("check for io_uring compatibility")?; + + return self::uring::SocketWorker::run( + config, + shared_state, + statistics, + validator, + request_sender, + response_receiver, + priv_dropper, + ); } self::mio::SocketWorker::run( diff --git a/scripts/bench/setup-udp-bookworm.sh b/scripts/bench/setup-udp-bookworm.sh index 1e508f21..ed59127c 100755 --- a/scripts/bench/setup-udp-bookworm.sh +++ b/scripts/bench/setup-udp-bookworm.sh @@ -5,13 +5,14 @@ sudo apt-get update && sudo apt-get upgrade -y sudo apt-get install -y curl vim htop screen cmake build-essential pkg-config git screen cvs zlib1g zlib1g-dev golang sudo echo "deb http://deb.debian.org/debian bookworm-backports main contrib" >> /etc/apt/sources.list -sudo apt-get update && sudo apt-get install linux-image-amd64/bookworm-backports +sudo apt-get update && sudo apt-get install -y linux-image-amd64/bookworm-backports curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source "$HOME/.cargo/env" # Build aquatic . ./scripts/env-native-cpu-without-avx-512 -cargo build --profile "release-debug" -p aquatic_udp +# export RUSTFLAGS="-C target-cpu=native" +cargo build --profile "release-debug" -p aquatic_udp --features "io-uring" cargo build --profile "release-debug" -p aquatic_udp_load_test cargo build --profile "release-debug" -p aquatic_bencher --features udp git log --oneline | head -n 1