b875b6b9b97ba48405ae630cc5f30f1cb34e1618
[WebKit-https.git] / PerformanceTests / Animometer / runner / resources / animometer.js
1 window.benchmarkRunnerClient = {
2     iterationCount: 1,
3     testsCount: null,
4     progressBar: null,
5     recordTable: null,
6     options: null,
7     score: 0,
8     _resultsDashboard: null,
9     _resultsTable: null,
10     
11     initialize: function(suites, options)
12     {
13         this.testsCount = this.iterationCount * suites.reduce(function (count, suite) { return count + suite.tests.length; }, 0);
14         this.options = options;
15     },
16
17     willAddTestFrame: function (frame)
18     {
19         var main = document.querySelector("main");
20         var style = getComputedStyle(main);
21         frame.style.left = main.offsetLeft + parseInt(style.borderLeftWidth) + parseInt(style.paddingLeft) + "px";
22         frame.style.top = main.offsetTop + parseInt(style.borderTopWidth) + parseInt(style.paddingTop) + "px";
23     },
24     
25     didRunTest: function ()
26     {
27         this.progressBar.incRange();
28     },
29     
30     willStartFirstIteration: function ()
31     {
32         this._resultsDashboard = new ResultsDashboard();
33         this._resultsTable = new ResultsTable(document.querySelector("section#results > data > table"), Headers);
34         
35         this.progressBar = new ProgressBar(document.getElementById("progress-completed"), this.testsCount);
36         this.recordTable = new ResultsTable(document.querySelector("section#running > #record > table"), Headers);
37     },
38     
39     didRunSuites: function (suitesSamplers)
40     {
41         this._resultsDashboard.push(suitesSamplers);
42     },
43     
44     didFinishLastIteration: function ()
45     {
46         var json = this._resultsDashboard.toJSON(true, true);
47         this.score = json[Strings["JSON_SCORE"]];
48         this._resultsTable.showIterations(json[Strings["JSON_RESULTS"][0]], this.options);
49         sectionsManager.showJSON("json", json[Strings["JSON_RESULTS"][0]][0]);
50         suitesManager.updateLocalStorageFromJSON(json[Strings["JSON_RESULTS"][0]][0]);
51         benchmarkController.showResults();
52     }
53 }
54
55 window.sectionsManager =
56 {
57     _sectionHeaderH1Element: function(sectionIdentifier)
58     {
59         return document.querySelector("#" + sectionIdentifier + " > header > h1");
60     },
61     
62     _sectionDataDivElement: function(sectionIdentifier)
63     {
64         return document.querySelector("#" + sectionIdentifier + " >  data > div");
65     },
66     
67     showScore: function(sectionIdentifier, title)
68     {
69         var element = this._sectionHeaderH1Element(sectionIdentifier);
70         element.textContent = title + ":";
71
72         var score = benchmarkRunnerClient.score.toFixed(2);
73         element.textContent += " [Score = " + score + "]";
74     },
75     
76     showTestName: function(sectionIdentifier, title, testName)
77     {
78         var element = this._sectionHeaderH1Element(sectionIdentifier);
79         element.textContent = title + ":";
80
81         if (!testName.length)
82             return;
83             
84         element.textContent += " [test = " + testName + "]";
85     },
86     
87     showJSON: function(sectionIdentifier, json)
88     {
89         var element = this._sectionDataDivElement(sectionIdentifier);
90         element.textContent = JSON.stringify(json, function(key, value) { 
91             if (typeof value == "number")
92                 return value.toFixed(2);
93             return value;
94         }, 4);
95     },
96     
97     showSection: function(sectionIdentifier, pushState)
98     {
99         var currentSectionElement = document.querySelector("section.selected");
100         console.assert(currentSectionElement);
101
102         var newSectionElement = document.getElementById(sectionIdentifier);
103         console.assert(newSectionElement);
104
105         currentSectionElement.classList.remove("selected");
106         newSectionElement.classList.add("selected");
107
108         if (pushState)
109             history.pushState({section: sectionIdentifier}, document.title);
110     },
111
112     setupSectionStyle: function()
113     {
114         if (screen.width >= 1800 && screen.height >= 1000)
115             DocumentExtension.insertCssRuleAfter(" section { width: 1600px; height: 800px; }", "section");
116         else
117             DocumentExtension.insertCssRuleAfter(" section { width: 800px; height: 600px; }", "section");
118     },
119     
120     setupRunningSectionStyle: function(options)
121     {
122         if (!options["show-running-results"])
123             document.getElementById("record").style.display = "none";
124
125         if (options["normalize-for-device-scale-factor"] && window.devicePixelRatio != 1) {
126             var percentage = window.devicePixelRatio * 100;
127             var rule = "section#running > #running-test > iframe";
128             var newRule = rule;
129             newRule += " { ";
130             newRule += "width: " + percentage + "%; ";
131             newRule += "height: " + percentage + "%; ";
132             newRule += "transform: scale(" + 100 / percentage + ") translate(" + (100 - percentage) / 2 + "%," + (100 - percentage) / 2 + "%);";
133             newRule += " }";
134             DocumentExtension.insertCssRuleAfter(newRule, rule);
135         }
136     }
137 }
138
139 window.optionsManager =
140 {
141     _optionsElements : function()
142     {
143         return document.querySelectorAll("section#home > options input");;
144     },
145     
146     _adaptiveTestElement: function()
147     {
148         return document.querySelector("section#home > options #adaptive-test");;
149     },
150     
151     updateUIFromLocalStorage: function()
152     {
153         var optionsElements = this._optionsElements();
154
155         for (var i = 0; i < optionsElements.length; ++i) {
156             var optionElement = optionsElements[i];
157             
158             var value = localStorage.getItem(optionElement.id);
159             if (value === null)
160                 continue;
161
162             if (optionElement.getAttribute("type") == "number")
163                 optionElement.value = +value;
164             else if (optionElement.getAttribute("type") == "checkbox")
165                 optionElement.checked = value == "true";
166         }
167     },
168
169     updateLocalStorageFromUI: function()
170     {
171         var optionsElements = this._optionsElements();
172         var options = {};        
173
174         for (var i = 0; i < optionsElements.length; ++i) {
175             var optionElement = optionsElements[i];
176         
177             if (optionElement.getAttribute("type") == "number")
178                 options[optionElement.id] = optionElement.value;
179             else if (optionElement.getAttribute("type") == "checkbox")
180                 options[optionElement.id] = optionElement.checked;
181     
182             localStorage.setItem(optionElement.id, options[optionElement.id]);
183         }
184         
185         return options;
186     }
187 }
188
189 window.suitesManager =
190 {
191     _treeElement : function()
192     {
193         return document.querySelector("suites > .tree");
194     },
195     
196     _suitesElements : function()
197     {
198         return document.querySelectorAll("#home > suites > ul > li");
199     },
200     
201     _checkboxElement: function(element)
202     {
203         return element.querySelector("input[type='checkbox']:not(.expand-button)");
204     },
205
206     _editElement: function(element)
207     {
208         return element.querySelector("input[type='number']");
209     },
210
211     _editsElements: function()
212     {
213         return document.querySelectorAll("section#home > suites input[type='number']");
214     },
215         
216     _localStorageNameForTest: function(suiteName, testName)
217     {
218         return suiteName + "/" + testName;
219     },
220
221     _updateSuiteCheckboxState: function(suiteCheckbox)
222     {
223         var numberEnabledTests = 0;
224         suiteCheckbox.testsElements.forEach(function(testElement) {
225             var testCheckbox = this._checkboxElement(testElement);
226             if (testCheckbox.checked)
227                 ++numberEnabledTests;
228         }, this);
229         suiteCheckbox.checked = numberEnabledTests > 0;
230         suiteCheckbox.indeterminate = numberEnabledTests > 0 && numberEnabledTests < suiteCheckbox.testsElements.length;
231     },
232
233     _updateStartButtonState: function()
234     {
235         var suitesElements = this._suitesElements();
236         var startButton = document.querySelector("#home > footer > button");
237         
238         for (var i = 0; i < suitesElements.length; ++i) {
239             var suiteElement = suitesElements[i];
240             var suiteCheckbox = this._checkboxElement(suiteElement);
241             
242             if (suiteCheckbox.checked) {
243                 startButton.disabled = false;
244                 return;
245             }
246         }
247     
248         startButton.disabled = true;
249     },
250
251     _onChangeSuiteCheckbox: function(event)
252     {
253         var selected = event.target.checked;
254         event.target.testsElements.forEach(function(testElement) {
255             var testCheckbox = this._checkboxElement(testElement);
256             testCheckbox.checked = selected;        
257         }, this);
258         this._updateStartButtonState();
259     },
260
261     _onChangeTestCheckbox: function(event)
262     {
263         var suiteCheckbox = event.target.suiteCheckbox;
264         this._updateSuiteCheckboxState(suiteCheckbox);
265         this._updateStartButtonState();
266     },
267
268     _createSuiteElement: function(treeElement, suite, id)
269     {
270         var suiteElement = DocumentExtension.createElement("li", {}, treeElement);
271         var expand = DocumentExtension.createElement("input", { type: "checkbox",  class: "expand-button", id: id }, suiteElement);
272         var label = DocumentExtension.createElement("label", { class: "tree-label", for: id }, suiteElement);
273
274         var suiteCheckbox = DocumentExtension.createElement("input", { type: "checkbox" }, label);
275         suiteCheckbox.suite = suite;
276         suiteCheckbox.onchange = this._onChangeSuiteCheckbox.bind(this);
277         suiteCheckbox.testsElements = [];
278
279         label.appendChild(document.createTextNode(" " + suite.name));
280         return suiteElement;
281     },
282
283     _createTestElement: function(listElement, test, suiteCheckbox)
284     {
285         var testElement = DocumentExtension.createElement("li", {}, listElement);
286         var span = DocumentExtension.createElement("span", { class: "tree-label" }, testElement);
287
288         var testCheckbox = DocumentExtension.createElement("input", { type: "checkbox" }, span);
289         testCheckbox.test = test;
290         testCheckbox.onchange = this._onChangeTestCheckbox.bind(this);
291         testCheckbox.suiteCheckbox = suiteCheckbox;
292
293         suiteCheckbox.testsElements.push(testElement);
294         span.appendChild(document.createTextNode(" " + test.name));
295         DocumentExtension.createElement("input", { type: "number" }, testElement);
296         return testElement;
297     },
298
299     createElements: function()
300     {
301         var treeElement = this._treeElement();
302
303         Suites.forEach(function(suite, index) {
304             var suiteElement = this._createSuiteElement(treeElement, suite, "suite-" + index);
305             var listElement = DocumentExtension.createElement("ul", {}, suiteElement);
306             var suiteCheckbox = this._checkboxElement(suiteElement);
307
308             suite.tests.forEach(function(test) {
309                 var testElement = this._createTestElement(listElement, test, suiteCheckbox);
310             }, this);
311         }, this);
312     },
313     
314     updateEditsElementsState: function()
315     {
316         var editsElements = this._editsElements();
317         var show = !optionsManager._adaptiveTestElement().checked;
318
319         for (var i = 0; i < editsElements.length; ++i) {
320             var editElement = editsElements[i];
321             if (show)
322                 editElement.classList.add("selected");
323             else
324                 editElement.classList.remove("selected");
325         }
326     },
327     
328     updateUIFromLocalStorage: function()
329     {
330         var suitesElements = this._suitesElements();
331         
332         for (var i = 0; i < suitesElements.length; ++i) {
333             var suiteElement = suitesElements[i];
334             var suiteCheckbox = this._checkboxElement(suiteElement);
335             var suite = suiteCheckbox.suite;
336             
337             suiteCheckbox.testsElements.forEach(function(testElement) {
338                 var testCheckbox = this._checkboxElement(testElement);
339                 var testEdit = this._editElement(testElement);
340                 var test = testCheckbox.test;
341                 
342                 var str = localStorage.getItem(this._localStorageNameForTest(suite.name, test.name));
343                 if (str === null)
344                     return;
345
346                 var value = JSON.parse(str);
347                 testCheckbox.checked = value.checked;
348                 testEdit.value = value.complexity;
349             }, this);
350
351             this._updateSuiteCheckboxState(suiteCheckbox);
352         }
353         
354         this._updateStartButtonState();
355     },
356
357     updateLocalStorageFromUI: function()
358     {
359         var suitesElements = this._suitesElements();
360         var suites = [];
361         
362         for (var i = 0; i < suitesElements.length; ++i) {
363             var suiteElement = suitesElements[i];
364             var suiteCheckbox = this._checkboxElement(suiteElement);
365             var suite = suiteCheckbox.suite;
366
367             var tests = [];
368             suiteCheckbox.testsElements.forEach(function(testElement) {
369                 var testCheckbox = this._checkboxElement(testElement);
370                 var testEdit = this._editElement(testElement);
371                 var test = testCheckbox.test;
372                 
373                 if (testCheckbox.checked) {
374                     test.complexity = testEdit.value;
375                     tests.push(test);
376                 }
377
378                 var value = { checked: testCheckbox.checked, complexity: testEdit.value }; 
379                 localStorage.setItem(this._localStorageNameForTest(suite.name, test.name), JSON.stringify(value));
380             }, this);
381
382             if (tests.length)
383                 suites.push(new Suite(suiteCheckbox.suite.name, tests));
384         }
385
386         return suites;
387     },
388     
389     updateLocalStorageFromJSON: function(iterationResults)
390     {
391         for (var suiteName in iterationResults[Strings["JSON_RESULTS"][1]]) {
392             var suiteResults = iterationResults[Strings["JSON_RESULTS"][1]][suiteName];
393
394             for (var testName in suiteResults[Strings["JSON_RESULTS"][2]]) {
395                 var testResults = suiteResults[Strings["JSON_RESULTS"][2]][testName];
396                 var data = testResults[Strings["JSON_EXPERIMENTS"][0]]
397                 var complexity = Math.round(data[Strings["JSON_MEASUREMENTS"][0]]);
398
399                 var value = { checked: true, complexity: complexity };
400                 localStorage.setItem(this._localStorageNameForTest(suiteName, testName), JSON.stringify(value));
401             }
402         }
403     }
404 }
405
406 window.benchmarkController =
407 {
408     initialize: function()
409     {
410         sectionsManager.setupSectionStyle();
411         optionsManager.updateUIFromLocalStorage();
412         suitesManager.createElements();
413         suitesManager.updateUIFromLocalStorage();
414         suitesManager.updateEditsElementsState();
415     },
416
417     onChangeAdaptiveTestCheckbox: function()
418     {
419         suitesManager.updateEditsElementsState();
420     },
421     
422     _runBenchmark: function(suites, options)
423     {
424         benchmarkRunnerClient.initialize(suites, options);
425         var frameContainer = document.querySelector("#running > #running-test");
426         var runner = new BenchmarkRunner(suites, frameContainer || document.body, benchmarkRunnerClient);
427         runner.runMultipleIterations();
428     },
429
430     startTest: function()
431     {
432         var options = optionsManager.updateLocalStorageFromUI();
433         var suites = suitesManager.updateLocalStorageFromUI();
434         sectionsManager.setupRunningSectionStyle(options);
435         this._runBenchmark(suites, options);
436         sectionsManager.showSection("running");
437     },
438     
439     showResults: function()
440     {
441         sectionsManager.showScore("results", Strings["TEXT_RESULTS"][0]);
442         sectionsManager.showSection("results", true);
443     },
444     
445     showJson: function()
446     {
447         sectionsManager.showScore("json", Strings["TEXT_RESULTS"][0]);
448         sectionsManager.showSection("json", true);
449     },
450     
451     showTestGraph: function(testName, axes, samples, samplingTimeOffset)
452     {
453         sectionsManager.showTestName("test-graph", Strings["TEXT_RESULTS"][1], testName);
454         sectionsManager.showSection("test-graph", true);
455         graph("section#test-graph > data", new Insets(20, 50, 20, 50), axes, samples, samplingTimeOffset);
456     },
457
458     showTestJSON: function(testName, json)
459     {
460         sectionsManager.showTestName("test-json", Strings["TEXT_RESULTS"][1], testName);
461         sectionsManager.showJSON("test-json", json);
462         sectionsManager.showSection("test-json", true);
463     }
464 }
465
466 document.addEventListener("DOMContentLoaded", benchmarkController.initialize());