Skip to content

Commit d42cdcb

Browse files
add max_payload_size cli arg
1 parent d2f920a commit d42cdcb

File tree

3 files changed

+87
-15
lines changed

3 files changed

+87
-15
lines changed

src/main.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ pub mod speedtest;
55

66
use clap::Parser;
77
use speedtest::speed_test;
8+
use speedtest::PayloadSize;
89

9-
pub const PAYLOAD_SIZES: [usize; 4] = [100_000, 1_000_000, 10_000_000, 25_000_000];
10+
// pub const PAYLOAD_SIZES: [usize; 4] = [100_000, 1_000_000, 10_000_000, 25_000_000];
1011

1112
/// Unofficial CLI for speed.cloudflare.com
1213
#[derive(Parser, Debug)]
1314
#[command(author, version, about, long_about = None)]
1415
struct Args {
16+
#[arg(value_parser = parse_payload_size, short, long, default_value_t = PayloadSize::M10)]
17+
/// The max payload size in bytes to use [100k, 1m, 10m, 25m or 100m]
18+
max_payload_size: PayloadSize,
19+
1520
/// Number of test runs per payload size. Needs to be at least 4
1621
#[arg(value_parser = clap::value_parser!(u32).range(4..1000), short, long, default_value_t = 10)]
1722
nr_tests: u32,
@@ -26,5 +31,14 @@ fn main() {
2631
let args = Args::parse();
2732
println!("Starting Cloudflare speed test");
2833
let client = reqwest::blocking::Client::new();
29-
speed_test(client, args.nr_tests, args.nr_latency_tests);
34+
speed_test(
35+
client,
36+
args.max_payload_size,
37+
args.nr_tests,
38+
args.nr_latency_tests,
39+
);
40+
}
41+
42+
fn parse_payload_size(input_string: &str) -> Result<PayloadSize, String> {
43+
PayloadSize::from(input_string.to_string())
3044
}

src/measurements.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::boxplot;
2-
use crate::speedtest::{TestType, PAYLOAD_SIZES};
2+
use crate::speedtest::TestType;
33
use std::{collections::HashSet, fmt::Display};
44

55
pub(crate) struct Measurement {
@@ -20,18 +20,22 @@ impl Display for Measurement {
2020
}
2121
}
2222

23-
pub(crate) fn log_measurements(measurements: &[Measurement]) {
23+
pub(crate) fn log_measurements(measurements: &[Measurement], payload_sizes: Vec<usize>) {
2424
println!("\n### STATS ###");
2525
measurements
2626
.iter()
2727
.map(|m| m.test_type)
2828
.collect::<HashSet<TestType>>()
2929
.iter()
30-
.for_each(|t| log_measurements_by_test_type(measurements, *t));
30+
.for_each(|t| log_measurements_by_test_type(measurements, payload_sizes.clone(), *t));
3131
}
3232

33-
fn log_measurements_by_test_type(measurements: &[Measurement], test_type: TestType) {
34-
for payload_size in PAYLOAD_SIZES {
33+
fn log_measurements_by_test_type(
34+
measurements: &[Measurement],
35+
payload_sizes: Vec<usize>,
36+
test_type: TestType,
37+
) {
38+
for payload_size in payload_sizes {
3539
let type_measurements: Vec<f64> = measurements
3640
.iter()
3741
.filter(|m| m.test_type == test_type)
@@ -48,6 +52,7 @@ fn log_measurements_by_test_type(measurements: &[Measurement], test_type: TestTy
4852
}
4953

5054
fn calc_stats(mbit_measurements: Vec<f64>) -> Option<(f64, f64, f64, f64, f64, f64)> {
55+
log::debug!("calc_stats for mbit_measurements {mbit_measurements:?}");
5156
let length = mbit_measurements.len();
5257
if length < 4 {
5358
return None;

src/speedtest.rs

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::measurements::format_bytes;
22
use crate::measurements::log_measurements;
33
use crate::measurements::Measurement;
44
use crate::progress::print_progress;
5+
use log;
56
use regex::Regex;
67
use reqwest::{
78
blocking::{Client, RequestBuilder},
@@ -12,19 +13,57 @@ use std::{
1213
fmt::Display,
1314
time::{Duration, Instant},
1415
};
15-
1616
const BASE_URL: &str = "http://speed.cloudflare.com";
1717
const DOWNLOAD_URL: &str = "__down?bytes=";
1818
const UPLOAD_URL: &str = "__up";
19-
// pub const PAYLOAD_SIZES: [usize; 1] = [10_000];
20-
pub const PAYLOAD_SIZES: [usize; 4] = [100_000, 1_000_000, 10_000_000, 25_000_000];
2119

2220
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
2321
pub(crate) enum TestType {
2422
Download,
2523
Upload,
2624
}
2725

26+
#[derive(Clone, Debug)]
27+
pub(crate) enum PayloadSize {
28+
K100 = 100_000,
29+
M1 = 1_000_000,
30+
M10 = 10_000_000,
31+
M25 = 25_000_000,
32+
M100 = 100_000_000,
33+
}
34+
35+
impl Display for PayloadSize {
36+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37+
write!(f, "{}", format_bytes(self.clone() as usize))
38+
}
39+
}
40+
41+
impl PayloadSize {
42+
pub fn from(payload_string: String) -> Result<Self, String> {
43+
match payload_string.to_lowercase().as_str() {
44+
"100_000" | "100000" | "100k" | "100kb" => Ok(Self::K100),
45+
"1_000_000" | "1000000" | "1m" | "1mb" => Ok(Self::M1),
46+
"10_000_000" | "10000000" | "10m" | "10mb" => Ok(Self::M10),
47+
"25_000_000" | "25000000" | "25m" | "25mb" => Ok(Self::M25),
48+
"100_000_000" | "100000000" | "100m" | "100mb" => Ok(Self::M100),
49+
_ => Err("Value needs to be one of 100k, 1m, 10m, 25m or 100m".to_string()),
50+
}
51+
}
52+
53+
fn sizes_from_max(max_payload_size: PayloadSize) -> Vec<usize> {
54+
log::debug!("getting payload iterations for max_payload_size {max_payload_size:?}");
55+
let payload_bytes: Vec<usize> =
56+
vec![100_000, 1_000_000, 10_000_000, 25_000_000, 100_000_000];
57+
match max_payload_size {
58+
PayloadSize::K100 => payload_bytes[0..1].to_vec(),
59+
PayloadSize::M1 => payload_bytes[0..2].to_vec(),
60+
PayloadSize::M10 => payload_bytes[0..3].to_vec(),
61+
PayloadSize::M25 => payload_bytes[0..4].to_vec(),
62+
PayloadSize::M100 => payload_bytes[0..5].to_vec(),
63+
}
64+
}
65+
}
66+
2867
struct Metadata {
2968
city: String,
3069
country: String,
@@ -43,18 +82,31 @@ impl Display for Metadata {
4382
}
4483
}
4584

46-
pub(crate) fn speed_test(client: Client, nr_tests: u32, nr_latency_tests: u32) {
85+
pub(crate) fn speed_test(
86+
client: Client,
87+
max_payload_size: PayloadSize,
88+
nr_tests: u32,
89+
nr_latency_tests: u32,
90+
) {
4791
let metadata = fetch_metadata(&client);
4892
println!("{metadata}");
4993
run_latency_test(&client, nr_latency_tests);
50-
let mut measurements = run_tests(&client, test_download, TestType::Download, nr_tests);
94+
let payload_sizes = PayloadSize::sizes_from_max(max_payload_size);
95+
let mut measurements = run_tests(
96+
&client,
97+
test_download,
98+
TestType::Download,
99+
payload_sizes.clone(),
100+
nr_tests,
101+
);
51102
measurements.append(&mut run_tests(
52103
&client,
53104
test_upload,
54105
TestType::Upload,
106+
payload_sizes.clone(),
55107
nr_tests,
56108
));
57-
log_measurements(&measurements);
109+
log_measurements(&measurements, payload_sizes);
58110
}
59111

60112
fn run_latency_test(client: &Client, nr_latency_tests: u32) -> (Vec<f64>, f64) {
@@ -103,15 +155,16 @@ fn test_latency(client: &Client) -> f64 {
103155
}
104156
req_latency
105157
}
106-
107158
fn run_tests(
108159
client: &Client,
109160
test_fn: fn(&Client, usize) -> f64,
110161
test_type: TestType,
162+
payload_sizes: Vec<usize>,
111163
nr_tests: u32,
112164
) -> Vec<Measurement> {
113165
let mut measurements: Vec<Measurement> = Vec::new();
114-
for payload_size in PAYLOAD_SIZES {
166+
for payload_size in payload_sizes {
167+
log::debug!("running tests for payload_size {payload_size}");
115168
for i in 0..nr_tests {
116169
print_progress(
117170
&format!("{:?} {:<5}", test_type, format_bytes(payload_size)),

0 commit comments

Comments
 (0)