1use std::ops::Range;
2
3use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput};
4use rand::prelude::*;
5use rand::rngs::StdRng;
6use rope::Rope;
7use util::RandomCharIter;
8
9fn generate_random_text(mut rng: StdRng, text_len: usize) -> String {
10 RandomCharIter::new(&mut rng).take(text_len).collect()
11}
12
13fn generate_random_rope(rng: StdRng, text_len: usize) -> Rope {
14 let text = generate_random_text(rng, text_len);
15 let mut rope = Rope::new();
16 rope.push(&text);
17 rope
18}
19
20fn generate_random_rope_ranges(mut rng: StdRng, rope: &Rope) -> Vec<Range<usize>> {
21 let range_max_len = 50;
22 let num_ranges = rope.len() / range_max_len;
23
24 let mut ranges = Vec::new();
25 let mut start = 0;
26 for _ in 0..num_ranges {
27 let range_start = rope.clip_offset(
28 rng.gen_range(start..=(start + range_max_len)),
29 sum_tree::Bias::Left,
30 );
31 let range_end = rope.clip_offset(
32 rng.gen_range(range_start..(range_start + range_max_len)),
33 sum_tree::Bias::Right,
34 );
35
36 let range = range_start..range_end;
37 if !range.is_empty() {
38 ranges.push(range);
39 }
40
41 start = range_end + 1;
42 }
43
44 ranges
45}
46
47fn rope_benchmarks(c: &mut Criterion) {
48 static SEED: u64 = 9999;
49 static KB: usize = 1024;
50
51 let rng = StdRng::seed_from_u64(SEED);
52 let sizes = [4 * KB, 64 * KB];
53
54 let mut group = c.benchmark_group("push");
55 for size in sizes.iter() {
56 group.throughput(Throughput::Bytes(*size as u64));
57 group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
58 let text = generate_random_text(rng.clone(), *size);
59
60 b.iter(|| {
61 let mut rope = Rope::new();
62 for _ in 0..10 {
63 rope.push(&text);
64 }
65 });
66 });
67 }
68 group.finish();
69
70 let mut group = c.benchmark_group("append");
71 for size in sizes.iter() {
72 group.throughput(Throughput::Bytes(*size as u64));
73 group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
74 let mut random_ropes = Vec::new();
75 for _ in 0..5 {
76 random_ropes.push(generate_random_rope(rng.clone(), *size));
77 }
78
79 b.iter(|| {
80 let mut rope_b = Rope::new();
81 for rope in &random_ropes {
82 rope_b.append(rope.clone())
83 }
84 });
85 });
86 }
87 group.finish();
88
89 let mut group = c.benchmark_group("slice");
90 for size in sizes.iter() {
91 group.throughput(Throughput::Bytes(*size as u64));
92 group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
93 let rope = generate_random_rope(rng.clone(), *size);
94
95 b.iter_batched(
96 || generate_random_rope_ranges(rng.clone(), &rope),
97 |ranges| {
98 for range in ranges.iter() {
99 rope.slice(range.clone());
100 }
101 },
102 BatchSize::SmallInput,
103 );
104 });
105 }
106 group.finish();
107
108 let mut group = c.benchmark_group("bytes_in_range");
109 for size in sizes.iter() {
110 group.throughput(Throughput::Bytes(*size as u64));
111 group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
112 let rope = generate_random_rope(rng.clone(), *size);
113
114 b.iter_batched(
115 || generate_random_rope_ranges(rng.clone(), &rope),
116 |ranges| {
117 for range in ranges.iter() {
118 let bytes = rope.bytes_in_range(range.clone());
119 assert!(bytes.into_iter().count() > 0);
120 }
121 },
122 BatchSize::SmallInput,
123 );
124 });
125 }
126 group.finish();
127
128 let mut group = c.benchmark_group("chars");
129 for size in sizes.iter() {
130 group.throughput(Throughput::Bytes(*size as u64));
131 group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
132 let rope = generate_random_rope(rng.clone(), *size);
133
134 b.iter_with_large_drop(|| {
135 let chars = rope.chars().count();
136 assert!(chars > 0);
137 });
138 });
139 }
140 group.finish();
141}
142
143criterion_group!(benches, rope_benchmarks);
144criterion_main!(benches);