loro/crates/delta/benches/rope.rs
Zixuan Chen 07500dab34
fix: map.keys() may return keys from deleted entries (#618)
* fix: map.keys() may return keys from deleted entries

* chore: changeset

* chore: fix latest clippy warning
2025-01-15 14:12:30 +08:00

189 lines
6.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use loro_delta::text_delta::TextDelta;
use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
fn generate_random_text(mut rng: StdRng, text_len: usize) -> String {
RandomCharIter::new(&mut rng).take(text_len).collect()
}
fn rope_benchmarks(c: &mut Criterion) {
static SEED: u64 = 9999;
static KB: usize = 1024;
let rng = StdRng::seed_from_u64(SEED);
let sizes = [4 * KB, 64 * KB, 256 * KB];
let mut group = c.benchmark_group("insert");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
b.iter(|| {
let mut rope: TextDelta = TextDelta::new();
for i in 0..*size {
let index = i * 3 / 4;
rope.insert_str(index, "n");
}
});
});
}
group.finish();
let mut group = c.benchmark_group("push");
for size in sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
let text = generate_random_text(rng.clone(), *size);
b.iter(|| {
let mut rope: TextDelta<()> = TextDelta::new();
for _ in 0..10 {
rope.push_str_insert(&text);
}
});
});
}
group.finish();
// let mut group = c.benchmark_group("append");
// for size in sizes.iter() {
// group.throughput(Throughput::Bytes(*size as u64));
// group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
// let mut random_ropes = Vec::new();
// for _ in 0..5 {
// random_ropes.push(generate_random_rope(rng.clone(), *size));
// }
// b.iter(|| {
// let mut rope_b = Rope::new();
// for rope in &random_ropes {
// rope_b.append(rope.clone())
// }
// });
// });
// }
// group.finish();
// let mut group = c.benchmark_group("slice");
// for size in sizes.iter() {
// group.throughput(Throughput::Bytes(*size as u64));
// group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
// let rope = generate_random_rope(rng.clone(), *size);
// b.iter_batched(
// || generate_random_rope_ranges(rng.clone(), &rope),
// |ranges| {
// for range in ranges.iter() {
// rope.slice(range.clone());
// }
// },
// BatchSize::SmallInput,
// );
// });
// }
// group.finish();
// let mut group = c.benchmark_group("bytes_in_range");
// for size in sizes.iter() {
// group.throughput(Throughput::Bytes(*size as u64));
// group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
// let rope = generate_random_rope(rng.clone(), *size);
// b.iter_batched(
// || generate_random_rope_ranges(rng.clone(), &rope),
// |ranges| {
// for range in ranges.iter() {
// let bytes = rope.bytes_in_range(range.clone());
// assert!(bytes.into_iter().count() > 0);
// }
// },
// BatchSize::SmallInput,
// );
// });
// }
// group.finish();
// let mut group = c.benchmark_group("chars");
// for size in sizes.iter() {
// group.throughput(Throughput::Bytes(*size as u64));
// group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
// let rope = generate_random_rope(rng.clone(), *size);
// b.iter_with_large_drop(|| {
// let chars = rope.chars().count();
// assert!(chars > 0);
// });
// });
// }
// group.finish();
// let mut group = c.benchmark_group("clip_point");
// for size in sizes.iter() {
// group.throughput(Throughput::Bytes(*size as u64));
// group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
// let rope = generate_random_rope(rng.clone(), *size);
// b.iter_batched(
// || generate_random_rope_points(rng.clone(), &rope),
// |offsets| {
// for offset in offsets.iter() {
// black_box(rope.clip_point(*offset, Bias::Left));
// black_box(rope.clip_point(*offset, Bias::Right));
// }
// },
// BatchSize::SmallInput,
// );
// });
// }
// group.finish();
}
criterion_group!(benches, rope_benchmarks);
criterion_main!(benches);
pub struct RandomCharIter<T: Rng> {
rng: T,
simple_text: bool,
}
impl<T: Rng> RandomCharIter<T> {
pub fn new(rng: T) -> Self {
Self {
rng,
simple_text: std::env::var("SIMPLE_TEXT").is_ok_and(|v| !v.is_empty()),
}
}
pub fn with_simple_text(mut self) -> Self {
self.simple_text = true;
self
}
}
impl<T: Rng> Iterator for RandomCharIter<T> {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
if self.simple_text {
return if self.rng.gen_range(0..100) < 5 {
Some('\n')
} else {
Some(self.rng.gen_range(b'a'..b'z' + 1).into())
};
}
match self.rng.gen_range(0..100) {
// whitespace
0..=19 => [' ', '\n', '\r', '\t'].choose(&mut self.rng).copied(),
// two-byte greek letters
20..=32 => char::from_u32(self.rng.gen_range(('α' as u32)..('ω' as u32 + 1))),
// // three-byte characters
33..=45 => ['✋', '✅', '❌', '❎', '⭐']
.choose(&mut self.rng)
.copied(),
// // four-byte characters
46..=58 => ['🍐', '🏀', '🍗', '🎉'].choose(&mut self.rng).copied(),
// ascii letters
_ => Some(self.rng.gen_range(b'a'..b'z' + 1).into()),
}
}
}