Import Dromaeo to WebKit repository.
[WebKit-https.git] / PerformanceTests / resources / runner.js
1
2 var PerfTestRunner = {};
3
4 PerfTestRunner.log = function (text) {
5     if (!document.getElementById("log")) {
6         var pre = document.createElement('pre');
7         pre.id = 'log';
8         document.body.appendChild(pre);
9     }
10     document.getElementById("log").innerHTML += text + "\n";
11     window.scrollTo(0, document.body.height);
12 }
13
14 PerfTestRunner.logInfo = function (text) {
15     if (!window.layoutTestController)
16         this.log(text);
17 }
18
19 PerfTestRunner.loadFile = function (path) {
20     var xhr = new XMLHttpRequest();
21     xhr.open("GET", path, false);
22     xhr.send(null);
23     return xhr.responseText;
24 }
25
26 PerfTestRunner.computeStatistics = function (times) {
27     var data = times.slice();
28
29     // Add values from the smallest to the largest to avoid the loss of significance
30     data.sort();
31
32     var middle = Math.floor(data.length / 2);
33     var result = {
34         min: data[0],
35         max: data[data.length - 1],
36         median: data.length % 2 ? data[middle] : (data[middle - 1] + data[middle]) / 2,
37     };
38
39     // Compute the mean and variance using a numerically stable algorithm.
40     var squareSum = 0;
41     result.mean = data[0];
42     result.sum = data[0];
43     for (var i = 1; i < data.length; ++i) {
44         var x = data[i];
45         var delta = x - result.mean;
46         var sweep = i + 1.0;
47         result.mean += delta / sweep;
48         result.sum += x;
49         squareSum += delta * delta * (i / sweep);
50     }
51     result.variance = squareSum / data.length;
52     result.stdev = Math.sqrt(result.variance);
53
54     return result;
55 }
56
57 PerfTestRunner.logStatistics = function (times) {
58     this.log("");
59     var statistics = this.computeStatistics(times);
60     this.printStatistics(statistics);
61 }
62
63 PerfTestRunner.printStatistics = function (statistics) {
64     this.log("");
65     this.log("avg " + statistics.mean);
66     this.log("median " + statistics.median);
67     this.log("stdev " + statistics.stdev);
68     this.log("min " + statistics.min);
69     this.log("max " + statistics.max);
70 }
71
72 PerfTestRunner.gc = function () {
73     if (window.GCController)
74         window.GCController.collect();
75     else {
76         function gcRec(n) {
77             if (n < 1)
78                 return {};
79             var temp = {i: "ab" + i + (i / 100000)};
80             temp += "foo";
81             gcRec(n-1);
82         }
83         for (var i = 0; i < 1000; i++)
84             gcRec(10);
85     }
86 }
87
88 PerfTestRunner._runLoop = function () {
89     if (this._completedRuns < this._runCount) {
90         this.gc();
91         window.setTimeout(function () { PerfTestRunner._runner(); }, 0);
92     } else {
93         this.logStatistics(this._times);
94         this._doneFunction();
95         if (window.layoutTestController)
96             layoutTestController.notifyDone();
97     }
98 }
99
100 PerfTestRunner._runner = function () {
101     var start = Date.now();
102     var totalTime = 0;
103
104     for (var i = 0; i < this._loopsPerRun; ++i) {
105         var returnValue = this._runFunction.call(window);
106         if (returnValue - 0 === returnValue) {
107             if (returnValue <= 0)
108                 this.log("runFunction returned a non-positive value: " + returnValue);
109             totalTime += returnValue;
110         }
111     }
112
113     // Assume totalTime can never be zero when _runFunction returns a number.
114     var time = totalTime ? totalTime : Date.now() - start;
115
116     this._completedRuns++;
117     if (this._completedRuns <= 0)
118         this.log("Ignoring warm-up run (" + time + ")");
119     else {
120         this._times.push(time);
121         this.log(time);
122     }
123     this._runLoop();
124 }
125
126 PerfTestRunner.run = function (runFunction, loopsPerRun, runCount, doneFunction) {
127     this._runFunction = runFunction;
128     this._loopsPerRun = loopsPerRun || 10;
129     this._runCount = runCount || 20;
130     this._doneFunction = doneFunction || function () {};
131     this._completedRuns = -1;
132     this.customRunFunction = null;
133     this._times = [];
134
135     this.log("Running " + this._runCount + " times");
136     this._runLoop();
137 }
138
139 if (window.layoutTestController) {
140     layoutTestController.waitUntilDone();
141     layoutTestController.dumpAsText();
142 }