Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tree creation benchmarks #401

Merged
merged 2 commits into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ taffy = { path = ".", features = ["random"] }
lto = true
panic = 'abort'

[[bench]]
name = "tree_creation"
path = "benches/tree_creation.rs"
harness = false

[[bench]]
name = "flexbox"
path = "benches/flexbox.rs"
Expand Down
1 change: 1 addition & 0 deletions benches/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pub mod yoga_helpers;

/// A helper function to recursively construct a deep tree
#[allow(dead_code)]
pub fn build_deep_tree<T, N>(
tree: &mut T,
max_nodes: u32,
Expand Down
12 changes: 12 additions & 0 deletions benches/helpers/yoga_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use slotmap::{DefaultKey, SlotMap};

pub mod yg {
Expand All @@ -12,6 +13,17 @@ mod tf {
pub use taffy::prelude::*;
}

pub fn new_default_style_with_children(
tree: &mut SlotMap<DefaultKey, yg::Node>,
children: Vec<DefaultKey>,
) -> DefaultKey {
let mut node = yg::Node::new();
for (i, child) in children.into_iter().enumerate() {
node.insert_child(&mut tree[child], i as u32);
}
tree.insert(node)
}

pub fn new_with_children(
tree: &mut SlotMap<DefaultKey, yg::Node>,
style: &tf::Style,
Expand Down
99 changes: 99 additions & 0 deletions benches/tree_creation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! This file includes benchmarks for tree creation
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use rand::prelude::*;
use rand_chacha::ChaCha8Rng;
use taffy::prelude::*;
use taffy::style::Style;

mod helpers;

#[cfg(feature = "yoga_benchmark")]
use helpers::yoga_helpers;
#[cfg(feature = "yoga_benchmark")]
use slotmap::SlotMap;
#[cfg(feature = "yoga_benchmark")]
use yoga_helpers::yg;

/// Build a random leaf node
fn build_random_leaf(taffy: &mut Taffy) -> Node {
taffy.new_with_children(Style::DEFAULT, &[]).unwrap()
}

/// A tree with many children that have shallow depth
fn build_taffy_flat_hierarchy(total_node_count: u32, use_with_capacity: bool) -> (Taffy, Node) {
let mut taffy = if use_with_capacity { Taffy::with_capacity(total_node_count as usize) } else { Taffy::new() };
let mut rng = ChaCha8Rng::seed_from_u64(12345);
let mut children = Vec::new();
let mut node_count = 0;

while node_count < total_node_count {
let sub_children_count = rng.gen_range(1..=4);
let sub_children: Vec<Node> = (0..sub_children_count).map(|_| build_random_leaf(&mut taffy)).collect();
let node = taffy.new_with_children(Style::DEFAULT, &sub_children).unwrap();

children.push(node);
node_count += 1 + sub_children_count;
}

let root = taffy.new_with_children(Style::DEFAULT, children.as_slice()).unwrap();
(taffy, root)
}

#[cfg(feature = "yoga_benchmark")]
/// A tree with many children that have shallow depth
fn build_yoga_flat_hierarchy(total_node_count: u32) -> (yg::YogaTree, Node) {
let mut tree = SlotMap::new();
let mut rng = ChaCha8Rng::seed_from_u64(12345);
let mut children = Vec::new();
let mut node_count = 0;

while node_count < total_node_count {
let sub_children_count = rng.gen_range(1..=4);
let sub_children: Vec<Node> =
(0..sub_children_count).map(|_| yoga_helpers::new_default_style_with_children(&mut tree, vec![])).collect();
let node = yoga_helpers::new_default_style_with_children(&mut tree, sub_children);

children.push(node);
node_count += 1 + sub_children_count;
}

let root = yoga_helpers::new_default_style_with_children(&mut tree, children);
(tree, root)
}

fn taffy_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("Tree creation");
for node_count in [1_000u32, 10_000, 100_000].iter() {
#[cfg(feature = "yoga_benchmark")]
let benchmark_id = BenchmarkId::new(format!("Yoga"), node_count);
#[cfg(feature = "yoga_benchmark")]
group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
b.iter(|| {
let (taffy, root) = build_yoga_flat_hierarchy(node_count);
std::hint::black_box(taffy);
std::hint::black_box(root);
})
});
let benchmark_id = BenchmarkId::new(format!("Taffy::new"), node_count);
group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
b.iter(|| {
let (tree, root) = build_taffy_flat_hierarchy(node_count, false);
std::hint::black_box(tree);
std::hint::black_box(root);
})
});

let benchmark_id = BenchmarkId::new(format!("Taffy::with_capacity"), node_count);
group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
b.iter(|| {
let (tree, root) = build_taffy_flat_hierarchy(node_count, true);
std::hint::black_box(tree);
std::hint::black_box(root);
})
});
}
group.finish();
}

criterion_group!(benches, taffy_benchmarks);
criterion_main!(benches);