(
args: Args,
metrics_registry: MetricsRegistry,
metrics: Arc<Metrics>,
writers: Vec<W>,
readers: Vec<R>,
)
| 167 | } |
| 168 | |
| 169 | async fn run_benchmark<W, R>( |
| 170 | args: Args, |
| 171 | metrics_registry: MetricsRegistry, |
| 172 | metrics: Arc<Metrics>, |
| 173 | writers: Vec<W>, |
| 174 | readers: Vec<R>, |
| 175 | ) -> Result<(), anyhow::Error> |
| 176 | where |
| 177 | W: BenchmarkWriter + Send + Sync + 'static, |
| 178 | R: BenchmarkReader + Send + Sync + 'static, |
| 179 | { |
| 180 | let num_records_total = args.records_per_second * usize::cast_from(args.runtime.as_secs()); |
| 181 | let data_generator = |
| 182 | DataGenerator::new(num_records_total, args.record_size_bytes, args.batch_size); |
| 183 | |
| 184 | let benchmark_description = format!( |
| 185 | "num-readers={} num-writers={} runtime={:?} num_records_total={} records-per-second={} record-size-bytes={} batch-size={}", |
| 186 | args.num_readers, |
| 187 | args.num_writers, |
| 188 | args.runtime, |
| 189 | num_records_total, |
| 190 | args.records_per_second, |
| 191 | args.record_size_bytes, |
| 192 | args.batch_size |
| 193 | ); |
| 194 | |
| 195 | info!("starting benchmark: {}", benchmark_description); |
| 196 | let mut generator_handles: Vec<JoinHandle<Result<String, anyhow::Error>>> = vec![]; |
| 197 | let mut write_handles: Vec<JoinHandle<Result<String, anyhow::Error>>> = vec![]; |
| 198 | let mut read_handles: Vec<JoinHandle<Result<(String, R), anyhow::Error>>> = vec![]; |
| 199 | |
| 200 | // All workers should have the starting time (so they can consistently track progress |
| 201 | // and reason about lag independently). |
| 202 | let start = Instant::now(); |
| 203 | // Use a barrier to start all threads at the same time. We need 2x the number of |
| 204 | // writers because we start 2 distinct tasks per writer. |
| 205 | let barrier = Arc::new(Barrier::new(2 * args.num_writers + args.num_readers)); |
| 206 | |
| 207 | // The batch interarrival time. We'll use this quantity to rate limit the |
| 208 | // data generation. |
| 209 | // No other known way to convert `usize` to `f64`. |
| 210 | #[allow(clippy::as_conversions)] |
| 211 | let time_per_batch = { |
| 212 | let records_per_second_f64 = args.records_per_second as f64; |
| 213 | let batch_size_f64 = args.batch_size as f64; |
| 214 | |
| 215 | let batches_per_second = records_per_second_f64 / batch_size_f64; |
| 216 | Duration::from_secs(1).div_f64(batches_per_second) |
| 217 | }; |
| 218 | |
| 219 | for (idx, mut writer) in writers.into_iter().enumerate() { |
| 220 | let b = Arc::clone(&barrier); |
| 221 | let data_generator = data_generator.clone(); |
| 222 | let start = start.clone(); |
| 223 | let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel(); |
| 224 | |
| 225 | // Intentionally create the span outside the task to set the parent. |
| 226 | let generator_span = info_span!("generator", idx); |
no test coverage detected