Add an option to select the results form the graphics benchmark
[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.iterations], this.options);
49         sectionsManager.showJSON("json", json[Strings.json.results.iterations][0]);
50         suitesManager.updateLocalStorageFromJSON(json[Strings.json.results.iterations][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     _sectionDataElement: function(sectionIdentifier)
63     {
64         return document.querySelector("#" + sectionIdentifier + " > data");
65     },
66     
67     _sectionDataDivElement: function(sectionIdentifier)
68     {
69         return document.querySelector("#" + sectionIdentifier + " >  data > div");
70     },
71     
72     showScore: function(sectionIdentifier, title)
73     {
74         var element = this._sectionHeaderH1Element(sectionIdentifier);
75         element.textContent = title + ":";
76
77         var score = benchmarkRunnerClient.score.toFixed(2);
78         element.textContent += " [" + Strings.text.score + " = " + score + "]";
79     },
80     
81     showTestName: function(sectionIdentifier, title, testName)
82     {
83         var element = this._sectionHeaderH1Element(sectionIdentifier);
84         element.textContent = title + ":";
85
86         if (!testName.length)
87             return;
88             
89         element.textContent += " [" + Strings.text.testName + " = " + testName + "]";
90     },
91     
92     showJSON: function(sectionIdentifier, json)
93     {
94         var element = this._sectionDataDivElement(sectionIdentifier);
95         element.textContent = JSON.stringify(json, function(key, value) { 
96             if (typeof value == "number")
97                 return value.toFixed(2);
98             return value;
99         }, 4);
100     },
101     
102     selectData: function(sectionIdentifier)
103     {
104         window.getSelection().removeAllRanges();
105         var element = this._sectionDataElement(sectionIdentifier);
106         var range = document.createRange();
107         range.selectNode(element);
108         window.getSelection().addRange(range);  
109     },
110     
111     selectDataContents: function(sectionIdentifier)
112     {
113         window.getSelection().removeAllRanges();
114         var element = this._sectionDataDivElement(sectionIdentifier);
115         var range = document.createRange();
116         range.selectNodeContents(element);
117         window.getSelection().addRange(range);
118     },
119         
120     showSection: function(sectionIdentifier, pushState)
121     {
122         var currentSectionElement = document.querySelector("section.selected");
123         console.assert(currentSectionElement);
124
125         var newSectionElement = document.getElementById(sectionIdentifier);
126         console.assert(newSectionElement);
127
128         currentSectionElement.classList.remove("selected");
129         newSectionElement.classList.add("selected");
130
131         if (pushState)
132             history.pushState({section: sectionIdentifier}, document.title);
133     },
134
135     setupRunningSectionStyle: function(options)
136     {
137         if (!options["show-running-results"])
138             document.getElementById("record").style.display = "none";
139     }
140 }
141
142 window.optionsManager =
143 {
144     _optionsElements : function()
145     {
146         return document.querySelectorAll("section#home > options input");;
147     },
148     
149     _adaptiveTestElement: function()
150     {
151         return document.querySelector("section#home > options #adaptive-test");;
152     },
153     
154     updateUIFromLocalStorage: function()
155     {
156         var optionsElements = this._optionsElements();
157
158         for (var i = 0; i < optionsElements.length; ++i) {
159             var optionElement = optionsElements[i];
160             
161             var value = localStorage.getItem(optionElement.id);
162             if (value === null)
163                 continue;
164
165             if (optionElement.getAttribute("type") == "number")
166                 optionElement.value = +value;
167             else if (optionElement.getAttribute("type") == "checkbox")
168                 optionElement.checked = value == "true";
169         }
170     },
171
172     updateLocalStorageFromUI: function()
173     {
174         var optionsElements = this._optionsElements();
175         var options = {};        
176
177         for (var i = 0; i < optionsElements.length; ++i) {
178             var optionElement = optionsElements[i];
179         
180             if (optionElement.getAttribute("type") == "number")
181                 options[optionElement.id] = optionElement.value;
182             else if (optionElement.getAttribute("type") == "checkbox")
183                 options[optionElement.id] = optionElement.checked;
184     
185             localStorage.setItem(optionElement.id, options[optionElement.id]);
186         }
187         
188         return options;
189     }
190 }
191
192 window.suitesManager =
193 {
194     _treeElement : function()
195     {
196         return document.querySelector("suites > .tree");
197     },
198     
199     _suitesElements : function()
200     {
201         return document.querySelectorAll("#home > suites > ul > li");
202     },
203     
204     _checkboxElement: function(element)
205     {
206         return element.querySelector("input[type='checkbox']:not(.expand-button)");
207     },
208
209     _editElement: function(element)
210     {
211         return element.querySelector("input[type='number']");
212     },
213
214     _editsElements: function()
215     {
216         return document.querySelectorAll("section#home > suites input[type='number']");
217     },
218         
219     _localStorageNameForTest: function(suiteName, testName)
220     {
221         return suiteName + "/" + testName;
222     },
223
224     _updateSuiteCheckboxState: function(suiteCheckbox)
225     {
226         var numberEnabledTests = 0;
227         suiteCheckbox.testsElements.forEach(function(testElement) {
228             var testCheckbox = this._checkboxElement(testElement);
229             if (testCheckbox.checked)
230                 ++numberEnabledTests;
231         }, this);
232         suiteCheckbox.checked = numberEnabledTests > 0;
233         suiteCheckbox.indeterminate = numberEnabledTests > 0 && numberEnabledTests < suiteCheckbox.testsElements.length;
234     },
235
236     _updateStartButtonState: function()
237     {
238         var suitesElements = this._suitesElements();
239         var startButton = document.querySelector("#home > footer > button");
240         
241         for (var i = 0; i < suitesElements.length; ++i) {
242             var suiteElement = suitesElements[i];
243             var suiteCheckbox = this._checkboxElement(suiteElement);
244             
245             if (suiteCheckbox.checked) {
246                 startButton.disabled = false;
247                 return;
248             }
249         }
250     
251         startButton.disabled = true;
252     },
253
254     _onChangeSuiteCheckbox: function(event)
255     {
256         var selected = event.target.checked;
257         event.target.testsElements.forEach(function(testElement) {
258             var testCheckbox = this._checkboxElement(testElement);
259             testCheckbox.checked = selected;        
260         }, this);
261         this._updateStartButtonState();
262     },
263
264     _onChangeTestCheckbox: function(event)
265     {
266         var suiteCheckbox = event.target.suiteCheckbox;
267         this._updateSuiteCheckboxState(suiteCheckbox);
268         this._updateStartButtonState();
269     },
270
271     _createSuiteElement: function(treeElement, suite, id)
272     {
273         var suiteElement = DocumentExtension.createElement("li", {}, treeElement);
274         var expand = DocumentExtension.createElement("input", { type: "checkbox",  class: "expand-button", id: id }, suiteElement);
275         var label = DocumentExtension.createElement("label", { class: "tree-label", for: id }, suiteElement);
276
277         var suiteCheckbox = DocumentExtension.createElement("input", { type: "checkbox" }, label);
278         suiteCheckbox.suite = suite;
279         suiteCheckbox.onchange = this._onChangeSuiteCheckbox.bind(this);
280         suiteCheckbox.testsElements = [];
281
282         label.appendChild(document.createTextNode(" " + suite.name));
283         return suiteElement;
284     },
285
286     _createTestElement: function(listElement, test, suiteCheckbox)
287     {
288         var testElement = DocumentExtension.createElement("li", {}, listElement);
289         var span = DocumentExtension.createElement("span", { class: "tree-label" }, testElement);
290
291         var testCheckbox = DocumentExtension.createElement("input", { type: "checkbox" }, span);
292         testCheckbox.test = test;
293         testCheckbox.onchange = this._onChangeTestCheckbox.bind(this);
294         testCheckbox.suiteCheckbox = suiteCheckbox;
295
296         suiteCheckbox.testsElements.push(testElement);
297         span.appendChild(document.createTextNode(" " + test.name));
298         DocumentExtension.createElement("input", { type: "number" }, testElement);
299         return testElement;
300     },
301
302     createElements: function()
303     {
304         var treeElement = this._treeElement();
305
306         Suites.forEach(function(suite, index) {
307             var suiteElement = this._createSuiteElement(treeElement, suite, "suite-" + index);
308             var listElement = DocumentExtension.createElement("ul", {}, suiteElement);
309             var suiteCheckbox = this._checkboxElement(suiteElement);
310
311             suite.tests.forEach(function(test) {
312                 var testElement = this._createTestElement(listElement, test, suiteCheckbox);
313             }, this);
314         }, this);
315     },
316     
317     updateEditsElementsState: function()
318     {
319         var editsElements = this._editsElements();
320         var show = !optionsManager._adaptiveTestElement().checked;
321
322         for (var i = 0; i < editsElements.length; ++i) {
323             var editElement = editsElements[i];
324             if (show)
325                 editElement.classList.add("selected");
326             else
327                 editElement.classList.remove("selected");
328         }
329     },
330     
331     updateUIFromLocalStorage: function()
332     {
333         var suitesElements = this._suitesElements();
334         
335         for (var i = 0; i < suitesElements.length; ++i) {
336             var suiteElement = suitesElements[i];
337             var suiteCheckbox = this._checkboxElement(suiteElement);
338             var suite = suiteCheckbox.suite;
339             
340             suiteCheckbox.testsElements.forEach(function(testElement) {
341                 var testCheckbox = this._checkboxElement(testElement);
342                 var testEdit = this._editElement(testElement);
343                 var test = testCheckbox.test;
344                 
345                 var str = localStorage.getItem(this._localStorageNameForTest(suite.name, test.name));
346                 if (str === null)
347                     return;
348
349                 var value = JSON.parse(str);
350                 testCheckbox.checked = value.checked;
351                 testEdit.value = value.complexity;
352             }, this);
353
354             this._updateSuiteCheckboxState(suiteCheckbox);
355         }
356         
357         this._updateStartButtonState();
358     },
359
360     updateLocalStorageFromUI: function()
361     {
362         var suitesElements = this._suitesElements();
363         var suites = [];
364         
365         for (var i = 0; i < suitesElements.length; ++i) {
366             var suiteElement = suitesElements[i];
367             var suiteCheckbox = this._checkboxElement(suiteElement);
368             var suite = suiteCheckbox.suite;
369
370             var tests = [];
371             suiteCheckbox.testsElements.forEach(function(testElement) {
372                 var testCheckbox = this._checkboxElement(testElement);
373                 var testEdit = this._editElement(testElement);
374                 var test = testCheckbox.test;
375                 
376                 if (testCheckbox.checked) {
377                     test.complexity = testEdit.value;
378                     tests.push(test);
379                 }
380
381                 var value = { checked: testCheckbox.checked, complexity: testEdit.value }; 
382                 localStorage.setItem(this._localStorageNameForTest(suite.name, test.name), JSON.stringify(value));
383             }, this);
384
385             if (tests.length)
386                 suites.push(new Suite(suiteCheckbox.suite.name, tests));
387         }
388
389         return suites;
390     },
391     
392     updateLocalStorageFromJSON: function(iterationResults)
393     {
394         for (var suiteName in iterationResults[Strings.json.results.suites]) {
395             var suiteResults = iterationResults[Strings.json.results.suites][suiteName];
396
397             for (var testName in suiteResults[Strings.json.results.tests]) {
398                 var testResults = suiteResults[Strings.json.results.tests][testName];
399                 var data = testResults[Strings.json.experiments.complexity];
400                 var complexity = Math.round(data[Strings.json.measurements.average]);
401
402                 var value = { checked: true, complexity: complexity };
403                 localStorage.setItem(this._localStorageNameForTest(suiteName, testName), JSON.stringify(value));
404             }
405         }
406     }
407 }
408
409 window.benchmarkController =
410 {
411     initialize: function()
412     {
413         optionsManager.updateUIFromLocalStorage();
414         suitesManager.createElements();
415         suitesManager.updateUIFromLocalStorage();
416         suitesManager.updateEditsElementsState();
417     },
418
419     onChangeAdaptiveTestCheckbox: function()
420     {
421         suitesManager.updateEditsElementsState();
422     },
423     
424     _runBenchmark: function(suites, options)
425     {
426         benchmarkRunnerClient.initialize(suites, options);
427         var frameContainer = document.querySelector("#running > #running-test");
428         var runner = new BenchmarkRunner(suites, frameContainer || document.body, benchmarkRunnerClient);
429         runner.runMultipleIterations();
430     },
431
432     startTest: function()
433     {
434         var options = optionsManager.updateLocalStorageFromUI();
435         var suites = suitesManager.updateLocalStorageFromUI();
436         sectionsManager.setupRunningSectionStyle(options);
437         this._runBenchmark(suites, options);
438         sectionsManager.showSection("running");
439     },
440
441     selectResults: function()
442     {
443         sectionsManager.selectData("results");
444     },
445     
446     showResults: function()
447     {
448         sectionsManager.showScore("results", Strings.text.results.results);
449         sectionsManager.showSection("results", true);
450     },
451     
452     showJSON: function()
453     {
454         sectionsManager.showScore("json", Strings.text.results.results);
455         sectionsManager.showSection("json", true);
456     },
457
458     showTestGraph: function(testName, axes, samples, samplingTimeOffset)
459     {
460         sectionsManager.showTestName("test-graph", Strings.text.results.graph, testName);
461         sectionsManager.showSection("test-graph", true);
462         graph("section#test-graph > data", new Insets(20, 50, 20, 50), axes, samples, samplingTimeOffset);
463     },
464
465     showTestJSON: function(testName, json)
466     {
467         sectionsManager.showTestName("test-json", Strings.text.results.graph, testName);
468         sectionsManager.showJSON("test-json", json);
469         sectionsManager.showSection("test-json", true);
470     },
471     
472     selectJSON: function(sectionIdentifier)
473     {
474         sectionsManager.selectDataContents(sectionIdentifier);
475     },
476 }
477
478 window.addEventListener("load", benchmarkController.initialize);