use crate::{append_fixed_random_data, get_fixed_journal};
use commonware_runtime::{
benchmarks::{context, tokio},
tokio::{Config, Context, Runner},
Runner as _, Supervisor as _,
};
use commonware_storage::journal::contiguous::{fixed::Journal, Contiguous as _};
use commonware_utils::{sequence::FixedBytes, test_rng, NZU64};
use criterion::{criterion_group, Criterion};
use futures::future::try_join_all;
use rand::RngExt as _;
use std::{
hint::black_box,
num::NonZeroU64,
time::{Duration, Instant},
};
const PARTITION: &str = "test-partition";
const ITEMS_PER_BLOB: NonZeroU64 = NZU64!(10_000);
const ITEMS_TO_WRITE: u64 = 5_000_000;
const ITEM_SIZE: usize = 32;
async fn bench_run_serial(
journal: &mut Journal<Context, FixedBytes<ITEM_SIZE>>,
items_to_read: usize,
) {
let reader = journal.snapshot().await.unwrap();
let mut rng = test_rng();
for _ in 0..items_to_read {
let pos = rng.random_range(0..ITEMS_TO_WRITE);
black_box(reader.read(pos).await.expect("failed to read data"));
}
}
async fn bench_run_concurrent(
journal: &mut Journal<Context, FixedBytes<ITEM_SIZE>>,
items_to_read: usize,
) {
let reader = journal.snapshot().await.unwrap();
let mut rng = test_rng();
let mut futures = Vec::with_capacity(items_to_read);
for _ in 0..items_to_read {
let pos = rng.random_range(0..ITEMS_TO_WRITE);
futures.push(reader.read(pos));
}
try_join_all(futures).await.expect("failed to read data");
}
async fn bench_run_read_many(
journal: &mut Journal<Context, FixedBytes<ITEM_SIZE>>,
items_to_read: usize,
) {
let reader = journal.snapshot().await.unwrap();
let mut rng = test_rng();
let mut positions: Vec<u64> = (0..items_to_read)
.map(|_| rng.random_range(0..ITEMS_TO_WRITE))
.collect();
positions.sort_unstable();
positions.dedup();
black_box(
reader
.read_many(&positions)
.await
.expect("failed to read data"),
);
}
fn bench_fixed_read_random(c: &mut Criterion) {
let cfg = Config::default();
let mut initialized = false;
let runner = tokio::Runner::new(cfg.clone());
for mode in ["serial", "concurrent", "read_many"] {
for items_to_read in [100, 1_000, 10_000, 100_000] {
c.bench_function(
&format!(
"{}/mode={} items={} size={}",
module_path!(),
mode,
items_to_read,
ITEM_SIZE
),
|b| {
if !initialized {
Runner::new(cfg.clone()).start(|ctx| async move {
let mut j = get_fixed_journal(ctx, PARTITION, ITEMS_PER_BLOB).await;
append_fixed_random_data::<_, ITEM_SIZE>(&mut j, ITEMS_TO_WRITE).await;
j.sync().await.unwrap();
});
initialized = true;
}
b.to_async(&runner).iter_custom(|iters| async move {
let ctx = context::get::<commonware_runtime::tokio::Context>();
let mut j =
get_fixed_journal(ctx.child("storage"), PARTITION, ITEMS_PER_BLOB)
.await;
let mut duration = Duration::ZERO;
for _ in 0..iters {
let start = Instant::now();
match mode {
"serial" => bench_run_serial(&mut j, items_to_read).await,
"concurrent" => bench_run_concurrent(&mut j, items_to_read).await,
"read_many" => bench_run_read_many(&mut j, items_to_read).await,
_ => unreachable!(),
}
duration += start.elapsed();
}
duration
});
},
);
}
}
if initialized {
Runner::new(cfg).start(|context| async move {
let j = get_fixed_journal::<ITEM_SIZE>(context, PARTITION, ITEMS_PER_BLOB).await;
j.destroy().await.unwrap();
});
}
}
criterion_group! {
name = benches;
config = Criterion::default().sample_size(10);
targets = bench_fixed_read_random
}