Skip to content

Commit cf3c005

Browse files
authored
[ISSUE #78]✨Add benchmarks for CheetahString performance across creation, cloning, querying, transforming, concatenating, iterating, and size scaling (#79)
1 parent a631659 commit cf3c005

File tree

1 file changed

+318
-0
lines changed

1 file changed

+318
-0
lines changed

benches/comprehensive.rs

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
use cheetah_string::CheetahString;
2+
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
3+
use std::sync::Arc;
4+
5+
// Benchmark: String creation from various sources
6+
fn bench_creation(c: &mut Criterion) {
7+
let mut group = c.benchmark_group("creation");
8+
9+
// Empty string
10+
group.bench_function("CheetahString::new", |b| {
11+
b.iter(|| black_box(CheetahString::new()))
12+
});
13+
14+
group.bench_function("String::new", |b| b.iter(|| black_box(String::new())));
15+
16+
group.bench_function("Arc<String>::new", |b| {
17+
b.iter(|| black_box(Arc::new(String::new())))
18+
});
19+
20+
// Short string (SSO optimized)
21+
let short = "hello";
22+
group.bench_function("CheetahString::from(short)", |b| {
23+
b.iter(|| black_box(CheetahString::from(short)))
24+
});
25+
26+
group.bench_function("String::from(short)", |b| {
27+
b.iter(|| black_box(String::from(short)))
28+
});
29+
30+
group.bench_function("Arc<String>::from(short)", |b| {
31+
b.iter(|| black_box(Arc::new(String::from(short))))
32+
});
33+
34+
// Medium string (23 bytes - SSO boundary)
35+
let medium = "12345678901234567890123"; // exactly 23 bytes
36+
group.bench_function("CheetahString::from(23B)", |b| {
37+
b.iter(|| black_box(CheetahString::from(medium)))
38+
});
39+
40+
group.bench_function("String::from(23B)", |b| {
41+
b.iter(|| black_box(String::from(medium)))
42+
});
43+
44+
// Long string (>SSO capacity)
45+
let long = "This is a longer string that exceeds SSO capacity";
46+
group.bench_function("CheetahString::from(long)", |b| {
47+
b.iter(|| black_box(CheetahString::from(long)))
48+
});
49+
50+
group.bench_function("String::from(long)", |b| {
51+
b.iter(|| black_box(String::from(long)))
52+
});
53+
54+
group.finish();
55+
}
56+
57+
// Benchmark: Cloning strings
58+
fn bench_clone(c: &mut Criterion) {
59+
let mut group = c.benchmark_group("clone");
60+
61+
// Empty
62+
let cs_empty = CheetahString::new();
63+
let s_empty = String::new();
64+
let arc_empty = Arc::new(String::new());
65+
66+
group.bench_function("CheetahString::clone(empty)", |b| {
67+
b.iter(|| black_box(cs_empty.clone()))
68+
});
69+
70+
group.bench_function("String::clone(empty)", |b| {
71+
b.iter(|| black_box(s_empty.clone()))
72+
});
73+
74+
group.bench_function("Arc<String>::clone(empty)", |b| {
75+
b.iter(|| black_box(arc_empty.clone()))
76+
});
77+
78+
// Short (SSO)
79+
let cs_short = CheetahString::from("hello");
80+
let s_short = String::from("hello");
81+
let arc_short = Arc::new(String::from("hello"));
82+
83+
group.bench_function("CheetahString::clone(short)", |b| {
84+
b.iter(|| black_box(cs_short.clone()))
85+
});
86+
87+
group.bench_function("String::clone(short)", |b| {
88+
b.iter(|| black_box(s_short.clone()))
89+
});
90+
91+
group.bench_function("Arc<String>::clone(short)", |b| {
92+
b.iter(|| black_box(arc_short.clone()))
93+
});
94+
95+
// Long
96+
let long_text = "a".repeat(1000);
97+
let cs_long = CheetahString::from(long_text.as_str());
98+
let s_long = String::from(long_text.as_str());
99+
let arc_long = Arc::new(String::from(long_text.as_str()));
100+
101+
group.bench_function("CheetahString::clone(1KB)", |b| {
102+
b.iter(|| black_box(cs_long.clone()))
103+
});
104+
105+
group.bench_function("String::clone(1KB)", |b| {
106+
b.iter(|| black_box(s_long.clone()))
107+
});
108+
109+
group.bench_function("Arc<String>::clone(1KB)", |b| {
110+
b.iter(|| black_box(arc_long.clone()))
111+
});
112+
113+
group.finish();
114+
}
115+
116+
// Benchmark: Query operations
117+
fn bench_query(c: &mut Criterion) {
118+
let mut group = c.benchmark_group("query");
119+
120+
let cs = CheetahString::from("hello world, this is a test string");
121+
let s = String::from("hello world, this is a test string");
122+
123+
group.bench_function("CheetahString::starts_with", |b| {
124+
b.iter(|| black_box(cs.starts_with("hello")))
125+
});
126+
127+
group.bench_function("String::starts_with", |b| {
128+
b.iter(|| black_box(s.starts_with("hello")))
129+
});
130+
131+
group.bench_function("CheetahString::ends_with", |b| {
132+
b.iter(|| black_box(cs.ends_with("string")))
133+
});
134+
135+
group.bench_function("String::ends_with", |b| {
136+
b.iter(|| black_box(s.ends_with("string")))
137+
});
138+
139+
group.bench_function("CheetahString::contains", |b| {
140+
b.iter(|| black_box(cs.contains("test")))
141+
});
142+
143+
group.bench_function("String::contains", |b| {
144+
b.iter(|| black_box(s.contains("test")))
145+
});
146+
147+
group.bench_function("CheetahString::find", |b| {
148+
b.iter(|| black_box(cs.find("test")))
149+
});
150+
151+
group.bench_function("String::find", |b| b.iter(|| black_box(s.find("test"))));
152+
153+
group.finish();
154+
}
155+
156+
// Benchmark: Transformation operations
157+
fn bench_transform(c: &mut Criterion) {
158+
let mut group = c.benchmark_group("transform");
159+
160+
// to_uppercase
161+
let cs_lower = CheetahString::from("hello world");
162+
let s_lower = String::from("hello world");
163+
164+
group.bench_function("CheetahString::to_uppercase", |b| {
165+
b.iter(|| black_box(cs_lower.to_uppercase()))
166+
});
167+
168+
group.bench_function("String::to_uppercase", |b| {
169+
b.iter(|| black_box(s_lower.to_uppercase()))
170+
});
171+
172+
// replace
173+
let cs_replace = CheetahString::from("hello world hello");
174+
let s_replace = String::from("hello world hello");
175+
176+
group.bench_function("CheetahString::replace", |b| {
177+
b.iter(|| black_box(cs_replace.replace("hello", "hi")))
178+
});
179+
180+
group.bench_function("String::replace", |b| {
181+
b.iter(|| black_box(s_replace.replace("hello", "hi")))
182+
});
183+
184+
// substring (CheetahString specific)
185+
group.bench_function("CheetahString::substring(short)", |b| {
186+
b.iter(|| black_box(cs_replace.substring(0, 5)))
187+
});
188+
189+
group.bench_function("CheetahString::substring(long)", |b| {
190+
b.iter(|| black_box(cs_replace.substring(0, 15)))
191+
});
192+
193+
group.finish();
194+
}
195+
196+
// Benchmark: Concatenation
197+
fn bench_concat(c: &mut Criterion) {
198+
let mut group = c.benchmark_group("concatenation");
199+
200+
// Short + short (both fit in SSO)
201+
let cs1 = CheetahString::from("hello");
202+
let cs2 = CheetahString::from(" world");
203+
let s1 = String::from("hello");
204+
205+
group.bench_function("CheetahString + &str", |b| {
206+
b.iter(|| black_box(cs1.clone() + " world"))
207+
});
208+
209+
group.bench_function("String + &str", |b| {
210+
b.iter(|| black_box(s1.clone() + " world"))
211+
});
212+
213+
group.bench_function("CheetahString + &CheetahString", |b| {
214+
b.iter(|| black_box(cs1.clone() + &cs2))
215+
});
216+
217+
// Long strings
218+
let cs_long1 = CheetahString::from("This is a longer string");
219+
let cs_long2 = CheetahString::from(" that will not fit in SSO");
220+
221+
group.bench_function("CheetahString + &str (long)", |b| {
222+
b.iter(|| black_box(cs_long1.clone() + " that will not fit in SSO"))
223+
});
224+
225+
group.bench_function("CheetahString + &CheetahString (long)", |b| {
226+
b.iter(|| black_box(cs_long1.clone() + &cs_long2))
227+
});
228+
229+
group.finish();
230+
}
231+
232+
// Benchmark: Iteration
233+
fn bench_iteration(c: &mut Criterion) {
234+
let mut group = c.benchmark_group("iteration");
235+
236+
let cs = CheetahString::from("hello world test string");
237+
let s = String::from("hello world test string");
238+
239+
group.bench_function("CheetahString::chars", |b| {
240+
b.iter(|| {
241+
for ch in cs.chars() {
242+
black_box(ch);
243+
}
244+
})
245+
});
246+
247+
group.bench_function("String::chars", |b| {
248+
b.iter(|| {
249+
for ch in s.chars() {
250+
black_box(ch);
251+
}
252+
})
253+
});
254+
255+
group.bench_function("CheetahString::split", |b| {
256+
b.iter(|| {
257+
for part in cs.split(" ") {
258+
black_box(part);
259+
}
260+
})
261+
});
262+
263+
group.bench_function("String::split", |b| {
264+
b.iter(|| {
265+
for part in s.split(" ") {
266+
black_box(part);
267+
}
268+
})
269+
});
270+
271+
group.finish();
272+
}
273+
274+
// Benchmark: Size scaling
275+
fn bench_size_scaling(c: &mut Criterion) {
276+
let mut group = c.benchmark_group("size_scaling");
277+
278+
for size in [10, 23, 50, 100, 500, 1000].iter() {
279+
let text = "a".repeat(*size);
280+
281+
group.bench_with_input(
282+
BenchmarkId::new("CheetahString::from", size),
283+
&text,
284+
|b, text| b.iter(|| black_box(CheetahString::from(text.as_str()))),
285+
);
286+
287+
group.bench_with_input(BenchmarkId::new("String::from", size), &text, |b, text| {
288+
b.iter(|| black_box(String::from(text.as_str())))
289+
});
290+
291+
let cs = CheetahString::from(text.as_str());
292+
let s = String::from(text.as_str());
293+
294+
group.bench_with_input(
295+
BenchmarkId::new("CheetahString::clone", size),
296+
&cs,
297+
|b, cs| b.iter(|| black_box(cs.clone())),
298+
);
299+
300+
group.bench_with_input(BenchmarkId::new("String::clone", size), &s, |b, s| {
301+
b.iter(|| black_box(s.clone()))
302+
});
303+
}
304+
305+
group.finish();
306+
}
307+
308+
criterion_group!(
309+
benches,
310+
bench_creation,
311+
bench_clone,
312+
bench_query,
313+
bench_transform,
314+
bench_concat,
315+
bench_iteration,
316+
bench_size_scaling
317+
);
318+
criterion_main!(benches);

0 commit comments

Comments
 (0)