From a627594c3ab9746f239ca366e1f70f6d0db33019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Mon, 6 Apr 2020 12:39:32 +0200 Subject: [PATCH] bench_handlers: parially extract setup portions for better profiling --- TODO.md | 7 +- aquatic/src/bin/bench_handlers/announce.rs | 51 +++------ aquatic/src/bin/bench_handlers/connect.rs | 23 ++-- aquatic/src/bin/bench_handlers/main.rs | 122 +++++++++++++++------ aquatic/src/bin/bench_handlers/scrape.rs | 45 +++----- 5 files changed, 127 insertions(+), 121 deletions(-) diff --git a/TODO.md b/TODO.md index 68590b0..70adff6 100644 --- a/TODO.md +++ b/TODO.md @@ -6,12 +6,13 @@ * Cleaner code * Stack-allocated vector? * Benchmarks - * Seperate setup so actual benchmarks can be run after each other, - enabling better profiling + * Move to own crate (aquatic_bench) + * Better black_box (or make sure to consume data) * Show standard deviation? * Send in connect reponse ids to other functions as integration test +* target-cpu=native ## Don't do -* Other hash algorithms: seemingly not worthwhile +* Other hash algorithms: seemingly not worthwhile (might be with AVX though) * `sendmmsg`: can't send to multiple socket addresses, so doesn't help \ No newline at end of file diff --git a/aquatic/src/bin/bench_handlers/announce.rs b/aquatic/src/bin/bench_handlers/announce.rs index d12ff11..047b20e 100644 --- a/aquatic/src/bin/bench_handlers/announce.rs +++ b/aquatic/src/bin/bench_handlers/announce.rs @@ -1,4 +1,4 @@ -use std::time::{Duration, Instant}; +use std::time::Instant; use std::net::SocketAddr; use rand::Rng; @@ -15,41 +15,19 @@ const ANNOUNCE_REQUESTS: usize = 1_000_000; pub fn bench( - rng: &mut impl Rng, state: &State, - info_hashes: &Vec + requests: Vec<(AnnounceRequest, SocketAddr)>, ) -> (f64, f64) { - println!("## benchmark: handle_announce_requests\n"); - - println!("generating data.."); - let mut responses = Vec::with_capacity(ANNOUNCE_REQUESTS); - - let mut announce_requests = create_announce_requests(rng, &info_hashes); - - let time = Time(Instant::now()); - - for (request, src) in announce_requests.iter() { - let key = ConnectionKey { - connection_id: request.connection_id, - socket_addr: *src, - }; - - state.connections.insert(key, time); - } - - let announce_requests = announce_requests.drain(..); - - ::std::thread::sleep(Duration::from_millis(100)); + let mut requests = requests; + let requests = requests.drain(..); let now = Instant::now(); - println!("running benchmark.."); - handle_announce_requests( &state, &mut responses, - announce_requests, + requests, ); let duration = Instant::now() - now; @@ -57,19 +35,17 @@ pub fn bench( let requests_per_second = ANNOUNCE_REQUESTS as f64 / (duration.as_millis() as f64 / 1000.0); let time_per_request = duration.as_nanos() as f64 / ANNOUNCE_REQUESTS as f64; - println!("\nrequests/second: {:.2}", requests_per_second); - println!("time per request: {:.2}ns", time_per_request); + // println!("\nrequests/second: {:.2}", requests_per_second); + // println!("time per request: {:.2}ns", time_per_request); - let mut total_num_peers = 0.0f64; - let mut max_num_peers = 0.0f64; + // let mut total_num_peers = 0.0f64; let mut num_responses: usize = 0; for (response, _src) in responses.drain(..) { - if let Response::Announce(response) = response { - let n = response.peers.len() as f64; + if let Response::Announce(_response) = response { + // let n = response.peers.len() as f64; - total_num_peers += n; - max_num_peers = max_num_peers.max(n); + // total_num_peers += n; num_responses += 1; } } @@ -78,15 +54,14 @@ pub fn bench( println!("ERROR: only {} responses received", num_responses); } - println!("avg num peers returned: {:.2}", total_num_peers / ANNOUNCE_REQUESTS as f64); - println!("max num peers returned: {:.2}", max_num_peers); + // println!("avg num peers returned: {:.2}", total_num_peers / ANNOUNCE_REQUESTS as f64); (requests_per_second, time_per_request) } -fn create_announce_requests( +pub fn create_requests( rng: &mut impl Rng, info_hashes: &Vec ) -> Vec<(AnnounceRequest, SocketAddr)> { diff --git a/aquatic/src/bin/bench_handlers/connect.rs b/aquatic/src/bin/bench_handlers/connect.rs index fca67aa..205c076 100644 --- a/aquatic/src/bin/bench_handlers/connect.rs +++ b/aquatic/src/bin/bench_handlers/connect.rs @@ -1,4 +1,4 @@ -use std::time::{Instant, Duration}; +use std::time::Instant; use std::net::SocketAddr; use rand::{Rng, thread_rng, rngs::SmallRng, SeedableRng}; @@ -10,19 +10,14 @@ use aquatic::handlers::handle_connect_requests; const ITERATIONS: usize = 10_000_000; -pub fn bench() -> (f64, f64){ - println!("## benchmark: handle_connect_requests\n"); - +pub fn bench( + requests: Vec<(ConnectRequest, SocketAddr)> +) -> (f64, f64){ let state = State::new(); - let mut responses = Vec::new(); - - let mut requests = create_requests(); + let mut responses = Vec::with_capacity(ITERATIONS); + let mut requests = requests; let requests = requests.drain(..); - println!("running benchmark.."); - - ::std::thread::sleep(Duration::from_millis(100)); - let now = Instant::now(); handle_connect_requests(&state, &mut responses, requests); @@ -32,8 +27,8 @@ pub fn bench() -> (f64, f64){ let requests_per_second = ITERATIONS as f64 / (duration.as_millis() as f64 / 1000.0); let time_per_request = duration.as_nanos() as f64 / ITERATIONS as f64; - println!("\nrequests/second: {:.2}", requests_per_second); - println!("time per request: {:.2}ns", time_per_request); + // println!("\nrequests/second: {:.2}", requests_per_second); + // println!("time per request: {:.2}ns", time_per_request); let mut dummy = 0usize; let mut num_responses: usize = 0; @@ -60,7 +55,7 @@ pub fn bench() -> (f64, f64){ } -fn create_requests() -> Vec<(ConnectRequest, SocketAddr)> { +pub fn create_requests() -> Vec<(ConnectRequest, SocketAddr)> { let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let mut requests = Vec::new(); diff --git a/aquatic/src/bin/bench_handlers/main.rs b/aquatic/src/bin/bench_handlers/main.rs index 2d83dba..6ae881a 100644 --- a/aquatic/src/bin/bench_handlers/main.rs +++ b/aquatic/src/bin/bench_handlers/main.rs @@ -2,14 +2,13 @@ //! //! Example summary output: //! ``` -//! # Average results over 20 rounds -//! -//! connect handler: 3 365 415 requests/second, 297.41 ns/request -//! announce handler: 346 650 requests/second, 2921.76 ns/request -//! scrape handler: 1 313 100 requests/second, 762.47 ns/request +//! # Average results over 100 rounds +//! connect handler: 3 201 147 requests/second, 312.66 ns/request +//! announce handler: 330 958 requests/second, 3029.13 ns/request +//! scrape handler: 1 242 478 requests/second, 805.62 ns/request //! ``` -use std::time::Duration; +use std::time::{Duration, Instant}; use num_format::{Locale, ToFormattedString}; use rand::{Rng, thread_rng, rngs::SmallRng, SeedableRng}; @@ -44,44 +43,99 @@ macro_rules! print_results { fn main(){ - let num_rounds = 20; + let num_rounds = 100; let mut connect_data = (0.0, 0.0); let mut announce_data = (0.0, 0.0); let mut scrape_data = (0.0, 0.0); - for round in 0..num_rounds { - println!("# Round {}/{}\n", round + 1, num_rounds); + { + let requests = connect::create_requests(); - let d = connect::bench(); - connect_data.0 += d.0; - connect_data.1 += d.1; + ::std::thread::sleep(Duration::from_secs(1)); - println!(""); + for round in 0..num_rounds { + println!("# Round {}/{}\n", round + 1, num_rounds); - ::std::thread::sleep(Duration::from_millis(100)); - - let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); - let info_hashes = create_info_hashes(&mut rng); - let state = State::new(); - - let d = announce::bench(&mut rng, &state, &info_hashes); - announce_data.0 += d.0; - announce_data.1 += d.1; - - state.connections.clear(); - - println!(""); - - ::std::thread::sleep(Duration::from_millis(100)); - - let d = scrape::bench(&mut rng, &state, &info_hashes); - scrape_data.0 += d.0; - scrape_data.1 += d.1; - - println!(); + let d = connect::bench(requests.clone()); + connect_data.0 += d.0; + connect_data.1 += d.1; + } } + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let info_hashes = create_info_hashes(&mut rng); + + let state_for_scrape: State = { + let requests = announce::create_requests( + &mut rng, + &info_hashes + ); + + let mut state_for_scrape = State::new(); + + ::std::thread::sleep(Duration::from_secs(1)); + + for round in 0..num_rounds { + println!("# Round {}/{}\n", round + 1, num_rounds); + + let state = State::new(); + + let time = Time(Instant::now()); + + for (request, src) in requests.iter() { + let key = ConnectionKey { + connection_id: request.connection_id, + socket_addr: *src, + }; + + state.connections.insert(key, time); + } + + let d = announce::bench(&state, requests.clone()); + announce_data.0 += d.0; + announce_data.1 += d.1; + + if round == num_rounds - 1 { + state_for_scrape = state.clone(); + } + } + + state_for_scrape + }; + + state_for_scrape.connections.clear(); + + { + let state = state_for_scrape; + + let requests = scrape::create_requests(&mut rng, &info_hashes); + + let time = Time(Instant::now()); + + for (request, src) in requests.iter() { + let key = ConnectionKey { + connection_id: request.connection_id, + socket_addr: *src, + }; + + state.connections.insert(key, time); + } + + ::std::thread::sleep(Duration::from_secs(1)); + + for round in 0..num_rounds { + println!("# Round {}/{}\n", round + 1, num_rounds); + + let d = scrape::bench(&state, requests.clone()); + scrape_data.0 += d.0; + scrape_data.1 += d.1; + + println!(); + } + } + + println!("# Average results over {} rounds\n", num_rounds); print_results!("connect handler: ", num_rounds, connect_data); diff --git a/aquatic/src/bin/bench_handlers/scrape.rs b/aquatic/src/bin/bench_handlers/scrape.rs index cc8185c..3fd871b 100644 --- a/aquatic/src/bin/bench_handlers/scrape.rs +++ b/aquatic/src/bin/bench_handlers/scrape.rs @@ -1,4 +1,4 @@ -use std::time::{Duration, Instant}; +use std::time::Instant; use std::net::SocketAddr; use rand::Rng; @@ -16,32 +16,13 @@ const SCRAPE_NUM_HASHES: usize = 10; pub fn bench( - rng: &mut impl Rng, state: &State, - info_hashes: &Vec + requests: Vec<(ScrapeRequest, SocketAddr)>, ) -> (f64, f64) { - println!("## benchmark: handle_scrape_requests\n"); - println!("generating data.."); - let mut responses = Vec::with_capacity(SCRAPE_REQUESTS); - - let mut scrape_requests = create_scrape_requests(rng, &info_hashes); - - let time = Time(Instant::now()); - - for (request, src) in scrape_requests.iter() { - let key = ConnectionKey { - connection_id: request.connection_id, - socket_addr: *src, - }; - - state.connections.insert(key, time); - } - + let mut scrape_requests = requests; let scrape_requests = scrape_requests.drain(..); - ::std::thread::sleep(Duration::from_millis(100)); - let now = Instant::now(); println!("running benchmark.."); @@ -57,18 +38,18 @@ pub fn bench( let requests_per_second = SCRAPE_REQUESTS as f64 / (duration.as_millis() as f64 / 1000.0); let time_per_request = duration.as_nanos() as f64 / SCRAPE_REQUESTS as f64; - println!("\nrequests/second: {:.2}", requests_per_second); - println!("time per request: {:.2}ns", time_per_request); + // println!("\nrequests/second: {:.2}", requests_per_second); + // println!("time per request: {:.2}ns", time_per_request); - let mut total_num_peers = 0.0f64; + // let mut total_num_peers = 0.0f64; let mut num_responses: usize = 0; for (response, _src) in responses.drain(..){ - if let Response::Scrape(response) = response { - for stats in response.torrent_stats { - total_num_peers += f64::from(stats.seeders.0); - total_num_peers += f64::from(stats.leechers.0); - } + if let Response::Scrape(_response) = response { + // for stats in response.torrent_stats { + // total_num_peers += f64::from(stats.seeders.0); + // total_num_peers += f64::from(stats.leechers.0); + // } num_responses += 1; } @@ -78,13 +59,13 @@ pub fn bench( println!("ERROR: only {} responses received", num_responses); } - println!("avg num peers reported: {:.2}", total_num_peers / (SCRAPE_REQUESTS as f64 * SCRAPE_NUM_HASHES as f64)); + // println!("avg num peers reported: {:.2}", total_num_peers / (SCRAPE_REQUESTS as f64 * SCRAPE_NUM_HASHES as f64)); (requests_per_second, time_per_request) } -fn create_scrape_requests( +pub fn create_requests( rng: &mut impl Rng, info_hashes: &Vec ) -> Vec<(ScrapeRequest, SocketAddr)> {