Skip to content

Commit

Permalink
Merge pull request #234 from epage/bench
Browse files Browse the repository at this point in the history
Comparitive benchmarks with Handlebars / Tera
  • Loading branch information
epage authored Nov 20, 2018
2 parents 969b6c8 + 863eae1 commit 2bc2462
Show file tree
Hide file tree
Showing 10 changed files with 1,038 additions and 78 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ serde_json = { version = "1.0", optional = true }
difference = "2.0"
docmatic = "0.1"
serde_yaml = "0.8"
tera = "0.11"
handlebars = "1.1"
serde_derive = "1.0"
serde_json = "1.0"
103 changes: 103 additions & 0 deletions benches/handlebars_baseline.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#![feature(test)]
extern crate handlebars;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

extern crate test;

use std::collections::BTreeMap;

use handlebars::{to_json, Handlebars, Template};
use serde_json::value::Value as Json;

static SOURCE: &'static str = "<html>
<head>
<title>{{year}}</title>
</head>
<body>
<h1>CSL {{year}}</h1>
<ul>
{{#each teams}}
<li class=\"{{#if @first}}champion{{/if}}\">
<b>{{name}}</b>: {{score}}
</li>
{{/each}}
</ul>
</body>
</html>";

fn make_data() -> BTreeMap<String, Json> {
let mut data = BTreeMap::new();

data.insert("year".to_string(), to_json("2015"));

let mut teams = Vec::new();

for v in vec![
("Jiangsu", 43u16),
("Beijing", 27u16),
("Guangzhou", 22u16),
("Shandong", 12u16),
].iter()
{
let (name, score) = *v;
let mut t = BTreeMap::new();
t.insert("name".to_string(), to_json(name));
t.insert("score".to_string(), to_json(score));
teams.push(t)
}

data.insert("teams".to_string(), to_json(&teams));
data
}

#[bench]
fn parse_template(b: &mut test::Bencher) {
b.iter(|| Template::compile(SOURCE).ok().unwrap());
}

#[bench]
fn render_template(b: &mut test::Bencher) {
let mut handlebars = Handlebars::new();
handlebars
.register_template_string("table", SOURCE)
.ok()
.expect("Invalid template format");

let data = make_data();
b.iter(|| handlebars.render("table", &data).ok().unwrap())
}

#[derive(Serialize)]
struct DataWrapper {
v: String,
}

#[derive(Serialize)]
struct RowWrapper {
real: Vec<DataWrapper>,
dummy: Vec<DataWrapper>,
}

#[bench]
fn large_loop_helper(b: &mut test::Bencher) {
let mut handlebars = Handlebars::new();
handlebars
.register_template_string("test", "BEFORE\n{{#each real}}{{this.v}}{{/each}}AFTER")
.ok()
.expect("Invalid template format");

let real: Vec<DataWrapper> = (1..1000)
.into_iter()
.map(|i| DataWrapper {
v: format!("n={}", i),
}).collect();
let dummy: Vec<DataWrapper> = (1..1000)
.into_iter()
.map(|i| DataWrapper {
v: format!("n={}", i),
}).collect();
let rows = RowWrapper { real, dummy };
b.iter(|| handlebars.render("test", &rows).ok().unwrap());
}
79 changes: 79 additions & 0 deletions benches/handlebars_liquid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#![feature(test)]

extern crate serde_yaml;
extern crate test;

extern crate liquid;

// Mirrors handlebars' benchmark
static ITERATE: &'static str = "<html>
<head>
<title>{{year}}</title>
</head>
<body>
<h1>CSL {{year}}</h1>
<ul>
{% for team in teams %}
<li class=\"{% if forloop.index0 == 0 %}champion{{% endif %}\">
<b>{{team.name}}</b>: {{team.score}}
</li>
{% endfor %}
</ul>
</body>
</html>";
static ITERATE_OBJECT: &'static str = "
year: 2015
teams:
- name: Jiangsu
score: 43
- name: Beijing
score: 27
- name: Guangzhou
score: 22
- name: Shandong
score: 12
";

#[bench]
fn parse_template(b: &mut test::Bencher) {
let parser = liquid::ParserBuilder::with_liquid().extra_filters().build();
b.iter(|| parser.parse(ITERATE));
}

#[bench]
fn render_template(b: &mut test::Bencher) {
let parser = liquid::ParserBuilder::with_liquid().extra_filters().build();
let template = parser
.parse(ITERATE)
.expect("Benchmark template parsing failed");

let data: liquid::value::Object =
serde_yaml::from_str(ITERATE_OBJECT).expect("Benchmark object parsing failed");

template.render(&data).unwrap();
b.iter(|| template.render(&data));
}

static LOOP: &'static str = "BEFORE\n{% for this in real%}{{this}}{%endfor%}AFTER";

#[bench]
fn large_loop_helper(b: &mut test::Bencher) {
let parser = liquid::ParserBuilder::with_liquid().extra_filters().build();
let template = parser
.parse(LOOP)
.expect("Benchmark template parsing failed");

let data_wrapper = liquid::value::Value::array(
(1..1000)
.map(|i| format!("n={}", i))
.map(liquid::value::Value::scalar),
);
let row_wrapper: liquid::value::Object = vec![
("real".into(), data_wrapper.clone()),
("dummy".into(), data_wrapper.clone()),
].into_iter()
.collect();

template.render(&row_wrapper).unwrap();
b.iter(|| template.render(&row_wrapper));
}
79 changes: 1 addition & 78 deletions benches/liquid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,83 +22,6 @@ fn bench_render_text(b: &mut test::Bencher) {

let data = liquid::value::Object::new();

b.iter(|| template.render(&data));
}

// Mirrors tera's VARIABLE_ONLY benchmark
static VARIABLE_ONLY: &'static str = "{{product.name}}";
static VARIABLE_ONLY_OBJECT: &'static str = "
username: bob
product:
name: Moto G
manufacturer: Motorola
summary: A phone
price: 100
";

#[bench]
fn bench_parse_variable(b: &mut test::Bencher) {
let parser = liquid::ParserBuilder::with_liquid().extra_filters().build();
b.iter(|| parser.parse(VARIABLE_ONLY));
}

#[bench]
fn bench_render_variable(b: &mut test::Bencher) {
let parser = liquid::ParserBuilder::with_liquid().extra_filters().build();
let template = parser
.parse(VARIABLE_ONLY)
.expect("Benchmark template parsing failed");

let data: liquid::value::Object =
serde_yaml::from_str(VARIABLE_ONLY_OBJECT).expect("Benchmark object parsing failed");

b.iter(|| template.render(&data));
}

// Mirrors handlebars' benchmark
static ITERATE: &'static str = "<html>
<head>
<title>{{year}}</title>
</head>
<body>
<h1>CSL {{year}}</h1>
<ul>
{% for team in teams %}
<li class=\"champion\">
<b>{{team.name}}</b>: {{team.score}}
</li>
{% endfor %}
</ul>
</body>
</html>";
static ITERATE_OBJECT: &'static str = "
year: 2015
teams:
- name: Jiangsu
score: 43
- name: Beijing
score: 27
- name: Guangzhou
score: 22
- name: Shandong
score: 12
";

#[bench]
fn bench_parse_template(b: &mut test::Bencher) {
let parser = liquid::ParserBuilder::with_liquid().extra_filters().build();
b.iter(|| parser.parse(ITERATE));
}

#[bench]
fn bench_render_template(b: &mut test::Bencher) {
let parser = liquid::ParserBuilder::with_liquid().extra_filters().build();
let template = parser
.parse(ITERATE)
.expect("Benchmark template parsing failed");

let data: liquid::value::Object =
serde_yaml::from_str(ITERATE_OBJECT).expect("Benchmark object parsing failed");

template.render(&data).unwrap();
b.iter(|| template.render(&data));
}
Loading

0 comments on commit 2bc2462

Please sign in to comment.