loro/crates/delta/benches/rope.rs
Zixuan Chen 9d4f7aa8a3
DeltaRope (#327)
* feat: delta rope support init

* perf: use generic-btree v0.9.0

* refactor: improve readability and maintainability

* fix: fix several issues about composing

* fix: a few more issue about composing deletions

* test: rich text

* fix: cover more edge cases

* refactor: use deltarope for list event

* refactor: replace text delta with DeltaRope

* fix: list fuzz err

* fix: safety issue on insert_many

* chore: refine impl of text delta

* refactor: use Replace instead of insert+del in DeltaItem (#330)

* refactor: use Replace instead of insert+del in DeltaItem

* fix: each deltaitem should have non-zero rle_len
Updated generic-btree dependency to version 0.10.3 and refactored DeltaItem and DeltaRope implementations in loro-delta. Refine compose impl

* fix: update generic-btree to fix the update leaf issue

* chore: lockfile

* chore: clippy fix

* refactor: make composing easier to understand

* refactor: simplify the impl of composing
2024-04-24 13:53:26 +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").map_or(false, |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()),
}
}
}