tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1111HTML 1039Markdown 12TOML 94541 Definitions

⎇ 7db11fa8752a54f39cacb5381460aff438d1824e benches/big_tree.rs Rust · 324 lines · 11.5 KB History Who touched what raw

Disable super-deep benchmarks (0.1 is too slow to complete these at all) (#280) 7db11fa87 · Nico Burns ·

1//! This file includes benchmarks for very large, pseudo-randomly generated trees
2use criterion::{criterion_group, criterion_main, Criterion};
3use rand::prelude::*;
4use rand_chacha::ChaCha8Rng;
5use taffy::prelude::*;
6use taffy::randomizable::Randomizeable;
7use taffy::style::Style;
8
9/// Build a random leaf node
10fn build_random_leaf(taffy: &mut Taffy, rng: &mut ChaCha8Rng) -> Node {
11    taffy.new_node(Style::random(rng), &[]).unwrap()
12}
13
14/// A tree with many children that have shallow depth
15fn build_flat_hierarchy(taffy: &mut Taffy, total_node_count: u32) -> Node {
16    let mut rng = ChaCha8Rng::seed_from_u64(12345);
17    let mut children = Vec::new();
18    let mut node_count = 0;
19
20    while node_count < total_node_count {
21        let sub_children_count = rng.gen_range(1..=4);
22        let sub_children: Vec<Node> = (0..sub_children_count).map(|_| build_random_leaf(taffy, &mut rng)).collect();
23        let node = taffy.new_node(Style::random(&mut rng), &sub_children).unwrap();
24
25        children.push(node);
26        node_count += 1 + sub_children_count;
27    }
28
29    taffy.new_node(Style { ..Default::default() }, children.as_slice()).unwrap()
30}
31
32/// A helper function to recursively construct a deep tree
33fn build_deep_tree(
34    taffy: &mut Taffy,
35    max_nodes: u32,
36    branching_factor: u32,
37    create_leaf_node: &mut impl FnMut(&mut Taffy) -> Node,
38    create_flex_node: &mut impl FnMut(&mut Taffy, Vec<Node>) -> Node,
39) -> Vec<Node> {
40    if max_nodes <= branching_factor {
41        // Build leaf nodes
42        return (0..max_nodes).map(|_| create_leaf_node(taffy)).collect();
43    }
44
45    // Add another layer to the tree
46    // Each child gets an equal amount of the remaining nodes
47    (0..branching_factor)
48        .map(|_| {
49            let max_nodes = (max_nodes - branching_factor) / branching_factor;
50            let sub_children = build_deep_tree(taffy, max_nodes, branching_factor, create_leaf_node, create_flex_node);
51            create_flex_node(taffy, sub_children)
52        })
53        .collect()
54}
55
56/// A tree with a higher depth for a more realistic scenario
57fn build_deep_hierarchy(taffy: &mut Taffy, node_count: u32, branching_factor: u32) -> Node {
58    let mut rng = ChaCha8Rng::seed_from_u64(12345);
59    let mut build_leaf_node = |taffy: &mut Taffy| build_random_leaf(taffy, &mut rng);
60    let mut rng = ChaCha8Rng::seed_from_u64(12345);
61    let mut build_flex_node =
62        |taffy: &mut Taffy, children: Vec<Node>| taffy.new_node(Style::random(&mut rng), &children).unwrap();
63
64    let tree = build_deep_tree(taffy, node_count, branching_factor, &mut build_leaf_node, &mut build_flex_node);
65
66    taffy.new_node(Style { ..Default::default() }, &tree).unwrap()
67}
68
69/// A deep tree that matches the shape and styling that yoga use on their benchmarks
70fn build_yoga_deep_hierarchy(taffy: &mut Taffy, node_count: u32, branching_factor: u32) -> Node {
71    let style = Style {
72        size: Size { width: Dimension::Points(10.0), height: Dimension::Points(10.0) },
73        flex_grow: 1.0,
74        ..Default::default()
75    };
76    let mut build_leaf_node = |taffy: &mut Taffy| taffy.new_node(style.clone(), &[]).unwrap();
77    let mut build_flex_node =
78        |taffy: &mut Taffy, children: Vec<Node>| taffy.new_node(style.clone(), &children).unwrap();
79
80    let tree = build_deep_tree(taffy, node_count, branching_factor, &mut build_leaf_node, &mut build_flex_node);
81    let root = taffy.new_node(Style { ..Default::default() }, &tree).unwrap();
82
83    root
84}
85
86fn taffy_benchmarks(c: &mut Criterion) {
87    let mut group = c.benchmark_group("yoga benchmarks");
88    group.sample_size(10);
89
90    group.bench_function("10 nodes", |b| {
91        b.iter_batched(
92            || {
93                let mut taffy = Taffy::new();
94                let root = build_yoga_deep_hierarchy(&mut taffy, 10, 10);
95                (taffy, root)
96            },
97            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
98            criterion::BatchSize::SmallInput,
99        )
100    });
101
102    group.bench_function("100 nodes", |b| {
103        b.iter_batched(
104            || {
105                let mut taffy = Taffy::new();
106                let root = build_yoga_deep_hierarchy(&mut taffy, 100, 10);
107                (taffy, root)
108            },
109            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
110            criterion::BatchSize::SmallInput,
111        )
112    });
113
114    group.bench_function("1_000 nodes", |b| {
115        b.iter_batched(
116            || {
117                let mut taffy = Taffy::new();
118                let root = build_yoga_deep_hierarchy(&mut taffy, 1_000, 10);
119                (taffy, root)
120            },
121            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
122            criterion::BatchSize::SmallInput,
123        )
124    });
125
126    group.bench_function("10_000 nodes", |b| {
127        b.iter_batched(
128            || {
129                let mut taffy = Taffy::new();
130                let root = build_yoga_deep_hierarchy(&mut taffy, 10_000, 10);
131                (taffy, root)
132            },
133            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
134            criterion::BatchSize::SmallInput,
135        )
136    });
137
138    group.bench_function("100_000 nodes", |b| {
139        b.iter_batched(
140            || {
141                let mut taffy = Taffy::new();
142                let root = build_yoga_deep_hierarchy(&mut taffy, 100_000, 10);
143                (taffy, root)
144            },
145            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
146            criterion::BatchSize::LargeInput,
147        )
148    });
149
150    // group.bench_function("1_000_000 nodes", |b| {
151    //     b.iter_batched(
152    //         || {
153    //             let mut taffy = Taffy::new();
154    //             let root = build_yoga_deep_hierarchy(&mut taffy, 1_000_000, 10);
155    //             (taffy, root)
156    //         },
157    //         |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
158    //         criterion::BatchSize::LargeInput,
159    //     )
160    // });
161    drop(group);
162
163    // Decrease sample size, because the tasks take longer
164    let mut group = c.benchmark_group("big trees (wide)");
165    group.sample_size(10);
166
167    group.bench_function("10 nodes (2-level hierarchy)", |b| {
168        b.iter_batched(
169            || {
170                let mut taffy = Taffy::new();
171                let root = build_flat_hierarchy(&mut taffy, 10);
172                (taffy, root)
173            },
174            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
175            criterion::BatchSize::SmallInput,
176        )
177    });
178
179    group.bench_function("100 nodes (2-level hierarchy)", |b| {
180        b.iter_batched(
181            || {
182                let mut taffy = Taffy::new();
183                let root = build_flat_hierarchy(&mut taffy, 100);
184                (taffy, root)
185            },
186            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
187            criterion::BatchSize::SmallInput,
188        )
189    });
190
191    group.bench_function("1_000 nodes (2-level hierarchy)", |b| {
192        b.iter_batched(
193            || {
194                let mut taffy = Taffy::new();
195                let root = build_flat_hierarchy(&mut taffy, 1_000);
196                (taffy, root)
197            },
198            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
199            criterion::BatchSize::SmallInput,
200        )
201    });
202
203    group.bench_function("10_000 nodes (2-level hierarchy)", |b| {
204        b.iter_batched(
205            || {
206                let mut taffy = Taffy::new();
207                let root = build_flat_hierarchy(&mut taffy, 10_000);
208                (taffy, root)
209            },
210            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
211            criterion::BatchSize::LargeInput,
212        )
213    });
214
215    group.bench_function("100_000 nodes (2-level hierarchy)", |b| {
216        b.iter_batched(
217            || {
218                let mut taffy = Taffy::new();
219                let root = build_flat_hierarchy(&mut taffy, 100_000);
220                (taffy, root)
221            },
222            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
223            criterion::BatchSize::LargeInput,
224        )
225    });
226
227    group.bench_function("100_000 nodes (7-level hierarchy)", |b| {
228        b.iter_batched(
229            || {
230                let mut taffy = Taffy::new();
231                let root = build_deep_hierarchy(&mut taffy, 100_000, 7);
232                (taffy, root)
233            },
234            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
235            criterion::BatchSize::LargeInput,
236        )
237    });
238
239    drop(group);
240
241    // Decrease sample size, because the tasks take longer
242    let mut group = c.benchmark_group("big trees (deep)");
243    group.sample_size(10);
244
245    group.bench_function("4000 nodes (12-level hierarchy)", |b| {
246        b.iter_batched(
247            || {
248                let mut taffy = Taffy::new();
249                let root = build_deep_hierarchy(&mut taffy, 4000, 2);
250                (taffy, root)
251            },
252            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
253            criterion::BatchSize::SmallInput,
254        )
255    });
256
257    group.bench_function("10_000 nodes (14-level hierarchy)", |b| {
258        b.iter_batched(
259            || {
260                let mut taffy = Taffy::new();
261                let root = build_deep_hierarchy(&mut taffy, 10_000, 2);
262                (taffy, root)
263            },
264            |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
265            criterion::BatchSize::SmallInput,
266        )
267    });
268
269    // group.bench_function("100_000 nodes (17-level hierarchy)", |b| {
270    //     b.iter_batched(
271    //         || {
272    //             let mut taffy = Taffy::new();
273    //             let root = build_deep_hierarchy(&mut taffy, 100_000, 2);
274    //             (taffy, root)
275    //         },
276    //         |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
277    //         criterion::BatchSize::LargeInput,
278    //     )
279    // });
280
281    // group.bench_function("1_000_000 nodes (20-level hierarchy)", |b| {
282    //      b.iter_batched(
283    //         || {
284    //             let mut taffy = Taffy::new();
285    //             let root = build_deep_hierarchy(&mut taffy, 1_000_000, 2);
286    //             (taffy, root)
287    //         },
288    //         |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
289    //         criterion::BatchSize::LargeInput,
290    //     )
291    // });
292
293    drop(group);
294
295    // let mut group = c.benchmark_group("super deep trees");
296    // group.sample_size(10);
297
298    // group.bench_function("100 nodes (100-level hierarchy)", |b| {
299    //      b.iter_batched(
300    //         || {
301    //             let mut taffy = Taffy::new();
302    //             let root = build_deep_hierarchy(&mut taffy, 100, 1);
303    //             (taffy, root)
304    //         },
305    //         |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
306    //         criterion::BatchSize::SmallInput,
307    //     )
308    // });
309
310    // group.bench_function("1_000 nodes (1000-level hierarchy)", |b| {
311    //      b.iter_batched(
312    //         || {
313    //             let mut taffy = Taffy::new();
314    //             let root = build_deep_hierarchy(&mut taffy, 1_000, 1);
315    //             (taffy, root)
316    //         },
317    //         |(mut taffy, root)| taffy.compute_layout(root, Size::undefined()).unwrap(),
318    //         criterion::BatchSize::SmallInput,
319    //     )
320    // });
321}
322
323criterion_group!(benches, taffy_benchmarks);
324criterion_main!(benches);