blob: 113590b349d4863ae1bb5baa666384359c573f91 [file] [log] [blame]
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
"use strict";
class Results {
constructor(benchmark)
{
this._benchmark = benchmark;
for (let subResult of Results.subResults)
this[subResult] = new Stats(benchmark.cells[subResult], subResult);
}
get benchmark() { return this._benchmark; }
reset()
{
for (let subResult of Results.subResults)
this[subResult].reset();
}
reportRunning()
{
if (isInBrowser)
this._benchmark.cells.message.innerHTML = "Running...";
}
reportDone()
{
if (isInBrowser)
this._benchmark.cells.message.innerHTML = "";
}
reportResult(times)
{
function averageAbovePercentile(numbers, percentile) {
// Don't change the original array.
numbers = numbers.slice();
// Sort in ascending order.
numbers.sort(function(a, b) { return a - b; });
// Now the elements we want are at the end. Keep removing them until the array size shrinks too much.
// Examples assuming percentile = 99:
//
// - numbers.length starts at 100: we will remove just the worst entry and then not remove anymore,
// since then numbers.length / originalLength = 0.99.
//
// - numbers.length starts at 1000: we will remove the ten worst.
//
// - numbers.length starts at 10: we will remove just the worst.
var numbersWeWant = [];
var originalLength = numbers.length;
while (numbers.length / originalLength > percentile / 100)
numbersWeWant.push(numbers.pop());
var sum = 0;
for (var i = 0; i < numbersWeWant.length; ++i)
sum += numbersWeWant[i];
var result = sum / numbersWeWant.length;
// Do a sanity check.
if (numbers.length && result < numbers[numbers.length - 1]) {
throw "Sanity check fail: the worst case result is " + result +
" but we didn't take into account " + numbers;
}
return result;
}
this.firstIteration.add(times[0]);
let steadyTimes = times.slice(1);
this.averageWorstCase.add(averageAbovePercentile(steadyTimes, 98));
this.steadyState.add(steadyTimes.reduce((previous, current) => previous + current));
this.reportDone();
}
reportError(message, url, lineNumber)
{
for (let subResult of Results.subResults)
this[subResult].reportResult(Stats.error);
if (isInBrowser)
this._benchmark.cells.message.innerHTML = url + ":" + lineNumber + ": " + message;
}
}
Results.subResults = ["firstIteration", "averageWorstCase", "steadyState"];