ca9cbdec0f48197bec82fb3720bc21a6ccad1ecb
[WebKit-https.git] / PerformanceTests / ARES-6 / driver.js
1 /*
2  * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 "use strict";
26
27 class Driver {
28     constructor(statusCell, triggerCell, triggerLink, magicCell, summaryCell, key)
29     {
30         this._benchmarks = new Map();
31         this._statusCell = statusCell;
32         this._triggerCell = triggerCell;
33         this._triggerLink = triggerLink;
34         this._magicCell = magicCell;
35         this._summary = new Stats(summaryCell, "summary");
36         this._key = key;
37         this._hadErrors = false;
38         if (isInBrowser)
39             window[key] = this;
40     }
41     
42     addBenchmark(benchmark)
43     {
44         this._benchmarks.set(benchmark, new Results(benchmark));
45     }
46     
47     readyTrigger() 
48     {
49         if (isInBrowser) {
50             this._triggerCell.addEventListener('click', this._triggerLink);
51             this._triggerCell.classList.add('ready');
52         }
53     }
54     
55     disableTrigger() 
56     {
57         if (isInBrowser) {
58             this._triggerCell.removeEventListener('click', this._triggerLink);
59             this._triggerCell.classList.remove('ready');
60         }
61     }
62     
63     start(numIterations)
64     {
65         this.disableTrigger();
66         this._updateIterations();
67
68         this._summary.reset();
69         for (let [benchmark, results] of this._benchmarks)
70             results.reset();
71         this._isRunning = true;
72         this._numIterations = numIterations;
73         this._iterator = null;
74         this._iterate();
75     }
76     
77     reportResult(...args)
78     {
79         this._benchmarks.get(this._benchmark).reportResult(...args);
80         this._recomputeSummary();
81         this._iterate();
82     }
83     
84     reportError(...args)
85     {
86         this._benchmarks.get(this._benchmark).reportError(...args);
87         this._recomputeSummary();
88         this._hadErrors = true;
89         this._iterate();
90     }
91     
92     _recomputeSummary()
93     {
94         class Geomean {
95             constructor()
96             {
97                 this._count = 0;
98                 this._sum = 0;
99             }
100             
101             add(value)
102             {
103                 this._count++;
104                 this._sum += Math.log(value);
105             }
106             
107             get result()
108             {
109                 return Math.exp(this._sum * (1 / this._count));
110             }
111         }
112         
113         let statses = [];
114         for (let results of this._benchmarks.values()) {
115             for (let subResult of Results.subResults)
116                 statses.push(results[subResult]);
117         }
118
119         let numIterations = Math.min(...statses.map(stats => stats.numIterations));
120         let data = new Array(numIterations);
121         for (let i = 0; i < data.length; ++i)
122             data[i] = new Geomean();
123         
124         for (let stats of statses) {
125             for (let i = 0; i < data.length; ++i)
126                 data[i].add(stats.valueForIteration(i));
127         }
128         
129         let geomeans = data.map(geomean => geomean.result);
130         
131         this._summary.reset(...geomeans);
132     }
133     
134     _iterate()
135     {
136         this._benchmark = this._iterator ? this._iterator.next().value : null;
137         if (!this._benchmark) {
138             if (!this._numIterations) {
139                 if (isInBrowser) {
140                     this._statusCell.innerHTML =
141                         (this._hadErrors ? "Failures encountered!" : "Restart");
142                     this.readyTrigger();
143                 } else
144                     print(this._hadErrors ? "Failures encountered!" : "Success! Benchmark is now finished.");
145                 return;
146             }
147             this._numIterations--;
148             this._updateIterations();
149             this._iterator = this._benchmarks.keys();
150             this._benchmark = this._iterator.next().value;
151         }
152         
153         this._benchmarks.get(this._benchmark).reportRunning();
154         
155         let benchmark = this._benchmark;
156         if (isInBrowser) {
157             window.setTimeout(() => {
158                 if (!this._isRunning)
159                     return;
160                 
161                 this._magicCell.contentDocument.body.textContent = "";
162                 this._magicCell.contentDocument.body.innerHTML = "<iframe id=\"magicFrame\" frameborder=\"0\">";
163                 
164                 let magicFrame = this._magicCell.contentDocument.getElementById("magicFrame");
165                 magicFrame.contentDocument.open();
166                 magicFrame.contentDocument.write(
167                     `<!DOCTYPE html><head><title>benchmark payload</title></head><body><script>` +
168                     `window.onerror = top.${this._key}.reportError;\n` +
169                     `function reportResult()\n` +
170                     `{\n` +
171                     `    var driver = top.${this._key};\n` +
172                     `    driver.reportResult.apply(driver, arguments);\n` +
173                     `}\n` +
174                     `</script>\n` +
175                     `${this._benchmark.code}</body></html>`);
176             }, 100);
177         } else {
178             Promise.resolve(20).then(() => {
179                 if (!this._isRunning)
180                     return;
181                 
182                 try {
183                     print(`Running... ${this._benchmark.name} ( ${this._numIterations + 1}  to go)`);
184                     benchmark.run();
185                     print("\n");
186                 } catch(e) {
187                     print(e);
188                     print(e.stack);
189                 }
190             });
191         }
192     }
193     
194     _updateIterations()
195     {
196         if (isInBrowser)
197             this._statusCell.innerHTML = "Running... " + (this._numIterations + 1) + " to go";
198     }
199 }