c6dc65841c08261dbb2c244ba34249084d975c61
[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     setupRunningSectionStyle: function(options)
113     {
114         if (!options["show-running-results"])
115             document.getElementById("record").style.display = "none";
116     }
117 }
118
119 window.optionsManager =
120 {
121     _optionsElements : function()
122     {
123         return document.querySelectorAll("section#home > options input");;
124     },
125     
126     _adaptiveTestElement: function()
127     {
128         return document.querySelector("section#home > options #adaptive-test");;
129     },
130     
131     updateUIFromLocalStorage: function()
132     {
133         var optionsElements = this._optionsElements();
134
135         for (var i = 0; i < optionsElements.length; ++i) {
136             var optionElement = optionsElements[i];
137             
138             var value = localStorage.getItem(optionElement.id);
139             if (value === null)
140                 continue;
141
142             if (optionElement.getAttribute("type") == "number")
143                 optionElement.value = +value;
144             else if (optionElement.getAttribute("type") == "checkbox")
145                 optionElement.checked = value == "true";
146         }
147     },
148
149     updateLocalStorageFromUI: function()
150     {
151         var optionsElements = this._optionsElements();
152         var options = {};        
153
154         for (var i = 0; i < optionsElements.length; ++i) {
155             var optionElement = optionsElements[i];
156         
157             if (optionElement.getAttribute("type") == "number")
158                 options[optionElement.id] = optionElement.value;
159             else if (optionElement.getAttribute("type") == "checkbox")
160                 options[optionElement.id] = optionElement.checked;
161     
162             localStorage.setItem(optionElement.id, options[optionElement.id]);
163         }
164         
165         return options;
166     }
167 }
168
169 window.suitesManager =
170 {
171     _treeElement : function()
172     {
173         return document.querySelector("suites > .tree");
174     },
175     
176     _suitesElements : function()
177     {
178         return document.querySelectorAll("#home > suites > ul > li");
179     },
180     
181     _checkboxElement: function(element)
182     {
183         return element.querySelector("input[type='checkbox']:not(.expand-button)");
184     },
185
186     _editElement: function(element)
187     {
188         return element.querySelector("input[type='number']");
189     },
190
191     _editsElements: function()
192     {
193         return document.querySelectorAll("section#home > suites input[type='number']");
194     },
195         
196     _localStorageNameForTest: function(suiteName, testName)
197     {
198         return suiteName + "/" + testName;
199     },
200
201     _updateSuiteCheckboxState: function(suiteCheckbox)
202     {
203         var numberEnabledTests = 0;
204         suiteCheckbox.testsElements.forEach(function(testElement) {
205             var testCheckbox = this._checkboxElement(testElement);
206             if (testCheckbox.checked)
207                 ++numberEnabledTests;
208         }, this);
209         suiteCheckbox.checked = numberEnabledTests > 0;
210         suiteCheckbox.indeterminate = numberEnabledTests > 0 && numberEnabledTests < suiteCheckbox.testsElements.length;
211     },
212
213     _updateStartButtonState: function()
214     {
215         var suitesElements = this._suitesElements();
216         var startButton = document.querySelector("#home > footer > button");
217         
218         for (var i = 0; i < suitesElements.length; ++i) {
219             var suiteElement = suitesElements[i];
220             var suiteCheckbox = this._checkboxElement(suiteElement);
221             
222             if (suiteCheckbox.checked) {
223                 startButton.disabled = false;
224                 return;
225             }
226         }
227     
228         startButton.disabled = true;
229     },
230
231     _onChangeSuiteCheckbox: function(event)
232     {
233         var selected = event.target.checked;
234         event.target.testsElements.forEach(function(testElement) {
235             var testCheckbox = this._checkboxElement(testElement);
236             testCheckbox.checked = selected;        
237         }, this);
238         this._updateStartButtonState();
239     },
240
241     _onChangeTestCheckbox: function(event)
242     {
243         var suiteCheckbox = event.target.suiteCheckbox;
244         this._updateSuiteCheckboxState(suiteCheckbox);
245         this._updateStartButtonState();
246     },
247
248     _createSuiteElement: function(treeElement, suite, id)
249     {
250         var suiteElement = DocumentExtension.createElement("li", {}, treeElement);
251         var expand = DocumentExtension.createElement("input", { type: "checkbox",  class: "expand-button", id: id }, suiteElement);
252         var label = DocumentExtension.createElement("label", { class: "tree-label", for: id }, suiteElement);
253
254         var suiteCheckbox = DocumentExtension.createElement("input", { type: "checkbox" }, label);
255         suiteCheckbox.suite = suite;
256         suiteCheckbox.onchange = this._onChangeSuiteCheckbox.bind(this);
257         suiteCheckbox.testsElements = [];
258
259         label.appendChild(document.createTextNode(" " + suite.name));
260         return suiteElement;
261     },
262
263     _createTestElement: function(listElement, test, suiteCheckbox)
264     {
265         var testElement = DocumentExtension.createElement("li", {}, listElement);
266         var span = DocumentExtension.createElement("span", { class: "tree-label" }, testElement);
267
268         var testCheckbox = DocumentExtension.createElement("input", { type: "checkbox" }, span);
269         testCheckbox.test = test;
270         testCheckbox.onchange = this._onChangeTestCheckbox.bind(this);
271         testCheckbox.suiteCheckbox = suiteCheckbox;
272
273         suiteCheckbox.testsElements.push(testElement);
274         span.appendChild(document.createTextNode(" " + test.name));
275         DocumentExtension.createElement("input", { type: "number" }, testElement);
276         return testElement;
277     },
278
279     createElements: function()
280     {
281         var treeElement = this._treeElement();
282
283         Suites.forEach(function(suite, index) {
284             var suiteElement = this._createSuiteElement(treeElement, suite, "suite-" + index);
285             var listElement = DocumentExtension.createElement("ul", {}, suiteElement);
286             var suiteCheckbox = this._checkboxElement(suiteElement);
287
288             suite.tests.forEach(function(test) {
289                 var testElement = this._createTestElement(listElement, test, suiteCheckbox);
290             }, this);
291         }, this);
292     },
293     
294     updateEditsElementsState: function()
295     {
296         var editsElements = this._editsElements();
297         var show = !optionsManager._adaptiveTestElement().checked;
298
299         for (var i = 0; i < editsElements.length; ++i) {
300             var editElement = editsElements[i];
301             if (show)
302                 editElement.classList.add("selected");
303             else
304                 editElement.classList.remove("selected");
305         }
306     },
307     
308     updateUIFromLocalStorage: function()
309     {
310         var suitesElements = this._suitesElements();
311         
312         for (var i = 0; i < suitesElements.length; ++i) {
313             var suiteElement = suitesElements[i];
314             var suiteCheckbox = this._checkboxElement(suiteElement);
315             var suite = suiteCheckbox.suite;
316             
317             suiteCheckbox.testsElements.forEach(function(testElement) {
318                 var testCheckbox = this._checkboxElement(testElement);
319                 var testEdit = this._editElement(testElement);
320                 var test = testCheckbox.test;
321                 
322                 var str = localStorage.getItem(this._localStorageNameForTest(suite.name, test.name));
323                 if (str === null)
324                     return;
325
326                 var value = JSON.parse(str);
327                 testCheckbox.checked = value.checked;
328                 testEdit.value = value.complexity;
329             }, this);
330
331             this._updateSuiteCheckboxState(suiteCheckbox);
332         }
333         
334         this._updateStartButtonState();
335     },
336
337     updateLocalStorageFromUI: function()
338     {
339         var suitesElements = this._suitesElements();
340         var suites = [];
341         
342         for (var i = 0; i < suitesElements.length; ++i) {
343             var suiteElement = suitesElements[i];
344             var suiteCheckbox = this._checkboxElement(suiteElement);
345             var suite = suiteCheckbox.suite;
346
347             var tests = [];
348             suiteCheckbox.testsElements.forEach(function(testElement) {
349                 var testCheckbox = this._checkboxElement(testElement);
350                 var testEdit = this._editElement(testElement);
351                 var test = testCheckbox.test;
352                 
353                 if (testCheckbox.checked) {
354                     test.complexity = testEdit.value;
355                     tests.push(test);
356                 }
357
358                 var value = { checked: testCheckbox.checked, complexity: testEdit.value }; 
359                 localStorage.setItem(this._localStorageNameForTest(suite.name, test.name), JSON.stringify(value));
360             }, this);
361
362             if (tests.length)
363                 suites.push(new Suite(suiteCheckbox.suite.name, tests));
364         }
365
366         return suites;
367     },
368     
369     updateLocalStorageFromJSON: function(iterationResults)
370     {
371         for (var suiteName in iterationResults[Strings["JSON_RESULTS"][1]]) {
372             var suiteResults = iterationResults[Strings["JSON_RESULTS"][1]][suiteName];
373
374             for (var testName in suiteResults[Strings["JSON_RESULTS"][2]]) {
375                 var testResults = suiteResults[Strings["JSON_RESULTS"][2]][testName];
376                 var data = testResults[Strings["JSON_EXPERIMENTS"][0]]
377                 var complexity = Math.round(data[Strings["JSON_MEASUREMENTS"][0]]);
378
379                 var value = { checked: true, complexity: complexity };
380                 localStorage.setItem(this._localStorageNameForTest(suiteName, testName), JSON.stringify(value));
381             }
382         }
383     }
384 }
385
386 window.benchmarkController =
387 {
388     initialize: function()
389     {
390         optionsManager.updateUIFromLocalStorage();
391         suitesManager.createElements();
392         suitesManager.updateUIFromLocalStorage();
393         suitesManager.updateEditsElementsState();
394     },
395
396     onChangeAdaptiveTestCheckbox: function()
397     {
398         suitesManager.updateEditsElementsState();
399     },
400     
401     _runBenchmark: function(suites, options)
402     {
403         benchmarkRunnerClient.initialize(suites, options);
404         var frameContainer = document.querySelector("#running > #running-test");
405         var runner = new BenchmarkRunner(suites, frameContainer || document.body, benchmarkRunnerClient);
406         runner.runMultipleIterations();
407     },
408
409     startTest: function()
410     {
411         var options = optionsManager.updateLocalStorageFromUI();
412         var suites = suitesManager.updateLocalStorageFromUI();
413         sectionsManager.setupRunningSectionStyle(options);
414         this._runBenchmark(suites, options);
415         sectionsManager.showSection("running");
416     },
417     
418     showResults: function()
419     {
420         sectionsManager.showScore("results", Strings["TEXT_RESULTS"][0]);
421         sectionsManager.showSection("results", true);
422     },
423     
424     showJson: function()
425     {
426         sectionsManager.showScore("json", Strings["TEXT_RESULTS"][0]);
427         sectionsManager.showSection("json", true);
428     },
429     
430     showTestGraph: function(testName, axes, samples, samplingTimeOffset)
431     {
432         sectionsManager.showTestName("test-graph", Strings["TEXT_RESULTS"][1], testName);
433         sectionsManager.showSection("test-graph", true);
434         graph("section#test-graph > data", new Insets(20, 50, 20, 50), axes, samples, samplingTimeOffset);
435     },
436
437     showTestJSON: function(testName, json)
438     {
439         sectionsManager.showTestName("test-json", Strings["TEXT_RESULTS"][1], testName);
440         sectionsManager.showJSON("test-json", json);
441         sectionsManager.showSection("test-json", true);
442     }
443 }
444
445 window.addEventListener("load", benchmarkController.initialize);