Skip to content

Commit a2b668b

Browse files
Add baseline String benchmarks without CowStr
1 parent bbe988d commit a2b668b

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ stable_deref_trait = { version = "1", default-features = false }
7575
[dev-dependencies]
7676
critical-section = { version = "1.1", features = ["std"] }
7777
static_assertions = "1.1.0"
78+
criterion = "0.5"
7879

7980
[package.metadata.docs.rs]
8081
features = [
@@ -89,3 +90,8 @@ features = [
8990
# for the pool module
9091
targets = ["i686-unknown-linux-gnu"]
9192
rustdoc-args = ["--cfg", "docsrs"]
93+
94+
[[bench]]
95+
name = "string_baseline"
96+
harness = false
97+

benches/string_baseline.rs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
//! Baseline benchmarks for heapless String operations.
2+
//!
3+
//! This benchmark suite measures the performance characteristics of basic
4+
//! String operations to establish a baseline for comparison.
5+
6+
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
7+
use heapless::String;
8+
9+
fn create_test_string<const N: usize>(content: &str) -> String<N> {
10+
String::try_from(content).expect("String too long for capacity")
11+
}
12+
13+
/// Baseline function that always copies into a new String<N>.
14+
fn baseline_always_copy<const N: usize>(input: &String<N>) -> String<N> {
15+
input.clone()
16+
}
17+
18+
/// Function that sometimes mutates the string (requires clone).
19+
fn baseline_conditional_mutation<const N: usize>(
20+
input: &String<N>,
21+
needs_mutation: bool,
22+
) -> String<N> {
23+
if needs_mutation {
24+
let mut owned = input.clone();
25+
let _ = owned.push_str("_mutated");
26+
owned
27+
} else {
28+
input.clone()
29+
}
30+
}
31+
32+
fn bench_string_baseline(c: &mut Criterion) {
33+
let mut group = c.benchmark_group("string_baseline");
34+
35+
let test_str: String<128> = create_test_string("test string for comparison");
36+
37+
group.bench_function("always_copy", |b| {
38+
b.iter(|| {
39+
let result = baseline_always_copy(black_box(&test_str));
40+
black_box(result)
41+
});
42+
});
43+
44+
group.bench_function("no_mutation", |b| {
45+
b.iter(|| {
46+
let result = baseline_conditional_mutation(black_box(&test_str), false);
47+
black_box(result)
48+
});
49+
});
50+
51+
group.bench_function("with_mutation", |b| {
52+
b.iter(|| {
53+
let result = baseline_conditional_mutation(black_box(&test_str), true);
54+
black_box(result)
55+
});
56+
});
57+
58+
group.finish();
59+
}
60+
61+
fn bench_string_creation(c: &mut Criterion) {
62+
let mut group = c.benchmark_group("string_creation");
63+
64+
let short_str: String<16> = create_test_string("hello");
65+
let medium_str: String<64> = create_test_string("This is a medium length test string");
66+
let long_str: String<256> = create_test_string("This is a much longer test string that contains more characters to properly test the performance characteristics");
67+
68+
group.bench_function("clone_short", |b| {
69+
b.iter(|| black_box(short_str.clone()));
70+
});
71+
72+
group.bench_function("clone_medium", |b| {
73+
b.iter(|| black_box(medium_str.clone()));
74+
});
75+
76+
group.bench_function("clone_long", |b| {
77+
b.iter(|| black_box(long_str.clone()));
78+
});
79+
80+
group.finish();
81+
}
82+
83+
fn bench_string_as_str(c: &mut Criterion) {
84+
let mut group = c.benchmark_group("string_as_str");
85+
86+
let test_str: String<64> = create_test_string("test string for as_str");
87+
88+
group.bench_function("as_str", |b| {
89+
b.iter(|| black_box(&test_str).as_str());
90+
});
91+
92+
group.finish();
93+
}
94+
95+
fn bench_string_clone_for_size<const N: usize>(
96+
group: &mut criterion::BenchmarkGroup<criterion::measurement::WallTime>,
97+
content: &str,
98+
size: usize,
99+
) {
100+
let test_str: String<N> = create_test_string(content);
101+
102+
group.bench_with_input(BenchmarkId::new("clone", size), &size, |b, _| {
103+
b.iter(|| black_box(&test_str).clone());
104+
});
105+
}
106+
107+
fn bench_string_clone_sizes(c: &mut Criterion) {
108+
let mut group = c.benchmark_group("string_clone_sizes");
109+
110+
bench_string_clone_for_size::<16>(&mut group, "short", 16);
111+
bench_string_clone_for_size::<64>(
112+
&mut group,
113+
"This is a medium length string for testing",
114+
64,
115+
);
116+
bench_string_clone_for_size::<256>(
117+
&mut group,
118+
"This is a very long string that we use to test the performance with different string sizes and capacities to ensure proper benchmarking",
119+
256,
120+
);
121+
122+
group.finish();
123+
}
124+
125+
fn bench_string_vs_clone(c: &mut Criterion) {
126+
let mut group = c.benchmark_group("string_vs_clone");
127+
128+
let test_str: String<128> =
129+
create_test_string("This is a string that would normally be cloned in every operation");
130+
131+
group.bench_function("clone_read_only", |b| {
132+
b.iter(|| {
133+
let s = black_box(&test_str).clone();
134+
let _result = black_box(s.as_str());
135+
});
136+
});
137+
138+
group.bench_function("clone_when_needed", |b| {
139+
b.iter(|| {
140+
let s = black_box(&test_str).clone();
141+
let _owned = black_box(s);
142+
});
143+
});
144+
145+
group.finish();
146+
}
147+
148+
criterion_group!(
149+
benches,
150+
bench_string_baseline,
151+
bench_string_creation,
152+
bench_string_as_str,
153+
bench_string_clone_sizes,
154+
bench_string_vs_clone
155+
);
156+
criterion_main!(benches);

0 commit comments

Comments
 (0)