Skip to content

Commit c16e2b6

Browse files
authored
Add comparative benchmarks with Taffy 0.3 (#572)
* Taffy 0.3 flexbox benchmarks * Add compute_layout method to BuildTree trait * Simplify benchmarks with macros
1 parent d4374b9 commit c16e2b6

File tree

6 files changed

+347
-185
lines changed

6 files changed

+347
-185
lines changed

benches/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@ license = "MIT"
1414

1515
[dependencies]
1616
criterion = "0.5"
17-
taffy = { path = ".." }
1817
rand = { version = "0.8.5" }
1918
rand_chacha = "0.3.1"
19+
taffy = { path = ".." }
20+
taffy_03 = { package = "taffy", version = "0.3", optional = true }
2021
yoga = { version = "0.4.0", optional = true }
2122
ordered-float = { version = "3.4.0", optional = true }
2223
slotmap = { version = "1.0.6", optional = true }
2324

2425
[features]
2526
yoga = ["dep:yoga", "dep:slotmap", "dep:ordered-float"]
2627
yoga-super-deep = ["yoga"]
28+
taffy03 = ["dep:taffy_03"]
2729
small = []
2830
large = []
2931

benches/benches/flexbox.rs

Lines changed: 122 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use taffy::style::Style as TaffyStyle;
77

88
use taffy_benchmarks::{BuildTreeExt, FixedStyleGenerator, GenStyle, TaffyTreeBuilder};
99

10+
#[cfg(feature = "taffy03")]
11+
use taffy_benchmarks::taffy_03_helpers::Taffy03TreeBuilder;
1012
#[cfg(feature = "yoga")]
11-
use taffy_benchmarks::yoga_helpers;
12-
#[cfg(feature = "yoga")]
13-
use yoga_helpers::{yg, YogaTreeBuilder};
13+
use taffy_benchmarks::yoga_helpers::YogaTreeBuilder;
1414

1515
fn random_dimension(rng: &mut impl Rng) -> Dimension {
1616
match rng.gen_range(0.0..=1.0) {
@@ -19,6 +19,8 @@ fn random_dimension(rng: &mut impl Rng) -> Dimension {
1919
_ => Dimension::Percent(rng.gen_range(0.0..1.0)),
2020
}
2121
}
22+
23+
#[derive(Clone)]
2224
pub struct RandomStyleGenerator;
2325
impl GenStyle<TaffyStyle> for RandomStyleGenerator {
2426
fn create_leaf_style(&mut self, rng: &mut impl Rng) -> TaffyStyle {
@@ -29,112 +31,78 @@ impl GenStyle<TaffyStyle> for RandomStyleGenerator {
2931
}
3032
}
3133

32-
/// A deep tree that matches the shape and styling that yoga use on their benchmarks
33-
fn build_flat_hierarchy<G: GenStyle<TaffyStyle>, TreeBuilder: BuildTreeExt<G>>(
34-
target_node_count: u32,
35-
style_generator: impl FnOnce() -> G,
36-
) -> (TreeBuilder::Tree, TreeBuilder::Node) {
37-
let tree_builder = TreeBuilder::new(style_generator());
38-
tree_builder.build_flat_hierarchy(target_node_count)
39-
}
40-
41-
/// A deep tree that matches the shape and styling that yoga use on their benchmarks
42-
fn build_deep_hierarchy<G: GenStyle<TaffyStyle>, TreeBuilder: BuildTreeExt<G>>(
43-
node_count: u32,
44-
branching_factor: u32,
45-
style_generator: impl FnOnce() -> G,
46-
) -> (TreeBuilder::Tree, TreeBuilder::Node) {
47-
let tree_builder = TreeBuilder::new(style_generator());
48-
tree_builder.build_deep_hierarchy(node_count, branching_factor)
34+
macro_rules! run_benchmark {
35+
($TreeBuilder: ty, $tree_builder_name: literal, $benchmark_name: expr, $group: ident, $builder: ident, $params: expr, $generate_style: expr, $generate_tree: expr) => {
36+
let benchmark_id = BenchmarkId::new(format!("{} {}", $tree_builder_name, $benchmark_name), $params);
37+
$group.bench_with_input(benchmark_id, $params, |b, _params| {
38+
b.iter_batched(
39+
|| -> $TreeBuilder {
40+
let mut $builder = <$TreeBuilder>::new($generate_style());
41+
$generate_tree;
42+
$builder
43+
},
44+
|mut builder| builder.compute_layout(None, None),
45+
criterion::BatchSize::SmallInput,
46+
)
47+
});
48+
};
4949
}
5050

51-
/// A deep tree that matches the shape and styling that yoga use on their benchmarks
52-
fn build_super_deep_hierarchy<G: GenStyle<TaffyStyle>, TreeBuilder: BuildTreeExt<G>>(
53-
depth: u32,
54-
nodes_per_level: u32,
55-
style_generator: impl FnOnce() -> G,
56-
) -> (TreeBuilder::Tree, TreeBuilder::Node) {
57-
let tree_builder = TreeBuilder::new(style_generator());
58-
tree_builder.build_super_deep_hierarchy(depth, nodes_per_level)
59-
}
51+
macro_rules! benchmark_each_library {
52+
($benchmark_name: expr, $group: ident, $builder: ident, $params: expr, $generate_style: expr, $generate_tree: expr) => {
53+
#[cfg(feature = "yoga")]
54+
run_benchmark!(YogaTreeBuilder<_, _>, "Yoga", $benchmark_name, $group, $builder, $params, $generate_style, $generate_tree);
55+
#[cfg(feature = "taffy03")]
56+
run_benchmark!(Taffy03TreeBuilder<_, _>, "Taffy 0.3", $benchmark_name, $group, $builder, $params, $generate_style, $generate_tree);
6057

61-
/// A deep tree that matches the shape and styling that yoga use on their benchmarks
62-
fn build_huge_nested_hierarchy<G: GenStyle<TaffyStyle>, TreeBuilder: BuildTreeExt<G>>(
63-
node_count: u32,
64-
branching_factor: u32,
65-
style_generator: impl FnOnce() -> G,
66-
) -> (TreeBuilder::Tree, TreeBuilder::Node) {
67-
let tree_builder = TreeBuilder::new(style_generator());
68-
tree_builder.build_deep_hierarchy(node_count, branching_factor)
58+
run_benchmark!(TaffyTreeBuilder<_, _>, "Taffy 0.4", $benchmark_name, $group, $builder, $params, $generate_style, $generate_tree);
59+
};
6960
}
7061

7162
fn huge_nested_benchmarks(c: &mut Criterion) {
72-
let mut group = c.benchmark_group("yoga 'huge nested'");
73-
let style = Style { size: length(10.0), flex_grow: 1.0, ..Default::default() };
74-
let style_gen = || FixedStyleGenerator(style.clone());
75-
for node_count in [
63+
let node_counts = [
7664
#[cfg(feature = "small")]
7765
1_000u32,
7866
10_000,
7967
#[cfg(feature = "large")]
8068
100_000,
81-
]
82-
.iter()
83-
{
84-
#[cfg(feature = "yoga")]
85-
group.bench_with_input(BenchmarkId::new("Yoga", node_count), node_count, |b, &node_count| {
86-
b.iter_batched(
87-
|| build_huge_nested_hierarchy::<_, YogaTreeBuilder<_, _>>(node_count, 10, style_gen),
88-
|(mut tree, root)| {
89-
tree[root].calculate_layout(f32::INFINITY, f32::INFINITY, yg::Direction::LTR);
90-
},
91-
criterion::BatchSize::SmallInput,
92-
)
93-
});
94-
group.bench_with_input(BenchmarkId::new("Taffy", node_count), node_count, |b, &node_count| {
95-
b.iter_batched(
96-
|| build_huge_nested_hierarchy::<_, TaffyTreeBuilder<_, _>>(node_count, 10, style_gen),
97-
|(mut taffy, root)| taffy.compute_layout(root, Size::MAX_CONTENT).unwrap(),
98-
criterion::BatchSize::SmallInput,
99-
)
100-
});
69+
];
70+
71+
let mut group = c.benchmark_group("yoga 'huge nested'");
72+
let style = Style { size: length(10.0), flex_grow: 1.0, ..Default::default() };
73+
for node_count in node_counts.iter() {
74+
benchmark_each_library!(
75+
"",
76+
group,
77+
builder,
78+
node_count,
79+
|| FixedStyleGenerator(style.clone()),
80+
builder.build_deep_hierarchy(*node_count, 10)
81+
);
10182
}
10283
group.finish();
10384
}
10485

10586
fn wide_benchmarks(c: &mut Criterion) {
106-
// Decrease sample size, because the tasks take longer
107-
let mut group = c.benchmark_group("Wide tree");
108-
group.sample_size(10);
109-
for node_count in [
87+
let node_counts = [
11088
#[cfg(feature = "small")]
11189
1_000u32,
11290
10_000,
11391
#[cfg(feature = "large")]
11492
100_000,
115-
]
116-
.iter()
117-
{
118-
#[cfg(feature = "yoga")]
119-
let benchmark_id = BenchmarkId::new(format!("Yoga (2-level hierarchy)"), node_count);
120-
#[cfg(feature = "yoga")]
121-
group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
122-
b.iter_batched(
123-
|| build_flat_hierarchy::<_, YogaTreeBuilder<_, _>>(node_count, || RandomStyleGenerator),
124-
|(mut tree, root)| {
125-
tree[root].calculate_layout(f32::INFINITY, f32::INFINITY, yg::Direction::LTR);
126-
},
127-
criterion::BatchSize::SmallInput,
128-
)
129-
});
130-
let benchmark_id = BenchmarkId::new(format!("Taffy (2-level hierarchy)"), node_count);
131-
group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
132-
b.iter_batched(
133-
|| build_flat_hierarchy::<_, TaffyTreeBuilder<_, _>>(node_count, || RandomStyleGenerator),
134-
|(mut taffy, root)| taffy.compute_layout(root, Size::MAX_CONTENT).unwrap(),
135-
criterion::BatchSize::SmallInput,
136-
)
137-
});
93+
];
94+
95+
let mut group = c.benchmark_group("Wide tree");
96+
group.sample_size(10); // Decrease sample size, because the tasks take longer
97+
for node_count in node_counts.iter() {
98+
benchmark_each_library!(
99+
"(2-level hierarchy)",
100+
group,
101+
builder,
102+
node_count,
103+
|| RandomStyleGenerator,
104+
builder.build_flat_hierarchy(*node_count)
105+
);
138106
}
139107
group.finish();
140108
}
@@ -150,64 +118,52 @@ fn deep_random_benchmarks(c: &mut Criterion) {
150118
(100_000, "(17-level hierarchy)"),
151119
];
152120
for (node_count, label) in benches.iter() {
153-
#[cfg(feature = "yoga")]
154-
group.bench_with_input(BenchmarkId::new(format!("Yoga {label}"), node_count), node_count, |b, &node_count| {
155-
b.iter_batched(
156-
|| build_deep_hierarchy::<_, YogaTreeBuilder<_, _>>(node_count, 2, || RandomStyleGenerator),
157-
|(mut tree, root)| {
158-
tree[root].calculate_layout(f32::INFINITY, f32::INFINITY, yg::Direction::LTR);
159-
},
160-
criterion::BatchSize::SmallInput,
161-
)
162-
});
163-
group.bench_with_input(BenchmarkId::new(format!("Taffy {label}"), node_count), node_count, |b, &node_count| {
164-
b.iter_batched(
165-
|| build_deep_hierarchy::<_, TaffyTreeBuilder<_, _>>(node_count, 2, || RandomStyleGenerator),
166-
|(mut taffy, root)| taffy.compute_layout(root, Size::MAX_CONTENT).unwrap(),
167-
criterion::BatchSize::SmallInput,
168-
)
169-
});
121+
benchmark_each_library!(
122+
label,
123+
group,
124+
builder,
125+
node_count,
126+
|| RandomStyleGenerator,
127+
builder.build_deep_hierarchy(*node_count, 2)
128+
);
170129
}
171130
group.finish();
172131
}
173132

174133
fn deep_auto_benchmarks(c: &mut Criterion) {
175-
// Decrease sample size, because the tasks take longer
176-
let mut group = c.benchmark_group("Deep tree (auto size)");
177-
group.sample_size(10);
178-
let style = Style { flex_grow: 1.0, margin: length(10.0), ..Default::default() };
179-
let style_gen = || FixedStyleGenerator(style.clone());
180134
let benches = [
181135
(4000, "(12-level hierarchy)"),
182136
(10_000, "(14-level hierarchy)"),
183137
#[cfg(feature = "large")]
184138
(100_000, "(17-level hierarchy)"),
185139
];
140+
let style = Style { flex_grow: 1.0, margin: length(10.0), ..Default::default() };
141+
142+
let mut group = c.benchmark_group("Deep tree (auto size)");
143+
group.sample_size(10); // Decrease sample size, because the tasks take longer
186144
for (node_count, label) in benches.iter() {
187-
#[cfg(feature = "yoga")]
188-
group.bench_with_input(BenchmarkId::new(format!("Yoga {label}"), node_count), node_count, |b, &node_count| {
189-
b.iter_batched(
190-
|| build_deep_hierarchy::<_, YogaTreeBuilder<_, _>>(node_count, 2, style_gen),
191-
|(mut tree, root)| {
192-
tree[root].calculate_layout(f32::INFINITY, f32::INFINITY, yg::Direction::LTR);
193-
},
194-
criterion::BatchSize::SmallInput,
195-
)
196-
});
197-
group.bench_with_input(BenchmarkId::new(format!("Taffy {label}"), node_count), node_count, |b, &node_count| {
198-
b.iter_batched(
199-
|| build_deep_hierarchy::<_, TaffyTreeBuilder<_, _>>(node_count, 2, style_gen),
200-
|(mut taffy, root)| taffy.compute_layout(root, Size::MAX_CONTENT).unwrap(),
201-
criterion::BatchSize::SmallInput,
202-
)
203-
});
145+
benchmark_each_library!(
146+
label,
147+
group,
148+
builder,
149+
node_count,
150+
|| FixedStyleGenerator(style.clone()),
151+
builder.build_deep_hierarchy(*node_count, 2)
152+
);
204153
}
205154
group.finish();
206155
}
207156

208157
fn super_deep_benchmarks(c: &mut Criterion) {
209-
let mut group = c.benchmark_group("super deep");
210-
group.sample_size(10);
158+
let benches = [
159+
#[cfg(feature = "small")]
160+
50u32,
161+
100,
162+
#[cfg(feature = "large")]
163+
200,
164+
];
165+
166+
#[derive(Clone)]
211167
struct SuperDeepStyleGen;
212168
impl GenStyle<TaffyStyle> for SuperDeepStyleGen {
213169
fn create_leaf_style(&mut self, _rng: &mut impl Rng) -> TaffyStyle {
@@ -219,40 +175,45 @@ fn super_deep_benchmarks(c: &mut Criterion) {
219175
self.create_leaf_style(rng)
220176
}
221177
}
222-
for depth in [
223-
#[cfg(feature = "small")]
224-
50u32,
225-
100,
226-
#[cfg(feature = "large")]
227-
200,
228-
]
229-
.iter()
230-
{
178+
179+
let mut group = c.benchmark_group("super deep");
180+
group.sample_size(10);
181+
182+
for depth in benches.iter() {
231183
// Yoga is particularly slow at these benchmarks, so we gate them behind a separate feature flag
232184
#[cfg(all(feature = "yoga", feature = "yoga-super-deep"))]
233-
group.bench_with_input(BenchmarkId::new("Yoga", depth), depth, |b, &depth| {
234-
b.iter_batched(
235-
|| build_super_deep_hierarchy::<_, YogaTreeBuilder<_, _>>(depth, 3, || SuperDeepStyleGen),
236-
|(mut tree, root)| {
237-
tree[root].calculate_layout(800., 800., yg::Direction::LTR);
238-
},
239-
criterion::BatchSize::SmallInput,
240-
)
241-
});
242-
group.bench_with_input(BenchmarkId::new("Taffy", depth), depth, |b, &depth| {
243-
b.iter_batched(
244-
|| build_super_deep_hierarchy::<_, TaffyTreeBuilder<_, _>>(depth, 3, || SuperDeepStyleGen),
245-
|(mut taffy, root)| {
246-
taffy
247-
.compute_layout(
248-
root,
249-
Size { width: AvailableSpace::Definite(800.), height: AvailableSpace::Definite(800.) },
250-
)
251-
.unwrap()
252-
},
253-
criterion::BatchSize::SmallInput,
254-
)
255-
});
185+
run_benchmark!(
186+
YogaTreeBuilder<_,_>,
187+
"Yoga",
188+
"",
189+
group,
190+
builder,
191+
depth,
192+
|| SuperDeepStyleGen,
193+
builder.build_super_deep_hierarchy(*depth, 3)
194+
);
195+
#[cfg(feature = "taffy03")]
196+
run_benchmark!(
197+
Taffy03TreeBuilder<_,_>,
198+
"Taffy 0.3",
199+
"",
200+
group,
201+
builder,
202+
depth,
203+
|| SuperDeepStyleGen,
204+
builder.build_super_deep_hierarchy(*depth, 3)
205+
);
206+
207+
run_benchmark!(
208+
TaffyTreeBuilder<_,_>,
209+
"Taffy 0.4",
210+
"",
211+
group,
212+
builder,
213+
depth,
214+
|| SuperDeepStyleGen,
215+
builder.build_super_deep_hierarchy(*depth, 3)
216+
);
256217
}
257218
group.finish();
258219
}

0 commit comments

Comments
 (0)