From 79f6b35258e2b508cb7ad6bf64cb01a2ce01ffc1 Mon Sep 17 00:00:00 2001 From: wycats Date: Tue, 28 Dec 2010 15:47:03 -0800 Subject: [PATCH] Add benchmarks --- Rakefile | 21 +++++++ bench/benchwarmer.js | 146 +++++++++++++++++++++++++++++++++++++++++++ bench/handlebars.js | 136 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 bench/benchwarmer.js create mode 100644 bench/handlebars.js diff --git a/Rakefile b/Rakefile index 22fc19a1..4d67cf00 100644 --- a/Rakefile +++ b/Rakefile @@ -63,3 +63,24 @@ task :debug => [:compile, "dist/handlebars.debug.js"] desc "build the build and debug versions of handlebars" task :release => [:build, :debug] + +desc "benchmark against dust.js and mustache.js" +task :bench do + require "open-uri" + File.open("vendor/mustache.js", "w") do |file| + file.puts open("https://github.com/janl/mustache.js/raw/master/mustache.js").read + file.puts "module.exports = Mustache;" + end + + File.open("vendor/benchmark.js", "w") do |file| + file.puts open("https://github.com/mathiasbynens/benchmark.js/raw/master/benchmark.js").read + end + + if File.directory?("vendor/dustjs") + system "cd vendor/dustjs && git pull" + else + system "git clone git://github.com/akdubya/dustjs.git vendor/dustjs" + end + + system "node bench/handlebars.js" +end diff --git a/bench/benchwarmer.js b/bench/benchwarmer.js new file mode 100644 index 00000000..c90fe01d --- /dev/null +++ b/bench/benchwarmer.js @@ -0,0 +1,146 @@ +var print = require("sys").print; +var Benchmark = require("benchmark"); + +var BenchWarmer = function(names) { + this.benchmarks = []; + this.currentBenches = []; + this.names = []; + this.errors = {}; +}; + +BenchWarmer.prototype = { + winners: function(benches) { + var result = Benchmark.filter(benches, function(bench) { return bench.cycles; }); + + if (result.length > 1) { + result.sort(function(a, b) { return b.compare(a); }); + first = result[0]; + last = result[result.length - 1]; + + var winners = []; + + Benchmark.each(result, function(bench) { + if (bench.compare(first) === 0) { + winners.push(bench); + } + }); + + return winners; + } else { + return result; + } + }, + suite: function(suite, fn) { + this.suiteName = suite; + this.first = true; + + var self = this; + + fn(function(name, benchFn) { + self.push(name, benchFn); + }); + }, + push: function(name, fn) { + if(this.names.indexOf(name) == -1) { + this.names.push(name); + } + + var first = this.first, suiteName = this.suiteName, self = this; + this.first = false; + + var bench = new Benchmark(function() { + fn(); + }, { + name: this.suiteName + ": " + name, + onComplete: function() { + if(first) { self.startLine(suiteName); } + self.writeBench(bench); + self.currentBenches.push(bench); + }, onError: function(bench) { + self.errors[bench.name] = bench; + } + }); + + this.benchmarks.push(bench); + }, + bench: function() { + var benchSize = 0, names = this.names, self = this, i, l; + + for(i=0, l=names.length; ivariables}}{{/each}}", + dust: "{#peeps}{>variables/}{/peeps}", + mustache: "{{#peeps}}{{>variables}}{{/peeps}}" + }, + recursion: { + context: { name: '1', kids: [{ name: '1.1', kids: [{name: '1.1.1', kids: []}] }] }, + partials: { + mustache: { recursion: "{{name}}{{#kids}}{{>recursion}}{{/kids}}" }, + handlebars: { recursion: "{{name}}{{#each kids}}{{>recursion}}{{/each}}" } + }, + handlebars: "{{name}}{{#each kids}}{{>recursion}}{{/each}}", + dust: "{name}{#kids}{>recursion:./}{/kids}", + mustache: "{{name}}{{#kids}}{{>recursion}}{{/kids}}" + }, + complex: { + handlebars: "

{{header}}

{{#if items}}{{^}}

The list is empty.

{{/if}}", + + dust: "

{header}

\n" + + "{?items}\n" + + " \n" + + "{:else}\n" + + "

The list is empty.

\n" + + "{/items}", + context: { + header: function() { + return "Colors"; + }, + items: [ + {name: "red", current: true, url: "#Red"}, + {name: "green", current: false, url: "#Green"}, + {name: "blue", current: false, url: "#Blue"} + ] + } + } + +}; + +handlebarsTemplates = {}; + +var warmer = new BenchWarmer(); + +var makeSuite = function(name) { + warmer.suite(name, function(bench) { + var templateName = name; + var details = benchDetails[templateName]; + var mustachePartials = details.partials && details.partials.mustache; + var mustacheSource = details.mustache; + var context = details.context; + + bench("dust", function() { + dust.render(templateName, context, function(err, out) { }); + }); + + bench("handlebars", function() { + handlebarsTemplates[templateName](context); + }); + + if(mustacheSource) { + bench("mustache", function() { + Mustache.to_html(mustacheSource, context, mustachePartials); + }); + } + }); +} + +for(var name in benchDetails) { + if(benchDetails.hasOwnProperty(name)) { + dust.loadSource(dust.compile(benchDetails[name].dust, name)); + handlebarsTemplates[name] = Handlebars.VM.compile(benchDetails[name].handlebars); + + var partials = benchDetails[name].partials; + if(partials) { + for(var partialName in partials.handlebars) { + if(partials.handlebars.hasOwnProperty(partialName)) { + Handlebars.registerPartial(partialName, partials.handlebars[partialName]); + } + } + } + + makeSuite(name); + } +} + +warmer.bench();