From 93a8858ba0a8d8095da1dac2be3751a57aa645ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ko=C5=82aczkowski?= Date: Wed, 15 Dec 2021 16:44:04 +0100 Subject: [PATCH] Rename iterations to cycles --- README.md | 6 +-- src/config.rs | 13 +++-- src/{iteration.rs => cycle.rs} | 59 ++++++++++---------- src/exec.rs | 28 +++++----- src/main.rs | 10 ++-- src/report.rs | 16 +++--- src/sampler.rs | 12 ++--- src/stats.rs | 98 +++++++++++++++++----------------- src/workload.rs | 12 ++--- 9 files changed, 127 insertions(+), 127 deletions(-) rename src/{iteration.rs => cycle.rs} (63%) diff --git a/README.md b/README.md index 689afb5..cf87b3e 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Latte has the following unique performance characteristics: This means you can test large clusters with a small number of clients. * About 50x-100x lower memory footprint than Java-based tools. * Very low impact on operating system resources – low number of syscalls, context switches and page faults. -* No client code warmup needed. The client code works with maximum performance from the first iteration. +* No client code warmup needed. The client code works with maximum performance from the first benchmark cycle. Even runs as short as 30 seconds give accurate results. * No GC pauses nor HotSpot recompilation happening in the middle of the test. You want to measure hiccups of the server, not the benchmarking tool. @@ -110,7 +110,7 @@ A workload script defines a set of public functions that Latte calls automatical must define at least a single public async function `run` with two arguments: - `ctx` – session context that provides the access to Cassandra -- `i` – current unique iteration number of a 64-bit integer type, starting at 0 +- `i` – current unique cycle number of a 64-bit integer type, starting at 0 The following script would benchmark querying the `system.local` table: @@ -181,7 +181,7 @@ If needed, you can skip the loading phase by passing `--no-load` command line fl ### Generating data Latte comes with a library of data generating functions. They are accessible in the `latte` crate. Typically, those -functions accept an integer `i` iteration number, so you can generate consistent numbers. The data generating functions +functions accept an integer `i` cycle number, so you can generate consistent numbers. The data generating functions are pure, i.e. invoking them multiple times with the same parameters yields always the same results. - `latte::uuid(i)` – generates a random (type 4) UUID diff --git a/src/config.rs b/src/config.rs index c60560e..05af41f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -63,7 +63,7 @@ impl Interval { } } -/// If the string is a valid integer, it is assumed to be the number of iterations. +/// If the string is a valid integer, it is assumed to be the number of cycles. /// If the string additionally contains a time unit, e.g. "s" or "secs", it is parsed /// as time duration. impl FromStr for Interval { @@ -75,7 +75,7 @@ impl FromStr for Interval { } else if let Ok(d) = parse_duration::parse(s) { Ok(Interval::Time(d)) } else { - Err("Required integer number of iterations or time duration".to_string()) + Err("Required integer number of cycles or time duration".to_string()) } } } @@ -86,13 +86,12 @@ impl FromStr for Interval { setting(AppSettings::DeriveDisplayOrder) )] pub struct RunCommand { - /// Number of requests per second to send. - /// If not given or zero the requests will be sent as fast as possible within - /// the parallelism limit + /// Number of cycles per second to execute. + /// If not given, the benchmark cycles will be executed as fast as possible. #[clap(short('r'), long, value_name = "COUNT")] pub rate: Option, - /// Number of iterations or time duration of the warmup phase + /// Number of cycles or duration of the warmup phase #[clap( short('w'), long("warmup"), @@ -101,7 +100,7 @@ pub struct RunCommand { )] pub warmup_duration: Interval, - /// Number of iterations or time duration of the main benchmark phase + /// Number of cycles or duration of the main benchmark phase #[clap( short('d'), long("duration"), diff --git a/src/iteration.rs b/src/cycle.rs similarity index 63% rename from src/iteration.rs rename to src/cycle.rs index 887e58d..596bfac 100644 --- a/src/iteration.rs +++ b/src/cycle.rs @@ -6,26 +6,27 @@ use std::time::Instant; const BATCH_SIZE: u64 = 64; -/// Provides distinct benchmark iteration numbers to multiple threads of execution. -pub struct IterationCounter { +/// Provides distinct benchmark cycle numbers to multiple threads of execution. +/// Cycle numbers increase and never repeat. +pub struct CycleCounter { shared: Arc, local: u64, local_max: u64, } -impl IterationCounter { - /// Creates a new iteration counter, starting at `start`. +impl CycleCounter { + /// Creates a new cycle counter, starting at `start`. /// The counter is logically positioned at one item before `start`, so the first call /// to `next` will return `start`. pub fn new(start: u64) -> Self { - IterationCounter { + CycleCounter { shared: Arc::new(AtomicU64::new(start)), local: 0, // the value does not matter as long as it is not lower than local_max local_max: 0, // force getting the shared count in the first call to `next` } } - /// Gets the next iteration number and advances the counter by one + /// Gets the next cycle number and advances the counter by one. pub fn next(&mut self) -> u64 { if self.local >= self.local_max { self.next_batch(); @@ -35,16 +36,16 @@ impl IterationCounter { result } - /// Reserves the next batch of iterations + /// Reserves the next batch of cycles. fn next_batch(&mut self) { self.local = self.shared.fetch_add(BATCH_SIZE, Ordering::Relaxed); self.local_max = self.local + BATCH_SIZE; } - /// Creates a new counter sharing the list of iterations with this one. - /// The new counter will never return the same iteration number as this one. - pub fn share(&self) -> IterationCounter { - IterationCounter { + /// Creates a new counter sharing the list of cycles with this one. + /// The new counter will never return the same cycle number as this one. + pub fn share(&self) -> CycleCounter { + CycleCounter { shared: self.shared.clone(), local: 0, local_max: 0, @@ -52,30 +53,30 @@ impl IterationCounter { } } -/// Provides distinct benchmark iteration numbers to multiple threads of execution. +/// Provides distinct benchmark cycle numbers to multiple threads of execution. /// Decides when to stop the benchmark execution. -pub struct BoundedIterationCounter { +pub struct BoundedCycleCounter { pub duration: config::Interval, start_time: Instant, - iteration_counter: IterationCounter, + cycle_counter: CycleCounter, } -impl BoundedIterationCounter { - /// Creates a new iteration counter based on configured benchmark duration. +impl BoundedCycleCounter { + /// Creates a new counter based on configured benchmark duration. /// For time-based deadline, the clock starts ticking when this object is created. pub fn new(duration: config::Interval) -> Self { - BoundedIterationCounter { + BoundedCycleCounter { duration, start_time: Instant::now(), - iteration_counter: IterationCounter::new(0), + cycle_counter: CycleCounter::new(0), } } - /// Returns the next iteration number or `None` if deadline or iteration count was exceeded. + /// Returns the next cycle number or `None` if deadline or cycle count was exceeded. pub fn next(&mut self) -> Option { match self.duration { Interval::Count(count) => { - let result = self.iteration_counter.next(); + let result = self.cycle_counter.next(); if result < count { Some(result) } else { @@ -84,34 +85,34 @@ impl BoundedIterationCounter { } Interval::Time(duration) => { if Instant::now() < self.start_time + duration { - Some(self.iteration_counter.next()) + Some(self.cycle_counter.next()) } else { None } } - Interval::Unbounded => Some(self.iteration_counter.next()), + Interval::Unbounded => Some(self.cycle_counter.next()), } } /// Shares this counter e.g. with another thread. pub fn share(&self) -> Self { - BoundedIterationCounter { + BoundedCycleCounter { start_time: self.start_time, duration: self.duration, - iteration_counter: self.iteration_counter.share(), + cycle_counter: self.cycle_counter.share(), } } } #[cfg(test)] mod test { - use crate::iteration::{IterationCounter, BATCH_SIZE}; + use crate::cycle::{CycleCounter, BATCH_SIZE}; use itertools::Itertools; use std::collections::BTreeSet; #[test] - pub fn iteration_counter_must_return_all_numbers() { - let mut counter = IterationCounter::new(10); + pub fn cycle_counter_must_return_all_numbers() { + let mut counter = CycleCounter::new(10); for i in 10..(10 + 2 * BATCH_SIZE) { let iter = counter.next(); assert_eq!(i, iter) @@ -119,8 +120,8 @@ mod test { } #[test] - pub fn shared_iteration_counter_must_return_distinct_numbers() { - let mut counter1 = IterationCounter::new(10); + pub fn shared_cycle_counter_must_return_distinct_numbers() { + let mut counter1 = CycleCounter::new(10); let mut counter2 = counter1.share(); let mut set1 = BTreeSet::new(); let mut set2 = BTreeSet::new(); diff --git a/src/exec.rs b/src/exec.rs index 25a0c70..93aaa36 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -13,8 +13,8 @@ use tokio_stream::wrappers::IntervalStream; use crate::error::Result; use crate::{ - BenchmarkStats, BoundedIterationCounter, InterruptHandler, Interval, Progress, Recorder, - Sampler, Workload, WorkloadStats, + BenchmarkStats, BoundedCycleCounter, InterruptHandler, Interval, Progress, Recorder, Sampler, + Workload, WorkloadStats, }; /// Returns a stream emitting `rate` events per second. @@ -23,16 +23,16 @@ fn interval_stream(rate: f64) -> IntervalStream { IntervalStream::new(tokio::time::interval(interval)) } -/// Runs a stream of workload iterations till completion in the context of the current task. +/// Runs a stream of workload cycles till completion in the context of the current task. /// Periodically sends workload statistics to the `out` channel. /// /// # Parameters -/// - stream: a stream of iteration numbers; None means the end of the stream +/// - stream: a stream of cycle numbers; None means the end of the stream /// - workload: defines the function to call -/// - iter_counter: shared iteration numbers provider +/// - cycle_counter: shared cycle numbers provider /// - concurrency: the maximum number of pending workload calls /// - sampling: controls when to output workload statistics -/// - progress: progress bar notified about each successful iteration +/// - progress: progress bar notified about each successful cycle /// - interrupt: allows for terminating the stream early /// - out: the channel to receive workload statistics /// @@ -40,7 +40,7 @@ fn interval_stream(rate: f64) -> IntervalStream { async fn run_stream( stream: impl Stream + std::marker::Unpin, workload: Workload, - iter_counter: BoundedIterationCounter, + cycle_counter: BoundedCycleCounter, concurrency: NonZeroUsize, sampling: Interval, interrupt: Arc, @@ -49,7 +49,7 @@ async fn run_stream( ) { workload.reset(Instant::now()); - let mut iter_counter = iter_counter; + let mut iter_counter = cycle_counter; let mut sampler = Sampler::new(iter_counter.duration, sampling, &workload, &mut out); let mut result_stream = stream @@ -62,7 +62,7 @@ async fn run_stream( while let Some(res) = result_stream.next().await { match res { - Ok((iter, end_time)) => sampler.iteration_completed(iter, end_time).await, + Ok((iter, end_time)) => sampler.cycle_completed(iter, end_time).await, Err(e) => { out.send(Err(e)).await.unwrap(); return; @@ -78,8 +78,8 @@ async fn run_stream( /// Launches a new worker task that runs a series of invocations of the workload function. /// -/// The task will run as long as `deadline` produces new iteration numbers. -/// The task updates the `progress` bar after each successful iteration. +/// The task will run as long as `deadline` produces new cycle numbers. +/// The task updates the `progress` bar after each successful cycle. /// /// Returns a stream where workload statistics are published. fn spawn_stream( @@ -87,7 +87,7 @@ fn spawn_stream( rate: Option, sampling: Interval, workload: Workload, - iter_counter: BoundedIterationCounter, + iter_counter: BoundedCycleCounter, interrupt: Arc, progress: Arc>, ) -> Receiver> { @@ -161,7 +161,7 @@ pub struct ExecutionOptions { /// /// # Parameters /// - `name`: text displayed next to the progress bar -/// - `count`: number of iterations +/// - `count`: number of cycles /// - `exec_options`: controls execution options such as parallelism level and rate /// - `workload`: encapsulates a set of queries to execute pub async fn par_execute( @@ -185,7 +185,7 @@ pub async fn par_execute( ..Default::default() }; let progress = Arc::new(StatusLine::with_options(progress, progress_opts)); - let deadline = BoundedIterationCounter::new(exec_options.duration); + let deadline = BoundedCycleCounter::new(exec_options.duration); let mut streams = Vec::with_capacity(thread_count); let mut stats = Recorder::start(rate, concurrency); diff --git a/src/main.rs b/src/main.rs index ca7dd84..b06694d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,10 +14,10 @@ use tokio::runtime::Builder; use config::RunCommand; use crate::config::{AppConfig, Command, HdrCommand, Interval, ShowCommand}; +use crate::cycle::BoundedCycleCounter; use crate::error::{LatteError, Result}; use crate::exec::{par_execute, ExecutionOptions}; use crate::interrupt::InterruptHandler; -use crate::iteration::BoundedIterationCounter; use crate::progress::Progress; use crate::report::{Report, RunConfigCmp}; use crate::sampler::Sampler; @@ -27,11 +27,11 @@ use crate::stats::{BenchmarkCmp, BenchmarkStats, Recorder}; use crate::workload::{FnRef, Workload, WorkloadStats, LOAD_FN, RUN_FN}; mod config; +mod cycle; mod error; mod exec; mod histogram; mod interrupt; -mod iteration; mod progress; mod report; mod sampler; @@ -293,16 +293,16 @@ async fn export_hdr_log(conf: HdrCommand) -> Result<()> { let interval_start_time = Duration::from_millis((sample.time_s * 1000.0) as u64); let interval_duration = Duration::from_millis((sample.duration_s * 1000.0) as u64); log_writer.write_histogram( - &sample.call_time_histogram_ns.0, + &sample.cycle_time_histogram_ns.0, interval_start_time, interval_duration, - Tag::new("call_time"), + Tag::new("cycles"), )?; log_writer.write_histogram( &sample.resp_time_histogram_ns.0, interval_start_time, interval_duration, - Tag::new("resp_time"), + Tag::new("requests"), )?; } Ok(()) diff --git a/src/report.rs b/src/report.rs index 923c116..eacf739 100644 --- a/src/report.rs +++ b/src/report.rs @@ -535,7 +535,7 @@ impl Display for Sample { f, "{:8.3} {:11.0} {:11.0} {:9.3} {:9.3} {:9.3} {:9.3} {:9.3} {:9.3} {:9.3} {:9.3} {:9.3}", self.time_s + self.duration_s, - self.call_throughput, + self.cycle_throughput, self.req_throughput, self.resp_time_percentiles[Percentile::Min as usize], self.resp_time_percentiles[Percentile::P25 as usize], @@ -586,14 +586,14 @@ impl<'a> Display for BenchmarkCmp<'a> { self.line("CPU utilisation", "%", |s| { Quantity::from(s.cpu_util).with_precision(1) }), - self.line("Calls", "op", |s| Quantity::from(s.call_count)), + self.line("Cycles", "op", |s| Quantity::from(s.cycle_count)), self.line("Errors", "op", |s| Quantity::from(s.error_count)), self.line("└─", "%", |s| { Quantity::from(s.errors_ratio).with_precision(1) }), self.line("Requests", "req", |s| Quantity::from(s.request_count)), self.line("└─", "req/op", |s| { - Quantity::from(s.requests_per_call).with_precision(1) + Quantity::from(s.requests_per_cycle).with_precision(1) }), self.line("Rows", "row", |s| Quantity::from(s.row_count)), self.line("└─", "row/req", |s| { @@ -601,15 +601,15 @@ impl<'a> Display for BenchmarkCmp<'a> { }), self.line("Samples", "", |s| Quantity::from(s.log.len())), self.line("Mean sample size", "op", |s| { - Quantity::from(s.log.iter().map(|s| s.call_count as f64).mean()) + Quantity::from(s.log.iter().map(|s| s.cycle_count as f64).mean()) }), self.line("└─", "req", |s| { Quantity::from(s.log.iter().map(|s| s.request_count as f64).mean()) }), self.line("Concurrency", "req", |s| Quantity::from(s.concurrency)), self.line("└─", "%", |s| Quantity::from(s.concurrency_ratio)), - self.line("Throughput", "op/s", |s| Quantity::from(s.call_throughput)) - .with_significance(self.cmp_call_throughput()) + self.line("Throughput", "op/s", |s| Quantity::from(s.cycle_throughput)) + .with_significance(self.cmp_cycle_throughput()) .with_orientation(1) .into_box(), self.line("├─", "req/s", |s| Quantity::from(s.req_throughput)) @@ -620,8 +620,8 @@ impl<'a> Display for BenchmarkCmp<'a> { .with_significance(self.cmp_row_throughput()) .with_orientation(1) .into_box(), - self.line("Mean call time", "ms", |s| { - Quantity::from(&s.call_time_ms).with_precision(3) + self.line("Mean cycle time", "ms", |s| { + Quantity::from(&s.cycle_time_ms).with_precision(3) }) .with_significance(self.cmp_mean_resp_time()) .with_orientation(-1) diff --git a/src/sampler.rs b/src/sampler.rs index 3b921b1..45f11ec 100644 --- a/src/sampler.rs +++ b/src/sampler.rs @@ -14,7 +14,7 @@ pub struct Sampler<'a> { output: &'a mut Sender>, start_time: Instant, last_snapshot_time: Instant, - last_snapshot_iter: u64, + last_snapshot_cycle: u64, } impl<'a> Sampler<'a> { @@ -32,15 +32,15 @@ impl<'a> Sampler<'a> { output, start_time, last_snapshot_time: start_time, - last_snapshot_iter: 0, + last_snapshot_cycle: 0, } } /// Should be called when a workload iteration finished. /// If there comes the time, it will send the stats to the output. - pub async fn iteration_completed(&mut self, iteration: u64, now: Instant) { + pub async fn cycle_completed(&mut self, iteration: u64, now: Instant) { let current_interval_duration = now - self.last_snapshot_time; - let current_interval_iter_count = iteration - self.last_snapshot_iter; + let current_interval_iter_count = iteration - self.last_snapshot_cycle; // Don't snapshot if we're too close to the end of the run, // to avoid excessively small samples: @@ -58,9 +58,9 @@ impl<'a> Sampler<'a> { } } Interval::Count(cnt) => { - if iteration > self.last_snapshot_iter + cnt && far_from_the_end { + if iteration > self.last_snapshot_cycle + cnt && far_from_the_end { self.send_stats().await; - self.last_snapshot_iter += cnt; + self.last_snapshot_cycle += cnt; } } Interval::Unbounded => {} diff --git a/src/stats.rs b/src/stats.rs index ebb7646..0639cfa 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -263,28 +263,28 @@ impl Percentile { pub struct Sample { pub time_s: f32, pub duration_s: f32, - pub call_count: u64, + pub cycle_count: u64, pub request_count: u64, pub error_count: u64, pub errors: HashSet, pub row_count: u64, pub mean_queue_len: f32, - pub call_throughput: f32, + pub cycle_throughput: f32, pub req_throughput: f32, pub row_throughput: f32, - pub mean_call_time_ms: f32, + pub mean_cycle_time_ms: f32, pub mean_resp_time_ms: f32, - pub call_time_percentiles: [f32; Percentile::COUNT], + pub cycle_time_percentiles: [f32; Percentile::COUNT], pub resp_time_percentiles: [f32; Percentile::COUNT], - pub call_time_histogram_ns: SerializableHistogram, + pub cycle_time_histogram_ns: SerializableHistogram, pub resp_time_histogram_ns: SerializableHistogram, } impl Sample { pub fn new(base_start_time: Instant, stats: &[WorkloadStats]) -> Sample { assert!(!stats.is_empty()); - let mut call_count = 0; - let mut call_times_ns = Histogram::new(3).unwrap(); + let mut cycle_count = 0; + let mut cycle_times_ns = Histogram::new(3).unwrap(); let mut request_count = 0; let mut row_count = 0; @@ -294,7 +294,7 @@ impl Sample { let mut duration_s = 0.0; let mut resp_times_ns = Histogram::new(3).unwrap(); - let mut call_time_histogram_ns = Histogram::new(3).unwrap(); + let mut cycle_time_histogram_ns = Histogram::new(3).unwrap(); let mut resp_time_histogram_ns = Histogram::new(3).unwrap(); for s in stats { @@ -311,28 +311,28 @@ impl Sample { resp_times_ns.add(&ss.resp_times_ns).unwrap(); resp_time_histogram_ns.add(&ss.resp_times_ns).unwrap(); - call_count += fs.call_count; - call_times_ns.add(&fs.call_times_ns).unwrap(); - call_time_histogram_ns.add(&fs.call_times_ns).unwrap(); + cycle_count += fs.call_count; + cycle_times_ns.add(&fs.call_times_ns).unwrap(); + cycle_time_histogram_ns.add(&fs.call_times_ns).unwrap(); } let resp_time_percentiles = percentiles_ms(&resp_times_ns); - let call_time_percentiles = percentiles_ms(&call_times_ns); + let call_time_percentiles = percentiles_ms(&cycle_times_ns); Sample { time_s: (stats[0].start_time - base_start_time).as_secs_f32(), duration_s, - call_count, + cycle_count, request_count, row_count, error_count, errors, mean_queue_len: not_nan_f32(mean_queue_len).unwrap_or(0.0), - call_throughput: call_count as f32 / duration_s, + cycle_throughput: cycle_count as f32 / duration_s, req_throughput: request_count as f32 / duration_s, row_throughput: row_count as f32 / duration_s, - mean_call_time_ms: call_times_ns.mean() as f32 / 1000000.0, - call_time_histogram_ns: SerializableHistogram(call_time_histogram_ns), - call_time_percentiles, + mean_cycle_time_ms: cycle_times_ns.mean() as f32 / 1000000.0, + cycle_time_histogram_ns: SerializableHistogram(cycle_time_histogram_ns), + cycle_time_percentiles: call_time_percentiles, mean_resp_time_ms: resp_times_ns.mean() as f32 / 1000000.0, resp_time_percentiles, resp_time_histogram_ns: SerializableHistogram(resp_time_histogram_ns), @@ -358,7 +358,7 @@ impl Log { } fn weights_by_call_count(&self) -> Vec { - self.samples.iter().map(|s| s.call_count as f32).collect() + self.samples.iter().map(|s| s.cycle_count as f32).collect() } fn weights_by_request_count(&self) -> Vec { @@ -369,7 +369,7 @@ impl Log { } fn call_throughput(&self) -> Mean { - let t: Vec = self.samples.iter().map(|s| s.call_throughput).collect(); + let t: Vec = self.samples.iter().map(|s| s.cycle_throughput).collect(); let w: Vec = self.samples.iter().map(|s| s.duration_s).collect(); Mean::compute(t.as_slice(), w.as_slice()) } @@ -402,17 +402,17 @@ impl Log { Mean::compute(t.as_slice(), w.as_slice()) } - fn call_time_ms(&self) -> Mean { - let t: Vec = self.samples.iter().map(|s| s.mean_call_time_ms).collect(); + fn cycle_time_ms(&self) -> Mean { + let t: Vec = self.samples.iter().map(|s| s.mean_cycle_time_ms).collect(); let w = self.weights_by_call_count(); Mean::compute(t.as_slice(), w.as_slice()) } - fn call_time_percentile(&self, p: Percentile) -> Mean { + fn cycle_time_percentile(&self, p: Percentile) -> Mean { let t: Vec = self .samples .iter() - .map(|s| s.call_time_percentiles[p as usize]) + .map(|s| s.cycle_time_percentiles[p as usize]) .collect(); let w = self.weights_by_call_count(); Mean::compute(t.as_slice(), w.as_slice()) @@ -457,19 +457,19 @@ pub struct BenchmarkStats { pub elapsed_time_s: f64, pub cpu_time_s: f64, pub cpu_util: f64, - pub call_count: u64, + pub cycle_count: u64, pub request_count: u64, - pub requests_per_call: f64, + pub requests_per_cycle: f64, pub errors: Vec, pub error_count: u64, pub errors_ratio: Option, pub row_count: u64, pub row_count_per_req: Option, - pub call_throughput: Mean, - pub call_throughput_ratio: Option, + pub cycle_throughput: Mean, + pub cycle_throughput_ratio: Option, pub req_throughput: Mean, pub row_throughput: Mean, - pub call_time_ms: TimeDistribution, + pub cycle_time_ms: TimeDistribution, pub resp_time_ms: Option, pub concurrency: Mean, pub concurrency_ratio: f64, @@ -505,8 +505,8 @@ impl BenchmarkCmp<'_> { /// Checks if call throughput means of two benchmark runs are significantly different. /// Returns None if the second benchmark is unset. - pub fn cmp_call_throughput(&self) -> Option { - self.cmp(|s| Some(s.call_throughput)) + pub fn cmp_cycle_throughput(&self) -> Option { + self.cmp(|s| Some(s.cycle_throughput)) } /// Checks if request throughput means of two benchmark runs are significantly different. @@ -545,12 +545,12 @@ pub struct Recorder { pub end_instant: Instant, pub start_cpu_time: ProcessTime, pub end_cpu_time: ProcessTime, - pub call_count: u64, + pub cycle_count: u64, pub request_count: u64, pub errors: HashSet, pub error_count: u64, pub row_count: u64, - pub call_times_ns: Histogram, + pub cycle_times_ns: Histogram, pub resp_times_ns: Histogram, pub queue_len_sum: u64, log: Log, @@ -575,12 +575,12 @@ impl Recorder { log: Log::new(), rate_limit, concurrency_limit, - call_count: 0, + cycle_count: 0, request_count: 0, row_count: 0, errors: HashSet::new(), error_count: 0, - call_times_ns: Histogram::new(3).unwrap(), + cycle_times_ns: Histogram::new(3).unwrap(), resp_times_ns: Histogram::new(3).unwrap(), queue_len_sum: 0, } @@ -593,12 +593,12 @@ impl Recorder { self.resp_times_ns .add(&s.session_stats.resp_times_ns) .unwrap(); - self.call_times_ns + self.cycle_times_ns .add(&s.function_stats.call_times_ns) .unwrap(); } let stats = Sample::new(self.start_instant, samples); - self.call_count += stats.call_count; + self.cycle_count += stats.cycle_count; self.request_count += stats.request_count; self.row_count += stats.row_count; if self.errors.len() < MAX_KEPT_ERRORS { @@ -627,17 +627,17 @@ impl Recorder { let cpu_util = 100.0 * cpu_time_s / elapsed_time_s / num_cpus::get() as f64; let count = self.request_count + self.error_count; - let call_throughput = self.log.call_throughput(); - let call_throughput_ratio = self + let cycle_throughput = self.log.call_throughput(); + let cycle_throughput_ratio = self .rate_limit - .map(|r| 100.0 * call_throughput.value as f64 / r as f64); + .map(|r| 100.0 * cycle_throughput.value as f64 / r as f64); let req_throughput = self.log.req_throughput(); let row_throughput = self.log.row_throughput(); let concurrency = self.log.mean_concurrency(); let concurrency_ratio = 100.0 * concurrency.value / self.concurrency_limit.get() as f64; - let call_time_percentiles: Vec = Percentile::iter() - .map(|p| self.log.call_time_percentile(p)) + let cycle_time_percentiles: Vec = Percentile::iter() + .map(|p| self.log.cycle_time_percentile(p)) .collect(); let resp_time_percentiles: Vec = Percentile::iter() .map(|p| self.log.resp_time_percentile(p)) @@ -649,22 +649,22 @@ impl Recorder { elapsed_time_s, cpu_time_s, cpu_util, - call_count: self.call_count, + cycle_count: self.cycle_count, errors: self.errors.into_iter().collect(), error_count: self.error_count, errors_ratio: not_nan(100.0 * self.error_count as f64 / count as f64), request_count: self.request_count, - requests_per_call: self.request_count as f64 / self.call_count as f64, + requests_per_cycle: self.request_count as f64 / self.cycle_count as f64, row_count: self.row_count, row_count_per_req: not_nan(self.row_count as f64 / self.request_count as f64), - call_throughput, - call_throughput_ratio, + cycle_throughput, + cycle_throughput_ratio, req_throughput, row_throughput, - call_time_ms: TimeDistribution { - mean: self.log.call_time_ms(), - percentiles: call_time_percentiles, - distribution: distribution(&self.call_times_ns), + cycle_time_ms: TimeDistribution { + mean: self.log.cycle_time_ms(), + percentiles: cycle_time_percentiles, + distribution: distribution(&self.cycle_times_ns), }, resp_time_ms: if self.request_count > 0 { Some(TimeDistribution { diff --git a/src/workload.rs b/src/workload.rs index b31df88..5af1e48 100644 --- a/src/workload.rs +++ b/src/workload.rs @@ -381,27 +381,27 @@ impl Workload { } } - /// Executes a single iteration of a workload. + /// Executes a single cycle of a workload. /// This should be idempotent – /// the generated action should be a function of the iteration number. - /// Returns the iteration number and the end time of the query. - pub async fn run(&self, iteration: u64) -> Result<(u64, Instant), LatteError> { + /// Returns the cycle number and the end time of the query. + pub async fn run(&self, cycle: u64) -> Result<(u64, Instant), LatteError> { let start_time = Instant::now(); let session = SessionRef::new(&self.session); let result = self .program - .async_call(self.function, (session, iteration as i64)) + .async_call(self.function, (session, cycle as i64)) .await .map(|_| ()); // erase Value, because Value is !Send let end_time = Instant::now(); let mut state = self.state.try_lock().unwrap(); state.fn_stats.operation_completed(end_time - start_time); match result { - Ok(_) => Ok((iteration, end_time)), + Ok(_) => Ok((cycle, end_time)), Err(LatteError::Cassandra(CassError(CassErrorKind::Overloaded(_)))) => { // don't stop on overload errors; // they are being counted by the session stats anyways - Ok((iteration, end_time)) + Ok((cycle, end_time)) } Err(e) => Err(e), }