Simplify the test harness
[WebKit-https.git] / PerformanceTests / Animometer / resources / debug-runner / animometer.js
1 Utilities.extendObject(window.benchmarkRunnerClient, {
2     testsCount: null,
3     progressBar: null,
4
5     initialize: function(suites, options)
6     {
7         this.testsCount = this.iterationCount * suites.reduce(function (count, suite) { return count + suite.tests.length; }, 0);
8         this.options = options;
9     },
10
11     willStartFirstIteration: function ()
12     {
13         this.results = new ResultsDashboard();
14         this.progressBar = new ProgressBar(document.getElementById("progress-completed"), this.testsCount);
15     },
16
17     didRunTest: function()
18     {
19         this.progressBar.incrementRange();
20     }
21 });
22
23 Utilities.extendObject(window.sectionsManager, {
24     setSectionHeader: function(sectionIdentifier, title)
25     {
26         document.querySelector("#" + sectionIdentifier + " h1").textContent = title;
27     }
28 });
29
30 window.optionsManager =
31 {
32     valueForOption: function(name)
33     {
34         var formElement = document.forms["benchmark-options"].elements[name];
35         if (formElement.type == "checkbox")
36             return formElement.checked;
37         return formElement.value;
38     },
39
40     updateUIFromLocalStorage: function()
41     {
42         var formElements = document.forms["benchmark-options"].elements;
43
44         for (var i = 0; i < formElements.length; ++i) {
45             var formElement = formElements[i];
46             var name = formElement.id || formElement.name;
47             var type = formElement.type;
48
49             var value = localStorage.getItem(name);
50             if (value === null)
51                 continue;
52
53             if (type == "number")
54                 formElements[name].value = +value;
55             else if (type == "checkbox")
56                 formElements[name].checked = value == "true";
57             else if (type == "radio")
58                 formElements[name].value = value;
59         }
60     },
61
62     updateLocalStorageFromUI: function()
63     {
64         var formElements = document.forms["benchmark-options"].elements;
65         var options = {};
66
67         for (var i = 0; i < formElements.length; ++i) {
68             var formElement = formElements[i];
69             var name = formElement.id || formElement.name;
70             var type = formElement.type;
71
72             if (type == "number")
73                 options[name] = formElement.value;
74             else if (type == "checkbox")
75                 options[name] = formElement.checked;
76             else if (type == "radio")
77                 options[name] = formElements[name].value;
78
79             localStorage.setItem(name, options[name]);
80         }
81
82         return options;
83     }
84 }
85
86 window.suitesManager =
87 {
88     _treeElement: function()
89     {
90         return document.querySelector("#suites > .tree");
91     },
92
93     _suitesElements: function()
94     {
95         return document.querySelectorAll("#suites > ul > li");
96     },
97
98     _checkboxElement: function(element)
99     {
100         return element.querySelector("input[type='checkbox']:not(.expand-button)");
101     },
102
103     _editElement: function(element)
104     {
105         return element.querySelector("input[type='number']");
106     },
107
108     _editsElements: function()
109     {
110         return document.querySelectorAll("#suites input[type='number']");
111     },
112
113     _localStorageNameForTest: function(suiteName, testName)
114     {
115         return suiteName + "/" + testName;
116     },
117
118     _updateSuiteCheckboxState: function(suiteCheckbox)
119     {
120         var numberEnabledTests = 0;
121         suiteCheckbox.testsElements.forEach(function(testElement) {
122             var testCheckbox = this._checkboxElement(testElement);
123             if (testCheckbox.checked)
124                 ++numberEnabledTests;
125         }, this);
126         suiteCheckbox.checked = numberEnabledTests > 0;
127         suiteCheckbox.indeterminate = numberEnabledTests > 0 && numberEnabledTests < suiteCheckbox.testsElements.length;
128     },
129
130     _updateStartButtonState: function()
131     {
132         var suitesElements = this._suitesElements();
133         var startButton = document.querySelector("#intro button");
134
135         for (var i = 0; i < suitesElements.length; ++i) {
136             var suiteElement = suitesElements[i];
137             var suiteCheckbox = this._checkboxElement(suiteElement);
138
139             if (suiteCheckbox.checked) {
140                 startButton.disabled = false;
141                 return;
142             }
143         }
144
145         startButton.disabled = true;
146     },
147
148     _onChangeSuiteCheckbox: function(event)
149     {
150         var selected = event.target.checked;
151         event.target.testsElements.forEach(function(testElement) {
152             var testCheckbox = this._checkboxElement(testElement);
153             testCheckbox.checked = selected;
154         }, this);
155         this._updateStartButtonState();
156     },
157
158     _onChangeTestCheckbox: function(event)
159     {
160         var suiteCheckbox = event.target.suiteCheckbox;
161         this._updateSuiteCheckboxState(suiteCheckbox);
162         this._updateStartButtonState();
163     },
164
165     _createSuiteElement: function(treeElement, suite, id)
166     {
167         var suiteElement = DocumentExtension.createElement("li", {}, treeElement);
168         var expand = DocumentExtension.createElement("input", { type: "checkbox",  class: "expand-button", id: id }, suiteElement);
169         var label = DocumentExtension.createElement("label", { class: "tree-label", for: id }, suiteElement);
170
171         var suiteCheckbox = DocumentExtension.createElement("input", { type: "checkbox" }, label);
172         suiteCheckbox.suite = suite;
173         suiteCheckbox.onchange = this._onChangeSuiteCheckbox.bind(this);
174         suiteCheckbox.testsElements = [];
175
176         label.appendChild(document.createTextNode(" " + suite.name));
177         return suiteElement;
178     },
179
180     _createTestElement: function(listElement, test, suiteCheckbox)
181     {
182         var testElement = DocumentExtension.createElement("li", {}, listElement);
183         var span = DocumentExtension.createElement("label", { class: "tree-label" }, testElement);
184
185         var testCheckbox = DocumentExtension.createElement("input", { type: "checkbox" }, span);
186         testCheckbox.test = test;
187         testCheckbox.onchange = this._onChangeTestCheckbox.bind(this);
188         testCheckbox.suiteCheckbox = suiteCheckbox;
189
190         suiteCheckbox.testsElements.push(testElement);
191         span.appendChild(document.createTextNode(" " + test.name));
192         DocumentExtension.createElement("input", { type: "number" }, testElement);
193         return testElement;
194     },
195
196     createElements: function()
197     {
198         var treeElement = this._treeElement();
199
200         Suites.forEach(function(suite, index) {
201             var suiteElement = this._createSuiteElement(treeElement, suite, "suite-" + index);
202             var listElement = DocumentExtension.createElement("ul", {}, suiteElement);
203             var suiteCheckbox = this._checkboxElement(suiteElement);
204
205             suite.tests.forEach(function(test) {
206                 var testElement = this._createTestElement(listElement, test, suiteCheckbox);
207             }, this);
208         }, this);
209     },
210
211     updateEditsElementsState: function()
212     {
213         var editsElements = this._editsElements();
214         var showComplexityInputs = optionsManager.valueForOption("adjustment") == "fixed";
215
216         for (var i = 0; i < editsElements.length; ++i) {
217             var editElement = editsElements[i];
218             if (showComplexityInputs)
219                 editElement.classList.add("selected");
220             else
221                 editElement.classList.remove("selected");
222         }
223     },
224
225     updateDisplay: function()
226     {
227         document.body.className = "display-" + optionsManager.valueForOption("display");
228     },
229
230     updateUIFromLocalStorage: function()
231     {
232         var suitesElements = this._suitesElements();
233
234         for (var i = 0; i < suitesElements.length; ++i) {
235             var suiteElement = suitesElements[i];
236             var suiteCheckbox = this._checkboxElement(suiteElement);
237             var suite = suiteCheckbox.suite;
238
239             suiteCheckbox.testsElements.forEach(function(testElement) {
240                 var testCheckbox = this._checkboxElement(testElement);
241                 var testEdit = this._editElement(testElement);
242                 var test = testCheckbox.test;
243
244                 var str = localStorage.getItem(this._localStorageNameForTest(suite.name, test.name));
245                 if (str === null)
246                     return;
247
248                 var value = JSON.parse(str);
249                 testCheckbox.checked = value.checked;
250                 testEdit.value = value.complexity;
251             }, this);
252
253             this._updateSuiteCheckboxState(suiteCheckbox);
254         }
255
256         this._updateStartButtonState();
257     },
258
259     updateLocalStorageFromUI: function()
260     {
261         var suitesElements = this._suitesElements();
262         var suites = [];
263
264         for (var i = 0; i < suitesElements.length; ++i) {
265             var suiteElement = suitesElements[i];
266             var suiteCheckbox = this._checkboxElement(suiteElement);
267             var suite = suiteCheckbox.suite;
268
269             var tests = [];
270             suiteCheckbox.testsElements.forEach(function(testElement) {
271                 var testCheckbox = this._checkboxElement(testElement);
272                 var testEdit = this._editElement(testElement);
273                 var test = testCheckbox.test;
274
275                 if (testCheckbox.checked) {
276                     test.complexity = testEdit.value;
277                     tests.push(test);
278                 }
279
280                 var value = { checked: testCheckbox.checked, complexity: testEdit.value };
281                 localStorage.setItem(this._localStorageNameForTest(suite.name, test.name), JSON.stringify(value));
282             }, this);
283
284             if (tests.length)
285                 suites.push(new Suite(suiteCheckbox.suite.name, tests));
286         }
287
288         return suites;
289     },
290
291     updateLocalStorageFromJSON: function(iterationResults)
292     {
293         for (var suiteName in iterationResults[Strings.json.results.suites]) {
294             var suiteResults = iterationResults[Strings.json.results.suites][suiteName];
295
296             for (var testName in suiteResults[Strings.json.results.tests]) {
297                 var testResults = suiteResults[Strings.json.results.tests][testName];
298                 var data = testResults[Strings.json.experiments.complexity];
299                 var complexity = Math.round(data[Strings.json.measurements.average]);
300
301                 var value = { checked: true, complexity: complexity };
302                 localStorage.setItem(this._localStorageNameForTest(suiteName, testName), JSON.stringify(value));
303             }
304         }
305     }
306 }
307
308 Utilities.extendObject(window.benchmarkController, {
309     initialize: function()
310     {
311         document.forms["benchmark-options"].addEventListener("change", benchmarkController.onFormChanged, true);
312         optionsManager.updateUIFromLocalStorage();
313         suitesManager.createElements();
314         suitesManager.updateUIFromLocalStorage();
315         suitesManager.updateDisplay();
316         suitesManager.updateEditsElementsState();
317     },
318
319     onFormChanged: function(event)
320     {
321         if (event.target.name == "adjustment") {
322             suitesManager.updateEditsElementsState();
323             return;
324         }
325         if (event.target.name == "display") {
326             suitesManager.updateDisplay();
327         }
328     },
329
330     startBenchmark: function()
331     {
332         var options = optionsManager.updateLocalStorageFromUI();
333         var suites = suitesManager.updateLocalStorageFromUI();
334         this._startBenchmark(suites, options, "running-test");
335     },
336
337     showResults: function()
338     {
339         if (!this.addedKeyEvent) {
340             document.addEventListener("keypress", this.selectResults, false);
341             this.addedKeyEvent = true;
342         }
343
344         sectionsManager.setSectionScore("results", benchmarkRunnerClient.results.score.toFixed(2));
345         var data = benchmarkRunnerClient.results.data[Strings.json.results.iterations];
346         sectionsManager.populateTable("results-header", Headers.testName, data);
347         sectionsManager.populateTable("results-score", Headers.score, data);
348         sectionsManager.populateTable("results-data", Headers.details, data);
349         document.querySelector("#results-json textarea").textContent = JSON.stringify(benchmarkRunnerClient.results.data, function(key, value) {
350             if (typeof value == "number")
351                 return value.toFixed(2);
352             return value;
353         });
354         sectionsManager.showSection("results", true);
355
356         suitesManager.updateLocalStorageFromJSON(data[0]);
357     },
358
359     showTestGraph: function(testName, score, mean, axes, samples, samplingTimeOffset)
360     {
361         sectionsManager.setSectionHeader("test-graph", testName);
362         sectionsManager.setSectionScore("test-graph", score, mean);
363         sectionsManager.showSection("test-graph", true);
364         graph("#test-graph-data", new Insets(10, 20, 30, 40), axes, samples, samplingTimeOffset);
365     }
366 });
367
368 window.addEventListener("load", benchmarkController.initialize);