Skip to content

Commit

Permalink
dynamic payload sizing: Skip further tests if threshold exceeded (#43)
Browse files Browse the repository at this point in the history
* WIP dynamic payload sizing: Skip further tests if threshold exceeded

* Cargo fmt

* version bump

* invert dynamic max payload flag, log measurements only if populated

* increase default payload size to 25MB

* improve help text
  • Loading branch information
code-inflation authored Dec 26, 2023
1 parent b57ac8c commit 78e3734
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cfspeedtest"
version = "1.1.3"
version = "1.2.0"
edition = "2021"
license = "MIT"
description = "Unofficial CLI for speed.cloudflare.com"
Expand Down
1 change: 1 addition & 0 deletions examples/simple_speedtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ fn main() {
nr_tests: 5,
nr_latency_tests: 20,
max_payload_size: PayloadSize::M10,
disable_dynamic_max_payload_size: false,
};

let measurements = speed_test(reqwest::blocking::Client::new(), options);
Expand Down
9 changes: 7 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ pub struct SpeedTestCLIOptions {
pub nr_latency_tests: u32,

/// The max payload size in bytes to use [100k, 1m, 10m, 25m or 100m]
#[arg(value_parser = parse_payload_size, short, long, default_value_t = PayloadSize::M10)]
#[arg(value_parser = parse_payload_size, short, long, default_value_t = PayloadSize::M25)]
pub max_payload_size: PayloadSize,

/// Set the output format [csv, json or json-pretty] >
/// This silences all other output to stdout
#[arg(value_parser = parse_output_format, short, long, default_value_t = OutputFormat::StdOut)]
pub output_format: OutputFormat,

/// Enable verbose output i.e. print out boxplots of the measurements
/// Enable verbose output i.e. print boxplots of the measurements
#[arg(short, long)]
pub verbose: bool,

Expand All @@ -67,6 +67,11 @@ pub struct SpeedTestCLIOptions {
/// Force usage of IPv6
#[arg(long)]
pub ipv6: bool,

/// Disables dynamically skipping tests with larger payload sizes if the tests for the previous payload
/// size took longer than 5 seconds
#[arg(short, long)]
pub disable_dynamic_max_payload_size: bool,
}

fn parse_payload_size(input_string: &str) -> Result<PayloadSize, String> {
Expand Down
41 changes: 23 additions & 18 deletions src/measurements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,27 +98,32 @@ fn log_measurements_by_test_type(
.filter(|m| m.payload_size == payload_size)
.map(|m| m.mbit)
.collect();
let (min, q1, median, q3, max, avg) = calc_stats(type_measurements).unwrap();

let formated_payload = format_bytes(payload_size);
let fmt_test_type = format!("{:?}", test_type);
stat_measurements.push(StatMeasurement {
test_type,
payload_size,
min,
q1,
median,
q3,
max,
avg,
});
if output_format == OutputFormat::StdOut {
println!(
// check if there are any measurements for the current payload_size
// skip stats calculation if there are no measurements
if !type_measurements.is_empty() {
let (min, q1, median, q3, max, avg) = calc_stats(type_measurements).unwrap();

let formated_payload = format_bytes(payload_size);
let fmt_test_type = format!("{:?}", test_type);
stat_measurements.push(StatMeasurement {
test_type,
payload_size,
min,
q1,
median,
q3,
max,
avg,
});
if output_format == OutputFormat::StdOut {
println!(
"{fmt_test_type:<9} {formated_payload:<7}| min {min:<7.2} max {max:<7.2} avg {avg:<7.2}"
);
if verbose {
let plot = boxplot::render_plot(min, q1, median, q3, max);
println!("{plot}\n");
if verbose {
let plot = boxplot::render_plot(min, q1, median, q3, max);
println!("{plot}\n");
}
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions src/speedtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub fn speed_test(client: Client, options: SpeedTestCLIOptions) -> Vec<Measureme
payload_sizes.clone(),
options.nr_tests,
options.output_format,
options.disable_dynamic_max_payload_size,
);
measurements.extend(run_tests(
&client,
Expand All @@ -104,6 +105,7 @@ pub fn speed_test(client: Client, options: SpeedTestCLIOptions) -> Vec<Measureme
payload_sizes.clone(),
options.nr_tests,
options.output_format,
options.disable_dynamic_max_payload_size,
));
log_measurements(
&measurements,
Expand Down Expand Up @@ -170,17 +172,21 @@ pub fn test_latency(client: &Client) -> f64 {
req_latency
}

const TIME_THRESHOLD: Duration = Duration::from_secs(5);

pub fn run_tests(
client: &Client,
test_fn: fn(&Client, usize, OutputFormat) -> f64,
test_type: TestType,
payload_sizes: Vec<usize>,
nr_tests: u32,
output_format: OutputFormat,
disable_dynamic_max_payload_size: bool,
) -> Vec<Measurement> {
let mut measurements: Vec<Measurement> = Vec::new();
for payload_size in payload_sizes {
log::debug!("running tests for payload_size {payload_size}");
let start = Instant::now();
for i in 0..nr_tests {
if output_format == OutputFormat::StdOut {
print_progress(
Expand All @@ -204,6 +210,13 @@ pub fn run_tests(
);
println!()
}
let duration = start.elapsed();

// only check TIME_THRESHOLD if dynamic max payload sizing is not disabled
if !disable_dynamic_max_payload_size && duration > TIME_THRESHOLD {
log::info!("Exceeded threshold");
break;
}
}
measurements
}
Expand Down

0 comments on commit 78e3734

Please sign in to comment.