Skip to content

Commit

Permalink
feat: Torin benchmarks (#277)
Browse files Browse the repository at this point in the history
* feat: Torin benchmarks

* test

* test 2

* test 3

* update benchmark

* update benchmark

* update benchmark

* update benchmark

* update benchmark

* update benchmark

* update benchmark

* update benchmark

* update benchmark

* update

* test

* revert test
  • Loading branch information
marc2332 authored Sep 6, 2023
1 parent 4d0d05f commit a379c09
Show file tree
Hide file tree
Showing 3 changed files with 342 additions and 24 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
on:
push:
paths:
- 'crates/torin/**/*'
- '.github/workflows/benchmarks.yml'

name: Run Benchmarks
jobs:
runBenchmark:
name: run benchmark
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: boa-dev/criterion-compare-action@59f4d964c5f19d7f13d36f5c0944b18ce6652cb0
with:
package: torin
branchName: feat/torin-benchmarks-TEST-COMPARE
token: ${{ secrets.GITHUB_TOKEN }}
57 changes: 33 additions & 24 deletions crates/torin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
[package]
name = "torin"
description = "UI layout Library designed for Freya."
version = "0.1.0"
edition = "2021"
license = "MIT"
authors = ["Marc Espín <[email protected]>"]
readme = "../../readme.md"
homepage = "https://freyaui.dev/"
repository = "https://github.com/marc2332/freya"
keywords = ["gui", "ui", "desktop", "skia", "dioxus"]
categories = ["gui", "caching"]

[features]
dioxus = ["dep:dioxus-native-core", "dep:dioxus-core"]
default = ["dioxus"]

[dependencies]
tracing = { workspace = true }
euclid = { workspace = true }
fxhash = { workspace = true }
dioxus-native-core = { workspace = true, optional = true }
dioxus-core = { workspace = true, optional = true }

[package]
name = "torin"
description = "UI layout Library designed for Freya."
version = "0.1.0"
edition = "2021"
license = "MIT"
authors = ["Marc Espín <[email protected]>"]
readme = "../../readme.md"
homepage = "https://freyaui.dev/"
repository = "https://github.com/marc2332/freya"
keywords = ["gui", "ui", "desktop", "skia", "dioxus"]
categories = ["gui", "caching"]

[features]
dioxus = ["dep:dioxus-native-core", "dep:dioxus-core"]
default = ["dioxus"]

[dependencies]
tracing = { workspace = true }
euclid = { workspace = true }
fxhash = { workspace = true }
dioxus-native-core = { workspace = true, optional = true }
dioxus-core = { workspace = true, optional = true }

[dev-dependencies]
criterion = "0.5.1"

[lib]
bench = false

[[bench]]
name = "bench"
harness = false
291 changes: 291 additions & 0 deletions crates/torin/benches/bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
use std::collections::HashMap;

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use torin::prelude::*;

struct TestingMeasurer;

impl LayoutMeasurer<usize> for TestingMeasurer {
fn measure(
&mut self,
_node_id: usize,
_node: &Node,
_area: &Area,
_parent_size: &Area,
_available_parent_area: &Area,
) -> Option<Area> {
None
}
}

#[derive(Default)]
struct TestingDOM {
mapper: HashMap<usize, (Option<usize>, Vec<usize>, u16, Node)>,
}

impl TestingDOM {
fn add(&mut self, node_id: usize, parent: Option<usize>, children: Vec<usize>, node: Node) {
let depth = parent.map(|p| self.mapper.get(&p).unwrap().2).unwrap_or(0) + 1;
self.mapper.insert(node_id, (parent, children, depth, node));
}

fn set_node(&mut self, node_id: usize, node: Node) {
self.mapper.get_mut(&node_id).unwrap().3 = node;
}
}

impl DOMAdapter<usize> for TestingDOM {
fn children_of(&self, node_id: &usize) -> Vec<usize> {
self.mapper
.get(node_id)
.map(|c| c.1.clone())
.unwrap_or_default()
}

fn parent_of(&self, node_id: &usize) -> Option<usize> {
self.mapper.get(node_id).map(|c| c.0).flatten()
}

fn height(&self, node_id: &usize) -> Option<u16> {
self.mapper.get(node_id).map(|c| c.2)
}

fn get_node(&self, node_id: &usize) -> Option<Node> {
self.mapper.get(node_id).map(|c| c.3.clone())
}

fn is_node_valid(&self, _node_id: &usize) -> bool {
true
}

fn closest_common_parent(&self, node_id_a: &usize, _node_id_b: &usize) -> Option<usize> {
Some(self.parent_of(node_id_a)?)
}
}

fn criterion_benchmark(c: &mut Criterion) {
let mut g = c.benchmark_group("benchmarks");
g.significance_level(0.1).sample_size(500);

let params = [
("big trees (wide) nodes=1000, depth=1", 1000, 1),
("big trees (wide) nodes=10000, depth=1", 10000, 1),
("big trees (wide) nodes=100000, depth=1", 100000, 1),
("big trees (deep) nodes=4000, depth=12", 4000, 12),
("big trees (deep) nodes=10000, depth=14", 10000, 14),
("big trees (deep) nodes=100000, depth=17", 100000, 17),
];

for (name, size, depth) in params {
let size_per_layer = size / depth;

g.bench_function(name, |b| {
let mut measurer = Some(TestingMeasurer);
let mut mocked_dom = TestingDOM::default();

let children_ids = (1..=size_per_layer).into_iter().collect::<Vec<usize>>();

let mut root = 0;

mocked_dom.add(
0,
None,
children_ids.clone(),
Node::from_size_and_direction(
Size::Percentage(Length::new(100.0)),
Size::Percentage(Length::new(100.0)),
DirectionMode::Vertical,
),
);

for level in 0..depth {
for i in &children_ids {
let id = (level * size) + *i;

mocked_dom.add(
id,
Some(root),
vec![],
Node::from_size_and_direction(
Size::Pixels(Length::new(100.0)),
Size::Pixels(Length::new(100.0)),
DirectionMode::Vertical,
),
);

if *i == size_per_layer - 1 {
root = id
}
}
}

b.iter(|| {
black_box({
let mut layout = Torin::<usize>::new();
layout.find_best_root(&mocked_dom);
layout.measure(
0,
Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)),
&mut measurer,
&mocked_dom,
)
});
})
});
}

g.bench_function(
"big trees (deep + cached) + invalidated node in the top",
|b| {
let mut layout = Torin::<usize>::new();
let mut measurer = Some(TestingMeasurer);
let mut mocked_dom = TestingDOM::default();

let children_ids = (1..=101).into_iter().collect::<Vec<usize>>();

let mut root = 0;

mocked_dom.add(
0,
None,
children_ids.clone(),
Node::from_size_and_direction(
Size::Percentage(Length::new(100.0)),
Size::Percentage(Length::new(100.0)),
DirectionMode::Vertical,
),
);

let levels = 20;

for level in 0..levels {
for i in &children_ids {
let id = (level * 1000) + *i;

mocked_dom.add(
id,
Some(root),
vec![],
Node::from_size_and_direction(
Size::Pixels(Length::new(100.0)),
Size::Pixels(Length::new(100.0)),
DirectionMode::Vertical,
),
);

if *i == 101 {
root = id
}
}
}

layout.find_best_root(&mocked_dom);
layout.measure(
0,
Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)),
&mut measurer,
&mocked_dom,
);

b.iter(|| {
black_box({
mocked_dom.set_node(
1,
Node::from_size_and_direction(
Size::Inner,
Size::Pixels(Length::new(10.0)),
DirectionMode::Vertical,
),
);
layout.invalidate(1);
layout.find_best_root(&mocked_dom);
layout.measure(
0,
Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)),
&mut measurer,
&mocked_dom,
)
});
})
},
);

g.bench_function(
"big trees (deep + cached) + invalidated node in the bottom",
|b| {
let mut layout = Torin::<usize>::new();
let mut measurer = Some(TestingMeasurer);
let mut mocked_dom = TestingDOM::default();

let children_ids = (1..=101).into_iter().collect::<Vec<usize>>();

let mut root = 0;

mocked_dom.add(
0,
None,
children_ids.clone(),
Node::from_size_and_direction(
Size::Percentage(Length::new(100.0)),
Size::Percentage(Length::new(100.0)),
DirectionMode::Vertical,
),
);

let levels = 20;

for level in 0..levels {
for i in &children_ids {
let id = (level * 1000) + *i;

mocked_dom.add(
id,
Some(root),
vec![],
Node::from_size_and_direction(
Size::Pixels(Length::new(100.0)),
Size::Pixels(Length::new(100.0)),
DirectionMode::Vertical,
),
);

if *i == 101 {
root = id
}
}
}

layout.find_best_root(&mocked_dom);
layout.measure(
0,
Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)),
&mut measurer,
&mocked_dom,
);

b.iter(|| {
black_box({
mocked_dom.set_node(
1,
Node::from_size_and_direction(
Size::Inner,
Size::Pixels(Length::new(10.0)),
DirectionMode::Vertical,
),
);
layout.invalidate(2001);
layout.find_best_root(&mocked_dom);
layout.measure(
0,
Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1000.0, 1000.0)),
&mut measurer,
&mocked_dom,
)
});
})
},
);
}

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

0 comments on commit a379c09

Please sign in to comment.