(#6143) - perf tests: use marky, measure median, add iterations param
diff --git a/TESTING.md b/TESTING.md
index ca1589f..95cc950 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -141,6 +141,10 @@
 
     PERF=1 ADAPTER=websql npm test
 
+You can also override the default number of iterations:
+
+    PERF=1 ITERATIONS=10 npm t
+
 ### Performance tests in the browser
 
 When you run `npm run dev`, performance tests are available at:
@@ -160,6 +164,10 @@
     http://127.0.0.1:8000/tests/performance/index.html?grep=basics
     http://127.0.0.1:8000/tests/performance/index.html?grep=basic-inserts
 
+You can also override the default number of iterations using `iterations=`:
+
+    http://127.0.0.1:8000/tests/performance/index.html?grep=basic-insert&interations=10
+
 ### Ad-hoc tests
 
 There's a WebSQL storage quota test available in:
diff --git a/package.json b/package.json
index f22fd33..a294dc5 100644
--- a/package.json
+++ b/package.json
@@ -86,6 +86,8 @@
     "lodash.debounce": "4.0.8",
     "lodash.flatten": "4.4.0",
     "lodash.uniq": "4.5.0",
+    "marky": "1.1.2",
+    "median": "0.0.2",
     "mkdirp": "0.5.1",
     "mocha": "3.2.0",
     "mockery": "2.0.0",
diff --git a/tests/performance/markMeasure.js b/tests/performance/markMeasure.js
deleted file mode 100644
index 842aa2c..0000000
--- a/tests/performance/markMeasure.js
+++ /dev/null
@@ -1,11 +0,0 @@
-function noop() {}
-
-if (typeof performance !== 'undefined' &&
-    performance.mark && performance.measure) {
-  module.exports = performance;
-} else {
-  module.exports = {
-    mark: noop,
-    measure: noop
-  };
-}
\ No newline at end of file
diff --git a/tests/performance/perf.reporter.js b/tests/performance/perf.reporter.js
index 9d0e8af..ae629a3 100644
--- a/tests/performance/perf.reporter.js
+++ b/tests/performance/perf.reporter.js
@@ -2,9 +2,17 @@
 var isNode = process && !process.browser;
 var UAParser = require('ua-parser-js');
 var ua = !isNode && new UAParser(navigator.userAgent);
-var now = isNode ? Date.now.bind(Date) : performance.now.bind(performance);
+var marky = require('marky');
+var median = require('median');
 global.results = {};
 
+// fix for Firefox max timing entries capped to 150:
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1331135
+/* global performance */
+if (typeof performance !== 'undefined' && performance.setResourceTimingBufferSize) {
+  performance.setResourceTimingBufferSize(100000);
+}
+
 var pre = !isNode && global.document.getElementById('output');
 
 function log(msg) {
@@ -21,21 +29,29 @@
   log('Starting suite: ' + suiteName + '\n\n');
 };
 
-exports.start = function (testCase) {
+exports.start = function (testCase, iter) {
   var key = testCase.name;
   log('Starting test: ' + key + ' with ' + testCase.assertions +
-    ' assertions and ' + testCase.iterations + ' iterations... ');
+    ' assertions and ' + iter + ' iterations... ');
   global.results[key] = {
-    start: now()
+    iterations: []
   };
 };
 
 exports.end = function (testCase) {
   var key = testCase.name;
   var obj = global.results[key];
-  obj.end = now();
-  obj.duration = obj.end - obj.start;
-  log('done in ' + obj.duration + 'ms\n');
+  obj.median = median(obj.iterations);
+  log('median: ' + obj.median + ' ms\n');
+};
+
+exports.startIteration = function (testCase) {
+  marky.mark(testCase.name);
+};
+
+exports.endIteration = function (testCase) {
+  var entry = marky.stop(testCase.name);
+  global.results[testCase.name].iterations.push(entry.duration);
 };
 
 exports.complete = function () {
diff --git a/tests/performance/utils.js b/tests/performance/utils.js
index 0a3e9dd..481777c 100644
--- a/tests/performance/utils.js
+++ b/tests/performance/utils.js
@@ -6,14 +6,17 @@
 var Promise = require('lie');
 var nextTick = (typeof process === 'undefined' || process.browser) ?
   setTimeout : process.nextTick;
-var markMeasure = require('./markMeasure');
 
 var grep;
+var iterations;
 if (global.window && global.window.location && global.window.location.search) {
   grep = global.window.location.search.match(/[&?]grep=([^&]+)/);
   grep = grep && grep[1];
+  iterations = global.window.location.search.match(/[&?]iterations=([^&]+)/);
+  iterations = iterations && parseInt(iterations[1], 10);
 } else if (process && process.env) {
   grep = process.env.GREP;
+  iterations = process.env.ITERATIONS && parseInt(process.env.ITERATIONS, 10);
 }
 
 var levelAdapter = typeof process !== 'undefined' && process.env &&
@@ -27,7 +30,10 @@
       return;
     }
 
-    if (testCase.iterations === 0) {
+    var iter = typeof iterations === 'number' ? iterations :
+      testCase.iterations;
+
+    if (iter === 0) {
       return;
     }
 
@@ -52,7 +58,7 @@
           if (i === 0) {
             reporter.startSuite(suiteName);
           }
-          reporter.start(testCase);
+          reporter.start(testCase, iter);
           t.end();
         });
       });
@@ -62,7 +68,7 @@
         var num = 0;
         function next() {
           nextTick(function () {
-            markMeasure.mark('start_' + testName);
+            reporter.startIteration(testCase);
             testCase.test(db, num, setupObj, after);
           });
         }
@@ -71,10 +77,9 @@
             t.error(err);
             reporter.log(testName + ' errored: ' + err.message + '\n');
           } else {
-            markMeasure.mark('end_' + testName);
-            markMeasure.measure(testName, 'start_' + testName, 'end_' + testName);
+            reporter.endIteration(testCase);
           }
-          if (++num < testCase.iterations) {
+          if (++num < iter) {
             next();
           } else {
             t.ok(testName + ' completed');