tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 583HTML 275Markdown 8TOML 41586 Sutichaykuna

⎇ 0.3.x benches/flexbox.rs Rust · 249 siq'ikuna · 10.4 KB Ñawpa willay Pi imata llamkarqan ch'uya

Remove generated benchmarks (#358) 57672e96e · Nico Burns ·

1//! This file includes benchmarks for very large, pseudo-randomly generated trees
2use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
3use rand::prelude::*;
4use rand_chacha::ChaCha8Rng;
5use taffy::prelude::*;
6use taffy::randomizable::Randomizeable;
7use taffy::style::Style;
8
9mod helpers;
10use helpers::build_deep_tree;
11
12#[cfg(feature = "yoga_benchmark")]
13use helpers::yoga_helpers;
14#[cfg(feature = "yoga_benchmark")]
15use slotmap::SlotMap;
16#[cfg(feature = "yoga_benchmark")]
17use yoga_helpers::yg;
18
19/// Build a random leaf node
20fn build_random_leaf(taffy: &mut Taffy, rng: &mut ChaCha8Rng) -> Node {
21    taffy.new_with_children(Style::random(rng), &[]).unwrap()
22}
23
24/// A tree with many children that have shallow depth
25fn build_taffy_flat_hierarchy(total_node_count: u32) -> (Taffy, Node) {
26    let mut taffy = Taffy::new();
27    let mut rng = ChaCha8Rng::seed_from_u64(12345);
28    let mut children = Vec::new();
29    let mut node_count = 0;
30
31    while node_count < total_node_count {
32        let sub_children_count = rng.gen_range(1..=4);
33        let sub_children: Vec<Node> =
34            (0..sub_children_count).map(|_| build_random_leaf(&mut taffy, &mut rng)).collect();
35        let node = taffy.new_with_children(Style::random(&mut rng), &sub_children).unwrap();
36
37        children.push(node);
38        node_count += 1 + sub_children_count;
39    }
40
41    let root = taffy.new_with_children(Style::DEFAULT, children.as_slice()).unwrap();
42    (taffy, root)
43}
44
45#[cfg(feature = "yoga_benchmark")]
46/// A tree with many children that have shallow depth
47fn build_yoga_flat_hierarchy(total_node_count: u32) -> (yg::YogaTree, Node) {
48    let mut tree = SlotMap::new();
49    let mut rng = ChaCha8Rng::seed_from_u64(12345);
50    let mut children = Vec::new();
51    let mut node_count = 0;
52
53    while node_count < total_node_count {
54        let sub_children_count = rng.gen_range(1..=4);
55        let sub_children: Vec<Node> = (0..sub_children_count)
56            .map(|_| yoga_helpers::new_with_children(&mut tree, &Style::random(&mut rng), vec![]))
57            .collect();
58        let node = yoga_helpers::new_with_children(&mut tree, &Style::random(&mut rng), sub_children);
59
60        children.push(node);
61        node_count += 1 + sub_children_count;
62    }
63
64    let root = yoga_helpers::new_with_children(&mut tree, &Style::DEFAULT, children);
65    (tree, root)
66}
67
68/// A tree with a higher depth for a more realistic scenario
69fn build_taffy_deep_hierarchy(node_count: u32, branching_factor: u32) -> (Taffy, Node) {
70    let mut rng = ChaCha8Rng::seed_from_u64(12345);
71    let mut build_leaf_node = |taffy: &mut Taffy| build_random_leaf(taffy, &mut rng);
72    let mut rng = ChaCha8Rng::seed_from_u64(12345);
73    let mut build_flex_node =
74        |taffy: &mut Taffy, children: Vec<Node>| taffy.new_with_children(Style::random(&mut rng), &children).unwrap();
75
76    let mut taffy = Taffy::new();
77    let tree = build_deep_tree(&mut taffy, node_count, branching_factor, &mut build_leaf_node, &mut build_flex_node);
78    let root = taffy.new_with_children(Style::DEFAULT, &tree).unwrap();
79    (taffy, root)
80}
81
82#[cfg(feature = "yoga_benchmark")]
83/// A tree with a higher depth for a more realistic scenario
84fn build_yoga_deep_hierarchy(node_count: u32, branching_factor: u32) -> (yg::YogaTree, Node) {
85    let mut rng = ChaCha8Rng::seed_from_u64(12345);
86    let mut build_leaf_node =
87        |tree: &mut yg::YogaTree| yoga_helpers::new_with_children(tree, &Style::random(&mut rng), vec![]);
88    let mut rng = ChaCha8Rng::seed_from_u64(12345);
89    let mut build_flex_node = |tree: &mut yg::YogaTree, children: Vec<Node>| {
90        yoga_helpers::new_with_children(tree, &Style::random(&mut rng), children)
91    };
92
93    let mut tree = SlotMap::new();
94    let children = build_deep_tree(&mut tree, node_count, branching_factor, &mut build_leaf_node, &mut build_flex_node);
95    let root = yoga_helpers::new_with_children(&mut tree, &Style::DEFAULT, children);
96
97    (tree, root)
98}
99
100/// A deep tree that matches the shape and styling that yoga use on their benchmarks
101fn build_taffy_huge_nested_hierarchy(node_count: u32, branching_factor: u32) -> (Taffy, Node) {
102    let style = Style {
103        size: Size { width: Dimension::Points(10.0), height: Dimension::Points(10.0) },
104        flex_grow: 1.0,
105        ..Default::default()
106    };
107    let mut build_leaf_node = |taffy: &mut Taffy| taffy.new_leaf(style.clone()).unwrap();
108    let mut build_flex_node =
109        |taffy: &mut Taffy, children: Vec<Node>| taffy.new_with_children(style.clone(), &children).unwrap();
110
111    let mut taffy = Taffy::new();
112    let tree = build_deep_tree(&mut taffy, node_count, branching_factor, &mut build_leaf_node, &mut build_flex_node);
113    let root = taffy.new_with_children(Style::DEFAULT, &tree).unwrap();
114    (taffy, root)
115}
116
117#[cfg(feature = "yoga_benchmark")]
118/// A deep tree that matches the shape and styling that yoga use on their benchmarks
119fn build_yoga_huge_nested_hierarchy(node_count: u32, branching_factor: u32) -> (yg::YogaTree, Node) {
120    let style = Style {
121        size: Size { width: Dimension::Points(10.0), height: Dimension::Points(10.0) },
122        flex_grow: 1.0,
123        ..Default::default()
124    };
125    let mut build_leaf_node = |tree: &mut yg::YogaTree| -> Node {
126        let mut node = yg::Node::new();
127        yoga_helpers::apply_taffy_style(&mut node, &style.clone());
128        tree.insert(node)
129    };
130    let mut build_flex_node = |tree: &mut yg::YogaTree, children: Vec<Node>| -> Node {
131        let mut node = yg::Node::new();
132        yoga_helpers::apply_taffy_style(&mut node, &style.clone());
133        for (i, child) in children.into_iter().enumerate() {
134            node.insert_child(&mut tree[child], i as u32);
135        }
136        tree.insert(node)
137    };
138
139    let mut tree = SlotMap::new();
140    let children = build_deep_tree(&mut tree, node_count, branching_factor, &mut build_leaf_node, &mut build_flex_node);
141    let mut root = yg::Node::new();
142    for (i, child) in children.into_iter().enumerate() {
143        root.insert_child(&mut tree[child], i as u32);
144    }
145    let root = tree.insert(root);
146    (tree, root)
147}
148
149fn taffy_benchmarks(c: &mut Criterion) {
150    let mut group = c.benchmark_group("yoga 'huge nested'");
151    for node_count in [1_000u32, 10_000, 100_000].iter() {
152        #[cfg(feature = "yoga_benchmark")]
153        group.bench_with_input(BenchmarkId::new("Yoga", node_count), node_count, |b, &node_count| {
154            b.iter_batched(
155                || build_yoga_huge_nested_hierarchy(node_count, 10),
156                |(mut tree, root)| {
157                    tree[root].calculate_layout(f32::INFINITY, f32::INFINITY, yg::Direction::LTR);
158                },
159                criterion::BatchSize::SmallInput,
160            )
161        });
162        group.bench_with_input(BenchmarkId::new("Taffy", node_count), node_count, |b, &node_count| {
163            b.iter_batched(
164                || build_taffy_huge_nested_hierarchy(node_count, 10),
165                |(mut taffy, root)| taffy.compute_layout(root, Size::MAX_CONTENT).unwrap(),
166                criterion::BatchSize::SmallInput,
167            )
168        });
169    }
170    group.finish();
171
172    // Decrease sample size, because the tasks take longer
173    let mut group = c.benchmark_group("big trees (wide)");
174    group.sample_size(10);
175    for node_count in [1_000u32, 10_000, 100_000].iter() {
176        #[cfg(feature = "yoga_benchmark")]
177        let benchmark_id = BenchmarkId::new(format!("Yoga (2-level hierarchy)"), node_count);
178        #[cfg(feature = "yoga_benchmark")]
179        group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
180            b.iter_batched(
181                || build_yoga_flat_hierarchy(node_count),
182                |(mut tree, root)| {
183                    tree[root].calculate_layout(f32::INFINITY, f32::INFINITY, yg::Direction::LTR);
184                },
185                criterion::BatchSize::SmallInput,
186            )
187        });
188        let benchmark_id = BenchmarkId::new(format!("Taffy (2-level hierarchy)"), node_count);
189        group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
190            b.iter_batched(
191                || build_taffy_flat_hierarchy(node_count),
192                |(mut taffy, root)| taffy.compute_layout(root, Size::MAX_CONTENT).unwrap(),
193                criterion::BatchSize::SmallInput,
194            )
195        });
196    }
197    group.finish();
198
199    // Decrease sample size, because the tasks take longer
200    let mut group = c.benchmark_group("big trees (deep)");
201    group.sample_size(10);
202    let benches = [(4000, "(12-level hierarchy)"), (10_000, "(14-level hierarchy)"), (100_000, "(17-level hierarchy)")];
203    for (node_count, label) in benches.iter() {
204        #[cfg(feature = "yoga_benchmark")]
205        group.bench_with_input(BenchmarkId::new(format!("Yoga {label}"), node_count), node_count, |b, &node_count| {
206            b.iter_batched(
207                || build_yoga_deep_hierarchy(node_count, 2),
208                |(mut tree, root)| {
209                    tree[root].calculate_layout(f32::INFINITY, f32::INFINITY, yg::Direction::LTR);
210                },
211                criterion::BatchSize::SmallInput,
212            )
213        });
214        group.bench_with_input(BenchmarkId::new(format!("Taffy {label}"), node_count), node_count, |b, &node_count| {
215            b.iter_batched(
216                || build_taffy_deep_hierarchy(node_count, 2),
217                |(mut taffy, root)| taffy.compute_layout(root, Size::MAX_CONTENT).unwrap(),
218                criterion::BatchSize::SmallInput,
219            )
220        });
221    }
222    group.finish();
223
224    let mut group = c.benchmark_group("super deep (1000-level hierarchy)");
225    group.sample_size(10);
226    for node_count in [1000u32].iter() {
227        #[cfg(feature = "yoga_benchmark")]
228        group.bench_with_input(BenchmarkId::new("Yoga", node_count), node_count, |b, &node_count| {
229            b.iter_batched(
230                || build_yoga_deep_hierarchy(node_count, 2),
231                |(mut tree, root)| {
232                    tree[root].calculate_layout(f32::INFINITY, f32::INFINITY, yg::Direction::LTR);
233                },
234                criterion::BatchSize::SmallInput,
235            )
236        });
237        group.bench_with_input(BenchmarkId::new("Taffy", node_count), node_count, |b, &node_count| {
238            b.iter_batched(
239                || build_taffy_deep_hierarchy(node_count, 2),
240                |(mut taffy, root)| taffy.compute_layout(root, Size::MAX_CONTENT).unwrap(),
241                criterion::BatchSize::SmallInput,
242            )
243        });
244    }
245    group.finish();
246}
247
248criterion_group!(benches, taffy_benchmarks);
249criterion_main!(benches);