Testing a small http-client on Linux using no_std & embedded reqwless.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add focused RNG benchmark binary and xtask benchmark command

rektide 0a9c0fed fe844f8a

+164 -1
.beads/dolt-monitor.pid.lock

This is a binary file and will not be displayed.

+18
Cargo.lock
··· 507 507 ] 508 508 509 509 [[package]] 510 + name = "getrandom" 511 + version = "0.2.17" 512 + source = "registry+https://github.com/rust-lang/crates.io-index" 513 + checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" 514 + dependencies = [ 515 + "cfg-if", 516 + "libc", 517 + "wasi", 518 + ] 519 + 520 + [[package]] 510 521 name = "ghash" 511 522 version = "0.5.1" 512 523 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 800 811 "embedded-io", 801 812 "embedded-io-async", 802 813 "embedded-nal-async", 814 + "getrandom", 803 815 "libc", 804 816 "reqwless", 805 817 "rustix", ··· 966 978 version = "0.9.5" 967 979 source = "registry+https://github.com/rust-lang/crates.io-index" 968 980 checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 981 + 982 + [[package]] 983 + name = "wasi" 984 + version = "0.11.1+wasi-snapshot-preview1" 985 + source = "registry+https://github.com/rust-lang/crates.io-index" 986 + checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 969 987 970 988 [[package]] 971 989 name = "windows-link"
+2 -1
Cargo.toml
··· 16 16 https = ["reqwless/embedded-tls", "dep:der"] 17 17 rng-dummy = [] 18 18 rng-dev-urandom = [] 19 - rng-getrandom = [] 19 + rng-getrandom = ["dep:getrandom"] 20 20 21 21 [dependencies] 22 22 embedded-io = { version = "0.7", default-features = false } 23 23 embedded-io-async = { version = "0.7", default-features = false } 24 24 embedded-nal-async = { version = "0.9", default-features = false } 25 25 der = { version = "0.8", default-features = false, features = ["derive", "oid", "time", "heapless"], optional = true } 26 + getrandom = { version = "0.2", optional = true } 26 27 libc = { version = "0.2", default-features = false } 27 28 reqwless = { version = "0.14", default-features = false } 28 29 rustix = { version = "1.1", default-features = false, features = ["net"], optional = true }
+59
src/bin/bench-rng.rs
··· 1 + #![allow(clippy::all)] 2 + 3 + use std::env; 4 + use std::time::Instant; 5 + 6 + fn main() { 7 + let args: Vec<String> = env::args().collect(); 8 + let iterations: usize = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(1000); 9 + 10 + println!("Running {iterations} iterations"); 11 + 12 + let start = Instant::now(); 13 + for _ in 0..iterations { 14 + std::hint::black_box(generate_rng_seed()); 15 + } 16 + let elapsed = start.elapsed(); 17 + 18 + let ns_per_iter = elapsed.as_nanos() as f64 / iterations as f64; 19 + println!("{:.2} ns/iter", ns_per_iter); 20 + println!("Total: {:?}", elapsed); 21 + } 22 + 23 + #[cfg(feature = "rng-dummy")] 24 + fn generate_rng_seed() -> u64 { 25 + 0xA17E_5EED_D00D_F00D 26 + } 27 + 28 + #[cfg(all(feature = "rng-dev-urandom", not(feature = "rng-dummy")))] 29 + fn generate_rng_seed() -> u64 { 30 + use std::fs::File; 31 + use std::io::Read; 32 + 33 + let mut buf = [0u8; 8]; 34 + let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom"); 35 + file.read_exact(&mut buf) 36 + .expect("failed to read /dev/urandom"); 37 + u64::from_ne_bytes(buf) 38 + } 39 + 40 + #[cfg(all( 41 + feature = "rng-getrandom", 42 + not(any(feature = "rng-dummy", feature = "rng-dev-urandom")) 43 + ))] 44 + fn generate_rng_seed() -> u64 { 45 + let mut buf = [0u8; 8]; 46 + getrandom::getrandom(&mut buf).expect("getrandom failed"); 47 + u64::from_ne_bytes(buf) 48 + } 49 + 50 + #[cfg(not(any( 51 + feature = "rng-dummy", 52 + feature = "rng-dev-urandom", 53 + feature = "rng-getrandom" 54 + )))] 55 + fn generate_rng_seed() -> u64 { 56 + compile_error!( 57 + "No RNG feature selected. Use --features rng-dummy, rng-dev-urandom, or rng-getrandom" 58 + ); 59 + }
+80
xtask/src/benchmark.rs
··· 1 + use std::process::Command; 2 + 3 + const ITERATIONS: &str = "10000"; 4 + 5 + pub fn run_hyperfine_benchmark() -> Result<(), String> { 6 + check_hyperfine_installed()?; 7 + 8 + let builds = [ 9 + ("rng-dummy", "rng-dummy"), 10 + ("rng-dev-urandom", "rng-dev-urandom"), 11 + ("rng-getrandom", "rng-getrandom"), 12 + ]; 13 + 14 + for (name, rng_feature) in &builds { 15 + build_benchmark_binary(name, rng_feature)?; 16 + } 17 + 18 + run_hyperfine_comparison(&builds) 19 + } 20 + 21 + fn check_hyperfine_installed() -> Result<(), String> { 22 + let output = Command::new("hyperfine") 23 + .arg("--version") 24 + .output() 25 + .map_err(|error| { 26 + format!("hyperfine not found: {error}\nInstall with: cargo install hyperfine") 27 + })?; 28 + 29 + if !output.status.success() { 30 + return Err("hyperfine --version failed".to_owned()); 31 + } 32 + 33 + Ok(()) 34 + } 35 + 36 + fn build_benchmark_binary(name: &str, rng_feature: &str) -> Result<(), String> { 37 + println!("==> Building {name}"); 38 + 39 + let status = Command::new("cargo") 40 + .arg("build") 41 + .arg("--release") 42 + .arg("--bin") 43 + .arg("bench-rng") 44 + .arg("--no-default-features") 45 + .arg("--features") 46 + .arg(rng_feature) 47 + .status() 48 + .map_err(|error| format!("failed to run cargo build: {error}"))?; 49 + 50 + if !status.success() { 51 + return Err(format!("build failed for {name}")); 52 + } 53 + 54 + let target_path = format!("target/release/{name}"); 55 + std::fs::copy("target/release/bench-rng", &target_path) 56 + .map_err(|error| format!("failed to copy binary for {name}: {error}"))?; 57 + 58 + Ok(()) 59 + } 60 + 61 + fn run_hyperfine_comparison(builds: &[(&str, &str)]) -> Result<(), String> { 62 + println!("\n==> Running hyperfine benchmark\n"); 63 + 64 + let mut cmd = Command::new("hyperfine"); 65 + cmd.arg("--warmup").arg("3").arg("--runs").arg("10"); 66 + 67 + for (name, _rng_feature) in builds { 68 + cmd.arg(format!("./target/release/{name} {ITERATIONS}")); 69 + } 70 + 71 + let status = cmd 72 + .status() 73 + .map_err(|error| format!("failed to run hyperfine: {error}"))?; 74 + 75 + if !status.success() { 76 + return Err("hyperfine benchmark failed".to_owned()); 77 + } 78 + 79 + Ok(()) 80 + }
+5
xtask/src/main.rs
··· 1 1 // pattern: Imperative Shell 2 2 3 + mod benchmark; 3 4 mod nightly_size; 4 5 mod validate; 5 6 7 + use benchmark::run_hyperfine_benchmark; 6 8 use clap::{Parser, Subcommand}; 7 9 use nightly_size::run_nightly_size_build; 8 10 use validate::{run_validate_tasks, ValidateTask}; ··· 26 28 #[arg(trailing_var_arg = true, allow_hyphen_values = true)] 27 29 args: Vec<String>, 28 30 }, 31 + /// Run hyperfine benchmarks comparing RNG backends. 32 + Benchmark, 29 33 } 30 34 31 35 fn main() { ··· 40 44 match cli.command { 41 45 Task::Validate { tasks } => run_validate_tasks(&tasks), 42 46 Task::NightlySize { args } => run_nightly_size_build(&args), 47 + Task::Benchmark => run_hyperfine_benchmark(), 43 48 } 44 49 }