Add AsyncBenchmarkBase.

The async benchmark harness accommodates tests that require async
setup/teardown/run implementations.
diff --git a/lib/benchmark_harness.dart b/lib/benchmark_harness.dart
index 46153a0..2809777 100644
--- a/lib/benchmark_harness.dart
+++ b/lib/benchmark_harness.dart
@@ -4,5 +4,8 @@
 
 library benchmark_harness;
 
+import 'dart:async';
+
 part 'src/benchmark_base.dart';
+part 'src/async_benchmark_base.dart';
 part 'src/score_emitter.dart';
diff --git a/lib/src/async_benchmark_base.dart b/lib/src/async_benchmark_base.dart
new file mode 100644
index 0000000..8a020f2
--- /dev/null
+++ b/lib/src/async_benchmark_base.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2014, 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.
+
+part of benchmark_harness;
+
+class AsyncBenchmarkBase {
+  final String name;
+  final ScoreEmitter emitter;
+
+  /// Empty constructor.
+  const AsyncBenchmarkBase(this.name, {this.emitter = const PrintEmitter()});
+
+  /// The benchmark code.
+  ///
+  /// This function is not used, if both [warmup] and [exercise] are
+  /// overwritten.
+  Future<void> run() async {}
+
+  /// Runs a short version of the benchmark. By default invokes [run] once.
+  Future<void> warmup() async {
+    await run();
+  }
+
+  /// Exercises the benchmark. By default invokes [run] once.
+  Future<void> exercise() async {
+    await run();
+  }
+
+  /// Not measured setup code executed prior to the benchmark runs.
+  Future<void> setup() async {}
+
+  /// Not measures teardown code executed after the benchark runs.
+  Future<void> teardown() async {}
+
+  /// Measures the score for this benchmark by executing it repeately until
+  /// time minimum has been reached.
+  static Future<double> measureFor(
+      Future<void> Function() f, int minimumMillis) async {
+    final minimumMicros = minimumMillis * 1000;
+    final watch = Stopwatch()..start();
+    var iter = 0;
+    var elapsed = 0;
+    while (elapsed < minimumMicros) {
+      await f();
+      elapsed = watch.elapsedMicroseconds;
+      iter++;
+    }
+    return elapsed / iter;
+  }
+
+  /// Measures the score for the benchmark and returns it.
+  Future<double> measure() async {
+    await setup();
+    try {
+      // Warmup for at least 100ms. Discard result.
+      await measureFor(warmup, 100);
+      // Run the benchmark for at least 2000ms.
+      return await measureFor(exercise, 2000);
+    } finally {
+      await teardown();
+    }
+  }
+
+  /// Run the benchmark and report results on the [emitter].
+  Future<void> report() async {
+    emitter.emit(name, await measure());
+  }
+}
diff --git a/test/benchmark_harness_test.dart b/test/benchmark_harness_test.dart
index bc85579..eaf0893 100644
--- a/test/benchmark_harness_test.dart
+++ b/test/benchmark_harness_test.dart
@@ -4,14 +4,22 @@
 
 library benchmark_harness_test;
 
+import 'dart:async';
+
 import 'package:benchmark_harness/benchmark_harness.dart';
 import 'package:test/test.dart';
 
 void main() {
   group('benchmark_harness', () {
     test('run is called', () {
-      var benchmark = MockBenchmark();
-      var micros = benchmark.measure();
+      final benchmark = MockBenchmark();
+      final micros = benchmark.measure();
+      expect(micros, isPositive);
+      expect(benchmark.runCount, isPositive);
+    });
+    test('async run is awaited', () async {
+      final benchmark = MockAsyncBenchmark();
+      final micros = await benchmark.measure();
       expect(micros, isPositive);
       expect(benchmark.runCount, isPositive);
     });
@@ -28,3 +36,14 @@
     runCount++;
   }
 }
+
+class MockAsyncBenchmark extends AsyncBenchmarkBase {
+  int runCount = 0;
+  MockAsyncBenchmark() : super('mock benchmark');
+
+  @override
+  Future<void> run() async {
+    await Future<void>.delayed(Duration.zero);
+    runCount++;
+  }
+}