Skip to content

Commit eec0737

Browse files
committed
upgrade benches
1 parent 952b42e commit eec0737

9 files changed

Lines changed: 439 additions & 171 deletions

File tree

Cargo.lock

Lines changed: 68 additions & 44 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bench/Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
[package]
2-
name = "benches"
2+
name = "bench"
33
publish = false
44
version = "0.1.0"
55
edition = "2021"
66

77
[dependencies]
8+
fastrand = "2.3.0"
9+
10+
[dev-dependencies]
811
cold-string = { path = "../cold-string" }
912
criterion = "0.5"
10-
rand = "0.8"
1113
sysinfo = "0.38.2"
12-
fastrand = "2.3.0"
14+
ahash = "0.8.12"
1315

1416
compact_string = "0.1.0"
1517
smol_str = "0.3.5"
1618
compact_str = "0.9.0"
19+
smartstring = "1.0.1"
20+
smallstr = "0.3.1"
1721

1822
[[bench]]
1923
name = "bench"

bench/benches/bench.rs

Lines changed: 96 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,123 @@
1-
use criterion::{black_box, criterion_group, criterion_main, Criterion};
1+
use criterion::{
2+
black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion,
3+
};
24
use std::collections::hash_map::DefaultHasher;
35
use std::hash::{Hash, Hasher};
6+
use std::str::FromStr;
47

8+
use bench::*;
59
use cold_string::ColdString;
610

711
const SHORT: &str = "qwerty";
812
const LONG: &str = "this_is_a_longer_string_that_will_allocate";
913

10-
fn bench_construction(c: &mut Criterion) {
11-
let mut group = c.benchmark_group("construction");
12-
13-
group.bench_function("ColdString short", |b| {
14-
b.iter(|| black_box(ColdString::from(black_box(SHORT))))
15-
});
16-
17-
group.bench_function("String short", |b| {
18-
b.iter(|| black_box(String::from(black_box(SHORT))))
19-
});
20-
21-
group.bench_function("ColdString long", |b| {
22-
b.iter(|| black_box(ColdString::from(black_box(LONG))))
23-
});
24-
25-
group.bench_function("String long", |b| {
26-
b.iter(|| black_box(String::from(black_box(LONG))))
14+
const LENGTHS: &[usize] = &[4, 8, 16, 32, 64];
15+
16+
fn bench_construction_inner<T: FromStr>(
17+
g: &mut BenchmarkGroup<'_, WallTime>,
18+
name: &'static str,
19+
min: usize,
20+
max: usize,
21+
strings: &[String],
22+
) {
23+
let label = format!("{}-len={}-{}", name, min, max);
24+
g.bench_function(&label, |b| {
25+
b.iter(|| {
26+
for x in strings.iter() {
27+
let _ = black_box(T::from_str(black_box(x.as_str())));
28+
}
29+
})
2730
});
31+
}
2832

33+
#[rustfmt::skip]
34+
fn bench_construction(c: &mut Criterion) {
35+
let mut group = c.benchmark_group("construction");
36+
for len in LENGTHS {
37+
for min in [0, *len] {
38+
let mut strings = Vec::with_capacity(1000);
39+
for _ in 0..1000 {
40+
strings.push(random_string(min, *len));
41+
}
42+
bench_construction_inner::<String>(&mut group, "std", min, *len, &strings);
43+
bench_construction_inner::<smol_str::SmolStr>(&mut group, "smol_str", min, *len, &strings);
44+
bench_construction_inner::<compact_str::CompactString>(&mut group, "compact_str", min, *len, &strings);
45+
bench_construction_inner::<smartstring::alias::String>(&mut group, "smartstring", min, *len, &strings);
46+
bench_construction_inner::<smallstr::SmallString<[u8; 8]>>(&mut group, "smallstr", min, *len, &strings);
47+
bench_construction_inner::<compact_string::CompactString>(&mut group, "compact_string", min, *len, &strings);
48+
bench_construction_inner::<cold_string::ColdString>(&mut group, "cold-string", min, *len, &strings);
49+
}
50+
}
2951
group.finish();
3052
}
3153

3254
fn bench_len(c: &mut Criterion) {
3355
let cold = ColdString::from(LONG);
3456
let string = String::from(LONG);
35-
3657
let mut group = c.benchmark_group("len");
37-
3858
group.bench_function("ColdString len", |b| b.iter(|| black_box(cold.len())));
39-
4059
group.bench_function("String len", |b| b.iter(|| black_box(string.len())));
41-
4260
group.finish();
4361
}
4462

45-
fn bench_as_str(c: &mut Criterion) {
46-
let cold = ColdString::from(LONG);
47-
let string = String::from(LONG);
63+
fn bench_as_str_inner<T: FromStr + AsRef<str>>(
64+
g: &mut BenchmarkGroup<'_, WallTime>,
65+
name: &'static str,
66+
min: usize,
67+
max: usize,
68+
strings: &[String],
69+
indices: &[usize], // Pass pre-shuffled indices
70+
) {
71+
// Pre-convert to the target type
72+
let strings: Vec<_> = strings.iter()
73+
.map(|s| T::from_str(s).map_err(|_| ()).unwrap())
74+
.collect();
75+
76+
let strings = black_box(strings);
77+
let label = format!("{}-len={}-{}", name, min, max);
78+
79+
g.bench_function(&label, |b| {
80+
b.iter(|| {
81+
let mut sum: u8 = 0;
82+
// Iterate using the shuffled indices to force cache misses
83+
for &i in indices.iter() {
84+
let s = &strings[i];
85+
let x: &str = black_box(s).as_ref();
86+
// Accessing the data is crucial to force the dereference
87+
sum ^= x.as_bytes().first().unwrap_or(&0);
88+
}
89+
black_box(sum)
90+
})
91+
});
92+
}
4893

94+
#[rustfmt::skip]
95+
fn bench_as_str(c: &mut Criterion) {
4996
let mut group = c.benchmark_group("as_str");
50-
51-
group.bench_function("ColdString as_str", |b| b.iter(|| black_box(cold.as_str())));
52-
53-
group.bench_function("String as_str", |b| b.iter(|| black_box(string.as_str())));
54-
97+
let count = 1_000_000;
98+
99+
// Pre-calculate random indices once to keep the comparison fair across crates
100+
let mut indices: Vec<usize> = (0..count).collect();
101+
fastrand::shuffle(&mut indices);
102+
// Limit to a subset if 1M iterations inside b.iter is too slow
103+
let indices_subset = &indices[..1000];
104+
105+
for len in LENGTHS {
106+
for min in [0, *len] {
107+
let mut strings = Vec::with_capacity(count);
108+
for _ in 0..count {
109+
strings.push(random_string(min, *len));
110+
}
111+
112+
bench_as_str_inner::<String>(&mut group, "std", min, *len, &strings, indices_subset);
113+
bench_as_str_inner::<smol_str::SmolStr>(&mut group, "smol_str", min, *len, &strings, indices_subset);
114+
bench_as_str_inner::<compact_str::CompactString>(&mut group, "compact_str", min, *len, &strings, indices_subset);
115+
bench_as_str_inner::<smartstring::alias::String>(&mut group, "smartstring", min, *len, &strings, indices_subset);
116+
bench_as_str_inner::<smallstr::SmallString<[u8; 8]>>(&mut group, "smallstr", min, *len, &strings, indices_subset);
117+
bench_as_str_inner::<compact_string::CompactString>(&mut group, "compact_string", min, *len, &strings, indices_subset);
118+
bench_as_str_inner::<cold_string::ColdString>(&mut group, "cold-string", min, *len, &strings, indices_subset);
119+
}
120+
}
55121
group.finish();
56122
}
57123

0 commit comments

Comments
 (0)