Skip to content

Commit

Permalink
Merge pull request lnx-search#12 from ChillFish8/code-cleanup
Browse files Browse the repository at this point in the history
Code cleanup
  • Loading branch information
ChillFish8 authored Jul 31, 2021
2 parents 374e2b4 + 0c3befa commit 3c34159
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 108 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rewrk"
version = "0.3.0"
version = "0.3.1"
authors = ["Harrison Burt <[email protected]>", "Programatik <[email protected]>"]
edition = "2018"

Expand All @@ -17,3 +17,4 @@ regex = "1.4.*"
rand = "0.8.3"
serde_json = "1"
http = "0.2.4"
anyhow = "1"
45 changes: 25 additions & 20 deletions src/bench.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use anyhow::{Error, Result};
use colored::*;
use std::fmt::Display;
use std::time::Duration;
Expand Down Expand Up @@ -41,9 +42,18 @@ pub fn start_benchmark(settings: BenchmarkSettings) {
let rt = runtime::get_rt(settings.threads);
let rounds = settings.rounds;
let is_json = settings.display_json;
for _ in 0..rounds {
rt.block_on(run(settings.clone()));
for i in 0..rounds {
if !is_json {
println!("Beginning round {}...", i + 1);
}

if let Err(e) = rt.block_on(run(settings.clone())) {
eprintln!("failed to run benchmark round due to error: {:?}", e);
return;
}

// Adds a line separator between rounds unless it's formatting
// as a json, for readability.
if !is_json {
println!();
};
Expand All @@ -59,7 +69,7 @@ pub fn start_benchmark(settings: BenchmarkSettings) {
/// extracted from the handle.
///
/// The results are then merged into a single set of averages across workers.
async fn run(settings: BenchmarkSettings) {
async fn run(settings: BenchmarkSettings) -> Result<()> {
let predict_size = settings.duration.as_secs() * 10_000;

let handles = http::start_tasks(
Expand All @@ -73,10 +83,7 @@ async fn run(settings: BenchmarkSettings) {

let handles = match handles {
Ok(v) => v,
Err(e) => {
eprintln!("error parsing uri: {}", e);
return;
}
Err(e) => return Err(Error::msg(format!("error parsing uri: {}", e))),
};

if !settings.display_json {
Expand All @@ -92,23 +99,19 @@ async fn run(settings: BenchmarkSettings) {
for handle in handles {
let result = match handle.await {
Ok(r) => r,
Err(e) => {
eprintln!("error processing results: {}", e);
return;
}
Err(e) => return Err(Error::msg(format!("error processing results: {}", e))),
};

if let Ok(stats) = result {
combiner = combiner.combine(stats);
} else if let Err(e) = result {
eprintln!("error processing results {}", e);
return;
return Err(Error::msg(format!("error combining results: {}", e)));
}
}

if settings.display_json {
combiner.display_json();
return;
return Ok(());
}

combiner.display_latencies();
Expand All @@ -118,6 +121,8 @@ async fn run(settings: BenchmarkSettings) {
if settings.display_percentile {
combiner.display_percentile_table();
}

Ok(())
}

/// Uber lazy way of just stringing everything and limiting it to 2 d.p
Expand All @@ -137,23 +142,23 @@ fn humanize(time: Duration) -> String {
let (hours, minutes) = div_mod(minutes, 60);
let (days, hours) = div_mod(hours, 24);

let mut human = String::new();
let mut human = Vec::new();

if days != 0 {
human = format!("{} days, ", days);
human.push(format!("{} day(s)", days));
};

if hours != 0 {
human = format!("{}{} hours, ", human, hours);
human.push(format!("{} hour(s)", hours));
};

if minutes != 0 {
human = format!("{}{} minutes, ", human, minutes);
human.push(format!("{} minute(s)", minutes));
};

if seconds != 0 {
human = format!("{}{} seconds", human, seconds);
human.push(format!("{} second(s)", seconds));
};

human
human.join(", ")
}
33 changes: 18 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
extern crate clap;
use crate::http::BenchType;

use anyhow::{Error, Result};
use clap::{App, Arg, ArgMatches};
use regex::Regex;
use tokio::time::Duration;
Expand All @@ -12,9 +13,11 @@ mod results;
mod runtime;
mod utils;

use crate::http::BenchType;

/// Matches a string like '12d 24h 5m 45s' to a regex capture.
static DURATION_MATCH: &str =
"(?P<days>[0-9]*)d|(?P<hours>[0-9]*)h|(?P<minutes>[0-9]*)m|(?P<seconds>[0-9]*)s";
"(?P<days>[0-9]+)d|(?P<hours>[0-9]+)h|(?P<minutes>[0-9]+)m|(?P<seconds>[0-9]+)s";

/// ReWrk
///
Expand All @@ -26,23 +29,23 @@ fn main() {
let threads: usize = match args.value_of("threads").unwrap_or("1").parse() {
Ok(v) => v,
Err(_) => {
println!("Invalid parameter for 'threads' given, input type must be a integer.");
eprintln!("invalid parameter for 'threads' given, input type must be a integer.");
return;
}
};

let conns: usize = match args.value_of("connections").unwrap_or("1").parse() {
Ok(v) => v,
Err(_) => {
println!("Invalid parameter for 'connections' given, input type must be a integer.");
eprintln!("invalid parameter for 'connections' given, input type must be a integer.");
return;
}
};

let host: &str = match args.value_of("host") {
Some(v) => v,
None => {
println!("Missing 'host' parameter.");
eprintln!("missing 'host' parameter.");
return;
}
};
Expand All @@ -60,7 +63,7 @@ fn main() {
let duration = match parse_duration(duration) {
Ok(dur) => dur,
Err(e) => {
eprintln!("{}", e);
eprintln!("failed to parse duration parameter: {}", e);
return;
}
};
Expand Down Expand Up @@ -92,42 +95,42 @@ fn main() {
///
/// If no matches are found for the string or a invalid match
/// is captured a error message returned and displayed.
fn parse_duration(duration: &str) -> Result<Duration, String> {
fn parse_duration(duration: &str) -> Result<Duration> {
let mut dur = Duration::default();

let re = Regex::new(DURATION_MATCH).unwrap();
for cap in re.captures_iter(duration) {
let add_to = if let Some(days) = cap.name("days") {
let days = days.as_str().parse::<u64>().unwrap();
let days = days.as_str().parse::<u64>()?;

let seconds = days * 24 * 60 * 60;
Duration::from_secs(seconds)
} else if let Some(hours) = cap.name("hours") {
let hours = hours.as_str().parse::<u64>().unwrap();
let hours = hours.as_str().parse::<u64>()?;

let seconds = hours * 60 * 60;
Duration::from_secs(seconds)
} else if let Some(minutes) = cap.name("minutes") {
let minutes = minutes.as_str().parse::<u64>().unwrap();
let minutes = minutes.as_str().parse::<u64>()?;

let seconds = minutes * 60;
Duration::from_secs(seconds)
} else if let Some(seconds) = cap.name("seconds") {
let seconds = seconds.as_str().parse::<u64>().unwrap();
let seconds = seconds.as_str().parse::<u64>()?;

Duration::from_secs(seconds)
} else {
return Err(format!("Invalid match: {:?}", cap));
return Err(Error::msg(format!("invalid match: {:?}", cap)));
};

dur += add_to
}

if dur.as_secs() <= 0 {
return Err(format!(
"Failed to extract any valid duration from {}",
return Err(Error::msg(format!(
"failed to extract any valid duration from {}",
duration
));
)));
}

Ok(dur)
Expand Down
97 changes: 25 additions & 72 deletions src/results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ use tokio::time::Duration;

use crate::utils::format_data;

fn get_percentile(request_times: &Vec<Duration>, pct: f64) -> Duration {
let mut len = request_times.len() as f64 * pct;
if len < 1.0 {
len = 1.0;
}

let e = format!("failed to calculate P{} avg latency", (1.0 - pct) * 100f64);
let pct = request_times
.chunks(len as usize)
.next()
.expect(&e);

let total: f64 = pct.iter().map(|dur| dur.as_secs_f64()).sum();

let avg = total / pct.len() as f64;

Duration::from_secs_f64(avg)
}

/// Contains and handles results from the workers
pub struct WorkerResult {
/// The total time taken for each worker.
Expand Down Expand Up @@ -139,98 +158,32 @@ impl WorkerResult {

/// Works out the average latency of the 99.9 percentile.
pub fn p999_avg_latency(&self) -> Duration {
let len = self.request_times.len() as f64 * 0.001;
let p999 = self
.request_times
.chunks(len as usize)
.next()
.expect("Failed to calculate P99.9 avg latency");

let total: f64 = p999.iter().map(|dur| dur.as_secs_f64()).sum();

let avg = total / p999.len() as f64;

Duration::from_secs_f64(avg)
get_percentile(&self.request_times, 0.001)
}

/// Works out the average latency of the 99 percentile.
pub fn p99_avg_latency(&self) -> Duration {
let len = self.request_times.len() as f64 * 0.01;
let p99 = self
.request_times
.chunks(len as usize)
.next()
.expect("Failed to calculate P99 avg latency");

let total: f64 = p99.iter().map(|dur| dur.as_secs_f64()).sum();

let avg = total / p99.len() as f64;

Duration::from_secs_f64(avg)
get_percentile(&self.request_times, 0.01)
}

/// Works out the average latency of the 95 percentile.
pub fn p95_avg_latency(&self) -> Duration {
let len = self.request_times.len() as f64 * 0.05;
let p95 = self
.request_times
.chunks(len as usize)
.next()
.expect("Failed to calculate P95 avg latency");

let total: f64 = p95.iter().map(|dur| dur.as_secs_f64()).sum();

let avg = total / p95.len() as f64;

Duration::from_secs_f64(avg)
get_percentile(&self.request_times, 0.05)
}

/// Works out the average latency of the 90 percentile.
pub fn p90_avg_latency(&self) -> Duration {
let len = self.request_times.len() as f64 * 0.10;
let p90 = self
.request_times
.chunks(len as usize)
.next()
.expect("Failed to calculate P90 avg latency");

let total: f64 = p90.iter().map(|dur| dur.as_secs_f64()).sum();

let avg = total / p90.len() as f64;

Duration::from_secs_f64(avg)
get_percentile(&self.request_times, 0.1)
}

/// Works out the average latency of the 75 percentile.
pub fn p75_avg_latency(&mut self) -> Duration {
let len = self.request_times.len() as f64 * 0.25;
let p75 = self
.request_times
.chunks(len as usize)
.next()
.expect("Failed to calculate P75 avg latency");

let total: f64 = p75.iter().map(|dur| dur.as_secs_f64()).sum();

let avg = total / p75.len() as f64;

Duration::from_secs_f64(avg)
get_percentile(&self.request_times, 0.25)
}

/// Works out the average latency of the 50 percentile.
pub fn p50_avg_latency(&mut self) -> Duration {
let len = self.request_times.len() / 2;
let p50 = self
.request_times
.chunks(len)
.next()
.expect("Failed to calculate P50 avg latency");

let total: f64 = p50.iter().map(|dur| dur.as_secs_f64()).sum();

let avg = total / p50.len() as f64;

Duration::from_secs_f64(avg)
get_percentile(&self.request_times, 0.5)
}

pub fn display_latencies(&mut self) {
Expand Down

0 comments on commit 3c34159

Please sign in to comment.