Przeglądaj źródła

feat: tests and benchmarks

Jonathan Kelley 3 lat temu
rodzic
commit
e6f5656

+ 1 - 1
packages/core/.vscode/settings.json

@@ -1,3 +1,3 @@
 {
-  "rust-analyzer.inlayHints.enable": false
+  "rust-analyzer.inlayHints.enable": true
 }

+ 5 - 0
packages/core/Cargo.toml

@@ -49,6 +49,7 @@ async-std = { version = "1.9.0", features = ["attributes"] }
 criterion = "0.3.5"
 dioxus-html = { path = "../html" }
 fern = { version = "0.6.0", features = ["colored"] }
+rand = { version = "0.8.4", features = ["small_rng"] }
 simple_logger = "1.13.0"
 
 
@@ -59,3 +60,7 @@ serialize = ["serde"]
 [[bench]]
 name = "create"
 harness = false
+
+[[bench]]
+name = "jsframework"
+harness = false

+ 1 - 7
packages/core/benches/create.rs

@@ -13,10 +13,4 @@ fn criterion_benchmark(c: &mut Criterion) {
 }
 
 criterion_group!(benches, criterion_benchmark);
-
-fn main() {
-    benches();
-    Criterion::default().configure_from_args().final_summary();
-    // $crate::__warn_about_html_reports_feature();
-    // $crate::__warn_about_cargo_bench_support_feature();
-}
+criterion_main!(benches);

+ 131 - 0
packages/core/benches/jsframework.rs

@@ -0,0 +1,131 @@
+//! This benchmark tests just the overhead of Dioxus itself.
+//!
+//! For the JS Framework Benchmark, both the framework and the browser is benchmarked together. Dioxus prepares changes
+//! to be made, but the change application phase will be just as performant as the vanilla wasm_bindgen code. In essence,
+//! we are measuring the overhead of Dioxus, not the performance of the "apply" phase.
+//!
+//! On my MBP 2019:
+//! - Dioxus takes 3ms to create 1_000 rows
+//! - Dioxus takes 30ms to create 10_000 rows
+//!
+//! As pure "overhead", these are really really good numbers, mostly slowed down by hitting the global allocator.
+//! These numbers don't represent Dioxus with the heuristic engine installed, so I assume it'll be even faster.
+
+use std::fmt::Display;
+
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+use dioxus_core as dioxus;
+use dioxus_core::prelude::*;
+use dioxus_html as dioxus_elements;
+use rand::prelude::*;
+
+criterion_group!(mbenches, create_rows);
+criterion_main!(mbenches);
+
+fn create_rows(c: &mut Criterion) {
+    static App: FC<()> = |cx| {
+        let mut rng = SmallRng::from_entropy();
+        let rows = (0..10_000).map(|f| {
+            let label = Label::new(&mut rng);
+            rsx! {
+                Row {
+                    row_id: f,
+                    label: label
+                }
+            }
+        });
+        cx.render(rsx! {
+            table {
+                tbody {
+                    {rows}
+                }
+            }
+        })
+    };
+
+    c.bench_function("create rows", |b| {
+        b.iter(|| {
+            let mut dom = VirtualDom::new(App);
+            let g = dom.rebuild().unwrap();
+            assert!(g.edits.len() > 1);
+        })
+    });
+}
+
+#[derive(PartialEq, Props)]
+struct RowProps {
+    row_id: usize,
+    label: Label,
+}
+fn Row<'a>(cx: Context<'a, RowProps>) -> DomTree {
+    cx.render(rsx! {
+        tr {
+            td { class:"col-md-1", "{cx.row_id}" }
+            td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
+                a { class: "lbl", "{cx.label}" }
+            }
+            td { class: "col-md-1"
+                a { class: "remove", onclick: move |_| {/* remove */}
+                    span { class: "glyphicon glyphicon-remove remove" aria_hidden: "true" }
+                }
+            }
+            td { class: "col-md-6" }
+        }
+    })
+}
+
+#[derive(PartialEq)]
+struct Label([&'static str; 3]);
+
+impl Label {
+    fn new(rng: &mut SmallRng) -> Self {
+        Label([
+            ADJECTIVES.choose(rng).unwrap(),
+            COLOURS.choose(rng).unwrap(),
+            NOUNS.choose(rng).unwrap(),
+        ])
+    }
+}
+impl Display for Label {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{} {} {}", self.0[0], self.0[1], self.0[2])
+    }
+}
+
+static ADJECTIVES: &[&str] = &[
+    "pretty",
+    "large",
+    "big",
+    "small",
+    "tall",
+    "short",
+    "long",
+    "handsome",
+    "plain",
+    "quaint",
+    "clean",
+    "elegant",
+    "easy",
+    "angry",
+    "crazy",
+    "helpful",
+    "mushy",
+    "odd",
+    "unsightly",
+    "adorable",
+    "important",
+    "inexpensive",
+    "cheap",
+    "expensive",
+    "fancy",
+];
+
+static COLOURS: &[&str] = &[
+    "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
+    "orange",
+];
+
+static NOUNS: &[&str] = &[
+    "table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
+    "pizza", "mouse", "keyboard",
+];

+ 109 - 0
packages/core/examples/jsframework.rs

@@ -0,0 +1,109 @@
+use dioxus_core as dioxus;
+use dioxus_core::prelude::*;
+use dioxus_html as dioxus_elements;
+use rand::prelude::*;
+use std::fmt::Display;
+
+fn main() {
+    let mut dom = VirtualDom::new(App);
+    let g = dom.rebuild().unwrap();
+    assert!(g.edits.len() > 1);
+}
+
+static App: FC<()> = |cx| {
+    let mut rng = SmallRng::from_entropy();
+    let rows = (0..10_000).map(|f| {
+        let label = Label::new(&mut rng);
+        rsx! {
+            Row {
+                row_id: f,
+                label: label
+            }
+        }
+    });
+    cx.render(rsx! {
+        table {
+            tbody {
+                {rows}
+            }
+        }
+    })
+};
+
+#[derive(PartialEq, Props)]
+struct RowProps {
+    row_id: usize,
+    label: Label,
+}
+fn Row<'a>(cx: Context<'a, RowProps>) -> DomTree {
+    cx.render(rsx! {
+        tr {
+            td { class:"col-md-1", "{cx.row_id}" }
+            td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
+                a { class: "lbl", "{cx.label}" }
+            }
+            td { class: "col-md-1"
+                a { class: "remove", onclick: move |_| {/* remove */}
+                    span { class: "glyphicon glyphicon-remove remove" aria_hidden: "true" }
+                }
+            }
+            td { class: "col-md-6" }
+        }
+    })
+}
+
+#[derive(PartialEq)]
+struct Label([&'static str; 3]);
+
+impl Label {
+    fn new(rng: &mut SmallRng) -> Self {
+        Label([
+            ADJECTIVES.choose(rng).unwrap(),
+            COLOURS.choose(rng).unwrap(),
+            NOUNS.choose(rng).unwrap(),
+        ])
+    }
+}
+impl Display for Label {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{} {} {}", self.0[0], self.0[1], self.0[2])
+    }
+}
+
+static ADJECTIVES: &[&str] = &[
+    "pretty",
+    "large",
+    "big",
+    "small",
+    "tall",
+    "short",
+    "long",
+    "handsome",
+    "plain",
+    "quaint",
+    "clean",
+    "elegant",
+    "easy",
+    "angry",
+    "crazy",
+    "helpful",
+    "mushy",
+    "odd",
+    "unsightly",
+    "adorable",
+    "important",
+    "inexpensive",
+    "cheap",
+    "expensive",
+    "fancy",
+];
+
+static COLOURS: &[&str] = &[
+    "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
+    "orange",
+];
+
+static NOUNS: &[&str] = &[
+    "table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
+    "pizza", "mouse", "keyboard",
+];

+ 4 - 2
packages/core/src/diff.rs

@@ -945,7 +945,8 @@ impl<'bump> DiffMachine<'bump> {
                         for child in RealChildIterator::new(next_new, self.vdom) {
                             let el = child.direct_id();
                             self.mutations.push_root(el);
-                            self.mutations.insert_before(1);
+                            todo!();
+                            // self.mutations.insert_before(1);
                         }
                     } else {
                         self.stack.create_node(
@@ -990,7 +991,8 @@ impl<'bump> DiffMachine<'bump> {
                 for child in RealChildIterator::new(last_node, self.vdom) {
                     let el = child.direct_id();
                     self.mutations.push_root(el);
-                    self.mutations.insert_after(1);
+                    // self.mutations.insert_after(1);
+                    todo!();
                 }
             } else {
                 eprintln!("key is not contained {:?}", key);