Skip to content

Commit

Permalink
add headless benchmarking
Browse files Browse the repository at this point in the history
  • Loading branch information
WorldSEnder committed Sep 10, 2021
1 parent 0fa0624 commit 2b0cba2
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 393 deletions.
2 changes: 0 additions & 2 deletions .cargo/config

This file was deleted.

3 changes: 3 additions & 0 deletions .github/workflows/everything.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ jobs:
- name: Run Browser Tests
run: wasm-pack test --headless --chrome --firefox examples/yew-integration

- name: Run Browser Benchmarks
run: wasm-pack test --headless --chrome --firefox examples/benchmarks --release --no-default-features

publish:
name: Publish to crates.io
runs-on: ubuntu-latest
Expand Down
16 changes: 13 additions & 3 deletions examples/benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,22 @@ authors = ["Kaede Hoshikawa <[email protected]>"]
edition = "2018"

[dependencies]
stylist = { path = "../../packages/stylist" }

log = "0.4.14"
console_log = { version = "0.2.0", features = ["color"] }
yew = "0.18.0"
stylist = { path = "../../packages/stylist", features = ["yew_integration"] }
web-sys = { version = "0.3.53", features = [
"Window",
"Performance",
] }
gloo = "0.3.0"

yew = { version = "0.18.0", optional = true }
gloo = { version = "0.3.0", optional = true }

[features]
default = ["with_interface"]
with_interface = ["stylist/yew_integration", "yew", "gloo"]

[dev-dependencies]
wasm-bindgen-test = "0.3.26"
wasm-bindgen = "0.2"
270 changes: 270 additions & 0 deletions examples/benchmarks/src/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
use gloo::timers::callback::Timeout;
use stylist::{yew::Global, StyleSource, YieldStyle};
use yew::prelude::*;

use crate::runner::BenchmarkResults;

static GLOBAL_STYLE: &str = r#"
html, body {
margin: 0;
padding: 0;
font-family: sans-serif;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
"#;

pub enum BenchMsg {
Step(BenchmarkResults),
}

pub struct Benchmarks {
link: ComponentLink<Self>,
finished: bool,
results: BenchmarkResults,
}

impl Benchmarks {
fn step(&mut self) {
let link = &self.link;
let mut results = self.results.clone();
let cb = link.batch_callback_once(move |_| results.step().then(|| BenchMsg::Step(results)));
Timeout::new(0, move || cb.emit(())).forget();
}
}

impl Component for Benchmarks {
type Message = BenchMsg;
type Properties = ();

fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
Self {
link,
finished: false,
results: Default::default(),
}
}

fn rendered(&mut self, first_render: bool) {
if first_render {
self.step();
}
}

fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Self::Message::Step(next_results) => {
self.results = next_results;
self.step();
}
}
true
}

fn change(&mut self, _: Self::Properties) -> ShouldRender {
false
}

fn view(&self) -> Html {
let results = &self.results;
html! {
<div class=self.style()>
{
if !self.finished {
html!{<div class="running">{"Benchmarking..."}<br />{"The browser may be unresponsive during the benchmark."}</div>}
} else {
html!{<div class="running" />}
}
}

<table>
<thead>
<tr>
<th>{"Benchmark"}</th>
<th>{"Result"}</th>
</tr>
</thead>
<tbody>
<tr>
<th>{"Parse Simple (10,000,000 iterations): "}</th>
<th>{results.parse_simple.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Macro (Literal) Simple (10,000,000 iterations): "}</th>
<th>{results.macro_simple.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Macro (Inline) Simple (10,000,000 iterations): "}</th>
<th>{results.macro_inline_simple.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Parse Simple, No Cache (100,000 iterations): "}</th>
<th>{results.parse_simple_no_cache.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Parse Complex (1,000,000 iterations): "}</th>
<th>{results.parse_complex.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Macro (Literal) Complex (1,000,000 iterations): "}</th>
<th>{results.macro_complex.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Macro (Inline) Complex (1,000,000 iterations): "}</th>
<th>{results.macro_inline_complex.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Parse Complex, No Cache (100,000 iterations): "}</th>
<th>{results.parse_complex_no_cache.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Cached Lookup (1,000,000 iterations): "}</th>
<th>{results.cached_lookup.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Cached Lookup, Big Sheet (100,000 iterations): "}</th>
<th>{results.cached_lookup_big_sheet.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
<tr>
<th>{"Mounting (2,000 iterations): "}</th>
<th>{results.mounting.map(|m| {format!("{:.0}ms", m)}).unwrap_or_else(|| "".to_string())}</th>
</tr>
</tbody>
</table>
</div>
}
}
}

impl YieldStyle for Benchmarks {
fn style_from(&self) -> StyleSource<'static> {
r#"
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.running {
height: 50px;
}
table {
border: 1px solid black;
border-collapse: collapse;
}
thead {
font-weight: bold;
background-color: rgb(240, 240, 240);
}
th {
text-align: left;
border: 1px solid black;
border-collapse: collapse;
padding: 5px;
}
tbody th {
font-weight: normal;
}
th:nth-child(1) {
padding-right: 20px;
}
th:nth-child(2) {
padding-left: 20px;
padding-right: 20px;
}
tbody tr:nth-child(even) {
background-color: rgb(240, 240, 240);
}
"#
.into()
}
}

#[derive(Debug, PartialEq)]
pub enum AppMsg {
Start,
}

pub struct App {
link: ComponentLink<Self>,
started: bool,
}

impl Component for App {
type Message = AppMsg;
type Properties = ();

fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
Self {
link,
started: false,
}
}

fn update(&mut self, msg: Self::Message) -> ShouldRender {
assert_eq!(msg, AppMsg::Start);

self.started = true;

true
}

fn change(&mut self, _: Self::Properties) -> ShouldRender {
false
}

fn view(&self) -> Html {
html! {
<>
<Global css=GLOBAL_STYLE />
<div class=self.style()>
<h1>{"Stylist Benchmark"}</h1>
{
if self.started {
html!{<Benchmarks />}
} else {
html!{
<>
<div class="before-intro">{"To start benchmarking, please click start:"}</div>
<button onclick=self.link.callback(|_| AppMsg::Start)>
{"Start!"}
</button>
</>
}
}
}
</div>
</>
}
}
}

impl YieldStyle for App {
fn style_from(&self) -> StyleSource<'static> {
r#"
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.before-intro {
padding-bottom: 20px;
}
button {
width: 300px;
height: 50px;
font-size: 20px;
}
"#
.into()
}
}
Loading

0 comments on commit 2b0cba2

Please sign in to comment.