///|
/// Reproducible workload configuration for the command-line benchmark.
pub struct BenchmarkConfig {
requested_sample_count : Int
iterations : Int
sampling_rate_hz : Double
body_mass_kg : Double
} derive(Debug, Eq)
///|
pub fn BenchmarkConfig::new(
requested_sample_count : Int,
iterations : Int,
sampling_rate_hz : Double,
body_mass_kg : Double,
) -> BenchmarkConfig {
{
requested_sample_count: if requested_sample_count < 1 {
1
} else {
requested_sample_count
},
iterations: if iterations < 1 {
1
} else {
iterations
},
sampling_rate_hz: if sampling_rate_hz <= 0.0 || sampling_rate_hz.is_nan() {
1000.0
} else {
sampling_rate_hz
},
body_mass_kg: if body_mass_kg <= 0.0 || body_mass_kg.is_nan() {
70.0
} else {
body_mass_kg
},
}
}
///|
pub struct BenchmarkResult {
iterations : Int
requested_sample_count : Int
actual_sample_count : Int
elapsed_ms : Int
trials_per_second : Double
mean_jump_height_m : Double
checksum_peak_force_n : Double
} derive(Debug, Eq)
///|
pub fn BenchmarkResult::empty() -> BenchmarkResult {
{
iterations: 0,
requested_sample_count: 0,
actual_sample_count: 0,
elapsed_ms: 0,
trials_per_second: 0.0,
mean_jump_height_m: 0.0,
checksum_peak_force_n: 0.0,
}
}
///|
/// Runs the complete synthetic-data CMJ pipeline repeatedly. The returned
/// checksum makes it difficult for a benchmark caller to accidentally measure
/// dead code or omit the analysis result.
pub fn run_cmj_benchmark(config : BenchmarkConfig) -> BenchmarkResult {
let start_ms = @env.now()
let options = @pipeline.PipelineOptions::default()
let mut height_sum = 0.0
let mut peak_sum = 0.0
let mut actual_samples = 0
for iteration = 0; iteration < config.iterations; iteration = iteration + 1 {
let generated = generate_synthetic_cmj_trial(
"benchmark-" + iteration.to_string(),
config.sampling_rate_hz,
config.body_mass_kg,
)
let trial = if generated.length() > config.requested_sample_count {
generated.slice(0, config.requested_sample_count)
} else {
generated
}
actual_samples = trial.length()
let report = @pipeline.run_cmj(trial, config.body_mass_kg, options)
match report.cmj_report {
Some(cmj) => {
height_sum = height_sum + cmj.jump_height_flight_m
peak_sum = peak_sum + cmj.peak_force_n
}
None => ()
}
}
let elapsed_ms = @env.now().to_int() - start_ms.to_int()
let safe_elapsed = if elapsed_ms < 0 { 0 } else { elapsed_ms }
let iterations = config.iterations
{
iterations,
requested_sample_count: config.requested_sample_count,
actual_sample_count: actual_samples,
elapsed_ms: safe_elapsed,
trials_per_second: if safe_elapsed == 0 {
0.0
} else {
iterations.to_double() * 1000.0 / safe_elapsed.to_double()
},
mean_jump_height_m: height_sum / iterations.to_double(),
checksum_peak_force_n: peak_sum,
}
}
///|
pub fn format_benchmark_result(result : BenchmarkResult) -> String {
"iterations=" +
result.iterations.to_string() +
" samples=" +
result.actual_sample_count.to_string() +
" elapsed_ms=" +
result.elapsed_ms.to_string() +
" trials_per_second=" +
result.trials_per_second.to_string() +
" mean_jump_height_m=" +
result.mean_jump_height_m.to_string() +
" checksum_peak_force_n=" +
result.checksum_peak_force_n.to_string()
}