Add a parsing benchmark.

R=nweiz@google.com

Review URL: https://codereview.chromium.org//1325013002 .
diff --git a/benchmark/benchmark.dart b/benchmark/benchmark.dart
new file mode 100644
index 0000000..aec6d4b
--- /dev/null
+++ b/benchmark/benchmark.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library yaml.benchmark.benchmark;
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+
+import 'package:yaml/yaml.dart';
+
+const numTrials = 10000000;
+const runsPerTrial = 1000;
+
+final source = loadFile("input.yaml");
+final expected = loadFile("output.json");
+
+void main(List<String> args) {
+  var best = double.INFINITY;
+
+  // Run the benchmark several times. This ensures the VM is warmed up and lets
+  // us see how much variance there is.
+  for (var i = 0; i <= numTrials; i++) {
+    var start = new DateTime.now();
+
+    // For a single benchmark, convert the source multiple times.
+    var result;
+    for (var j = 0; j < runsPerTrial; j++) {
+      result = loadYaml(source);
+    }
+
+    var elapsed =
+        new DateTime.now().difference(start).inMilliseconds / runsPerTrial;
+
+    // Keep track of the best run so far.
+    if (elapsed >= best) continue;
+    best = elapsed;
+
+    // Sanity check to make sure the output is what we expect and to make sure
+    // the VM doesn't optimize "dead" code away.
+    if (JSON.encode(result) != expected) {
+      print("Incorrect output:\n${JSON.encode(result)}");
+      exit(1);
+    }
+
+    // Don't print the first run. It's always terrible since the VM hasn't
+    // warmed up yet.
+    if (i == 0) continue;
+    printResult("Run ${padLeft('#$i', 3)}", elapsed);
+  }
+
+  printResult("Best   ", best);
+}
+
+String loadFile(String name) {
+  var path = p.join(p.dirname(p.fromUri(Platform.script)), name);
+  return new File(path).readAsStringSync();
+}
+
+void printResult(String label, double time) {
+  print("$label: ${padLeft(time.toStringAsFixed(3), 4)}ms "
+      "${'=' * ((time * 100).toInt())}");
+}
+
+String padLeft(input, int length) {
+  var result = input.toString();
+  if (result.length < length) {
+    result = " " * (length - result.length) + result;
+  }
+
+  return result;
+}
diff --git a/benchmark/input.yaml b/benchmark/input.yaml
new file mode 100644
index 0000000..89bf9dc
--- /dev/null
+++ b/benchmark/input.yaml
@@ -0,0 +1,48 @@
+verb: RecommendCafes
+recipe:
+  - verb: List
+    outputs: ["Cafe[]"]
+  - verb: Fetch
+    inputs: ["Cafe[]"]
+    outputs: ["CafeWithMenu[]"]
+  - verb: Flatten
+    inputs: ["CafeWithMenu[]"]
+    outputs: ["DishOffering[]"]
+  - verb: Score
+    inputs: ["DishOffering[]"]
+    outputs: ["DishOffering[]/Scored"]
+  - verb: Display
+    inputs: ["DishOffering[]/Scored"]
+tags:
+  booleans: [ true, false ]
+  dates:
+  - canonical: 2001-12-15T02:59:43.1Z
+  - iso8601: 2001-12-14t21:59:43.10-05:00
+  - spaced: 2001-12-14 21:59:43.10 -5
+  - date: 2002-12-14
+  numbers:
+  - int: 12345
+  - negative: -345
+  - floating-point: 345.678
+  - hexidecimal: 0x123abc
+  - exponential: 12.3015e+02
+  - octal: 0o14
+  strings:
+  - unicode: "Sosa did fine.\u263A"
+  - control: "\b1998\t1999\t2000\n"
+  - hex esc: "\x0d\x0a is \r\n"
+  - single: '"Howdy!" he cried.'
+  - quoted: ' # Not a ''comment''.'
+  - tie-fighter: '|\-*-/|'
+  - plain:
+      This unquoted scalar
+      spans many lines.
+
+  - quoted: "So does this
+      quoted scalar.\n"
+  - accomplishment: >
+      Mark set a major league
+      home run record in 1998.
+  - stats: |
+      65 Home Runs
+      0.278 Batting Average
diff --git a/benchmark/output.json b/benchmark/output.json
new file mode 100644
index 0000000..054cef7
--- /dev/null
+++ b/benchmark/output.json
@@ -0,0 +1 @@
+{"verb":"RecommendCafes","recipe":[{"outputs":["Cafe[]"],"verb":"List"},{"outputs":["CafeWithMenu[]"],"verb":"Fetch","inputs":["Cafe[]"]},{"outputs":["DishOffering[]"],"verb":"Flatten","inputs":["CafeWithMenu[]"]},{"outputs":["DishOffering[]/Scored"],"verb":"Score","inputs":["DishOffering[]"]},{"verb":"Display","inputs":["DishOffering[]/Scored"]}],"tags":{"numbers":[{"int":12345},{"negative":-345},{"floating-point":345.678},{"hexidecimal":1194684},{"exponential":1230.15},{"octal":12}],"dates":[{"canonical":"2001-12-15T02:59:43.1Z"},{"iso8601":"2001-12-14t21:59:43.10-05:00"},{"spaced":"2001-12-14 21:59:43.10 -5"},{"date":"2002-12-14"}],"strings":[{"unicode":"Sosa did fine.☺"},{"control":"\b1998\t1999\t2000\n"},{"hex esc":"\r\n is \r\n"},{"single":"\"Howdy!\" he cried."},{"quoted":" # Not a 'comment'."},{"tie-fighter":"|\\-*-/|"},{"plain":"This unquoted scalar spans many lines."},{"quoted":"So does this quoted scalar.\n"},{"accomplishment":"Mark set a major league home run record in 1998.\n"},{"stats":"65 Home Runs\n0.278 Batting Average\n"}],"booleans":[true,false]}}
\ No newline at end of file