Add an option to output the results of the graphics benchmark in JSON format
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 26 Oct 2015 16:44:54 +0000 (16:44 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 26 Oct 2015 16:44:54 +0000 (16:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150484
<rdar://problem/23243721>

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2015-10-26
Reviewed by Darin Adler.

* Animometer/resources/extensions.js:
(ResultsDashboard): A new class to hold the iterations results.
(ResultsDashboard.prototype.push): Appends an iteration results;
(ResultsDashboard.prototype.toJSON): Converts the iterations results to JSON format.

(RecordTable.prototype.clear): Clears the results table.
(RecordTable.prototype._showTitles): Shows the header titles and appends the sub-titles to a queue.
(RecordTable.prototype._showHeader): Shows the table header titles.
(RecordTable.prototype._showEmpty): Shows an empty table cell.
(RecordTable.prototype._showValue): Shows a number value in the results table.
(RecordTable.prototype._showSamples): Shows a button for the sampled data graph.
(RecordTable.prototype._showTest): Shows the results of a single test.
(RecordTable.prototype._showSuite): Shows the results of a single suite.
(RecordTable.prototype.showRecord): Shows a single iteration for a single test.
(RecordTable.prototype.showIterations): Shows the results of all the suites of the iterations.

(ResultsTable): RecordTable was renamed to ResultsTable.
(ResultsTable.prototype.clear): Clears the table element.
(ResultsTable.prototype._showHeaderRow): Shows a row in the results table header.
(ResultsTable.prototype._showHeader): Shows the results table header.
(ResultsTable.prototype._showEmpty): Shows an empty table cell.
(ResultsTable.prototype._showText): Shows a string in a new table cell.
(ResultsTable.prototype._showFixedNumber): Shows a number in a new table cell.
(ResultsTable.prototype._showGraph): Shows a button for the sampled data graph.
(ResultsTable.prototype._showJSON): Shows a button for the sampled data JSON.
(ResultsTable.prototype._showTest): Shows the results of a single test.
(ResultsTable.prototype._showSuite): Shows the results of a single suite.
(ResultsTable.prototype._showIteration): Shows the results of a single iteration.
(ResultsTable.prototype.showRecord): Shows a single iteration for a single test.
(ResultsTable.prototype.showIterations): Shows all the results.
(RecordTable): Deleted.
(RecordTable.prototype.clear): Deleted.
(RecordTable.prototype._showTitles): Deleted.
(RecordTable.prototype._showHeader): Deleted.
(RecordTable.prototype._showEmpty): Deleted.
(RecordTable.prototype._showValue): Deleted.
(RecordTable.prototype._showSamples): Deleted.
(RecordTable.prototype._showTest): Deleted.
(RecordTable.prototype._showSuite): Deleted.
(RecordTable.prototype.showRecord): Deleted.
(RecordTable.prototype.showIterations): Deleted.

* Animometer/resources/sampler.js:
(Sampler.prototype.startSampling): Use forEach.
(Sampler.prototype.sample): Use forEach.
(Sampler.prototype.toJSON): Converts the sampler data to JSON format.

* Animometer/resources/strings.js: Added.
This new file will be used to associate the strings used by the benchmark
with IDs. A string can be changed in one place without having to change
all the instances of this string in multiple files. There two groups of
strings in this file. The first one is used by the UI elements and the second
group is used when constructing the results JSON.

* Animometer/runner/animometer.html:
* Animometer/runner/resources/animometer.css:

* Animometer/runner/resources/animometer.js:
(window.benchmarkRunnerClient.willAddTestFrame):
(window.benchmarkRunnerClient.willStartFirstIteration):
(window.benchmarkRunnerClient.didRunSuites):
(window.benchmarkRunnerClient.didFinishLastIteration):
Make benchmarkRunnerClient uses ResultsDashboard instead of _iterationsSamplers
Get the JSON from ResultsDashboard.toJSON() and pass it to ResultsTable.showIterations().
Also set the textContent of the "#json" textarea with the results JSON.

(showResults): Delete unneeded code.
(showJson): Shows the "json" section.
(showTestGraph): Rename showGraph() to be showTestGraph().
(showTestJSON): Shows the JSON of a single testResults.
(showGraph): Deleted.

* Animometer/runner/resources/tests.js:
Use the string table instead of putting literal strings.

* Animometer/tests/resources/stage.js:
(StageBenchmark.prototype.showResults):
Fix the parameters which are passed to RecordTable.showRecord().

* Animometer/tests/bouncing-particles/bouncing-canvas-images.html:
* Animometer/tests/bouncing-particles/bouncing-canvas-shapes.html:
* Animometer/tests/bouncing-particles/bouncing-css-images.html:
* Animometer/tests/bouncing-particles/bouncing-css-shapes.html:
* Animometer/tests/bouncing-particles/bouncing-svg-images.html:
* Animometer/tests/bouncing-particles/bouncing-svg-shapes.html:
* Animometer/tests/examples/canvas-electrons.html:
* Animometer/tests/examples/canvas-stars.html:
* Animometer/tests/simple/simple-canvas-paths.html:
* Animometer/tests/template/template-canvas.html:
* Animometer/tests/template/template-css.html:
* Animometer/tests/template/template-svg.html:
* Animometer/tests/text/layering-text.html:
Include the new strings.js file in all the test files.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@191586 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
PerformanceTests/Animometer/resources/extensions.js
PerformanceTests/Animometer/resources/sampler.js
PerformanceTests/Animometer/resources/strings.js [new file with mode: 0644]
PerformanceTests/Animometer/runner/animometer.html
PerformanceTests/Animometer/runner/resources/animometer.css
PerformanceTests/Animometer/runner/resources/animometer.js
PerformanceTests/Animometer/runner/resources/tests.js
PerformanceTests/Animometer/tests/bouncing-particles/bouncing-canvas-images.html
PerformanceTests/Animometer/tests/bouncing-particles/bouncing-canvas-shapes.html
PerformanceTests/Animometer/tests/bouncing-particles/bouncing-css-images.html
PerformanceTests/Animometer/tests/bouncing-particles/bouncing-css-shapes.html
PerformanceTests/Animometer/tests/bouncing-particles/bouncing-svg-images.html
PerformanceTests/Animometer/tests/bouncing-particles/bouncing-svg-shapes.html
PerformanceTests/Animometer/tests/examples/canvas-electrons.html
PerformanceTests/Animometer/tests/examples/canvas-stars.html
PerformanceTests/Animometer/tests/resources/stage.js
PerformanceTests/Animometer/tests/simple/simple-canvas-paths.html
PerformanceTests/Animometer/tests/template/template-canvas.html
PerformanceTests/Animometer/tests/template/template-css.html
PerformanceTests/Animometer/tests/template/template-svg.html
PerformanceTests/Animometer/tests/text/layering-text.html
PerformanceTests/ChangeLog

index 66b13b7978a15215e13361ec8df348e044249190..c700d146234864a805b480ca6a577d47a220d8e3 100644 (file)
@@ -141,42 +141,96 @@ ProgressBar.prototype =
     }
 }
 
-function RecordTable(element)
+function ResultsDashboard()
+{
+    this._iterationsSamplers = [];
+}
+
+ResultsDashboard.prototype =
+{
+    push: function(suitesSamplers)
+    {
+        this._iterationsSamplers.push(suitesSamplers);        
+    },
+    
+    toJSON: function(statistics, graph)
+    {
+        var iterationsResults = [];
+        var iterationsScores = [];
+        
+        this._iterationsSamplers.forEach(function(iterationSamplers, index) {
+            var suitesResults = {};
+            var suitesScores = [];
+        
+            for (var suiteName in iterationSamplers) {
+                var suite = suiteFromName(suiteName);
+                var suiteSamplers = iterationSamplers[suiteName];
+
+                var testsResults = {};
+                var testsScores = [];
+                
+                for (var testName in suiteSamplers) {
+                    var sampler = suiteSamplers[testName];
+                    testsResults[testName] = sampler.toJSON(statistics, graph);
+                    testsScores.push(testsResults[testName][Strings["JSON_SCORE"]]);
+                }
+
+                suitesResults[suiteName] =  {};
+                suitesResults[suiteName][Strings["JSON_SCORE"]] = Statistics.geometricMean(testsScores);
+                suitesResults[suiteName][Strings["JSON_RESULTS"][2]] = testsResults;
+                suitesScores.push(suitesResults[suiteName][Strings["JSON_SCORE"]]);
+            }
+            
+            iterationsResults[index] = {};
+            iterationsResults[index][Strings["JSON_SCORE"]] = Statistics.geometricMean(suitesScores);
+            iterationsResults[index][Strings["JSON_RESULTS"][1]] = suitesResults;
+            iterationsScores.push(iterationsResults[index][Strings["JSON_SCORE"]]);
+        });
+
+        var json = {};
+        json[Strings["JSON_SCORE"]] = Statistics.sampleMean(iterationsScores.length, iterationsScores.reduce(function(a, b) { return a * b; }));
+        json[Strings["JSON_RESULTS"][0]] = iterationsResults;
+        return json;
+    }
+}
+
+function ResultsTable(element, headers)
 {
     this.element = element;
+    this._headers = headers;
     this.clear();
 }
 
-RecordTable.prototype =
+ResultsTable.prototype =
 {
     clear: function()
     {
         this.element.innerHTML = "";
     },
-    
-    _showTitles: function(row, queue, titles, message)
+
+    _showHeaderRow: function(row, queue, headers, message)
     {
-        titles.forEach(function (title) {
+        headers.forEach(function (header) {
             var th = document.createElement("th");
-            th.textContent = title.text;
+            th.textContent = header.text;
             if (typeof message != "undefined" && message.length) {
                 th.appendChild(document.createElement('br'));
                 th.appendChild(document.createTextNode('[' + message +']'));
                 message = "";
             }
-            if ("width" in title)
-                th.width = title.width + "%";
+            if ("width" in header)
+                th.width = header.width + "%";
             row.appendChild(th);
-            queue.push({element: th, titles: title.children });
+            queue.push({element: th, headers: header.children });
         });
     },
-    
-    _showHeader: function(suiteName, titles, message)
+
+    _showHeader: function(message)
     {
         var row = document.createElement("tr");
 
         var queue = [];
-        this._showTitles(row, queue, titles, message);
+        this._showHeaderRow(row, queue, this._headers, message);
         this.element.appendChild(row);
 
         while (queue.length) {
@@ -186,7 +240,7 @@ RecordTable.prototype =
             for (var i = 0, len = queue.length; i < len; ++i) {
                 var entry = queue.shift();
 
-                if (!entry.titles.length) {
+                if (!entry.headers.length) {
                     entries.push(entry.element);
                     continue;
                 }
@@ -194,8 +248,8 @@ RecordTable.prototype =
                 if (!row)
                     var row = document.createElement("tr");
 
-                this._showTitles(row, queue, entry.titles, "");
-                entry.element.colSpan = entry.titles.length;
+                this._showHeaderRow(row, queue, entry.headers, "");
+                entry.element.colSpan = entry.headers.length;
             }
 
             if (row) {
@@ -207,100 +261,132 @@ RecordTable.prototype =
         }
     },
     
-    _showEmpty: function(row, testName)
+    _showEmpty: function(row)
     {
         var td = document.createElement("td");
         row.appendChild(td);
     },
-    
-    _showValue: function(row, testName, value)
+
+    _showText: function(row, text)
     {
         var td = document.createElement("td");
-        td.textContent = value.toFixed(2);
+        td.textContent = text;
+        row.appendChild(td);
+    },
+
+    _showFixedNumber: function(row, value, digits)
+    {
+        var td = document.createElement("td");
+        td.textContent = value.toFixed(digits || 2);
         row.appendChild(td);
     },
     
-    _showSamples: function(row, testName, axes, samples, samplingTimeOffset)
+    _showGraph: function(row, testName, testResults)
     {
+        var data = testResults[Strings["JSON_SAMPLES"][0]];
+        if (!data) {
+            this._showEmpty(row);
+            return;
+        }
+        
         var td = document.createElement("td");
         var button = document.createElement("div");
         button.className = "small-button";
-            
+
         button.addEventListener("click", function() {
-            window.showGraph(testName, axes, samples, samplingTimeOffset);
+            var samples = data[Strings["JSON_GRAPH"][0]];
+            var samplingTimeOffset = data[Strings["JSON_GRAPH"][1]];
+            var axes = Strings["TEXT_EXPERIMENTS"];
+            window.showTestGraph(testName, axes, samples, samplingTimeOffset);
         });
             
-        button.textContent = "Graph...";
+        button.textContent = Strings["TEXT_RESULTS"][1] + "...";
         td.appendChild(button);
         row.appendChild(td);
     },
-    
-    _showTest: function(testName, titles, sampler, finalResults)
+
+    _showJSON: function(row, testName, testResults)
     {
-        var row = document.createElement("tr");
-        var td = document.createElement("td");
+        var data = testResults[Strings["JSON_SAMPLES"][0]];
+        if (!data) {
+            this._showEmpty(row);
+            return;
+        }
         
-        td.textContent = testName;
+        var td = document.createElement("td");
+        var button = document.createElement("div");
+        button.className = "small-button";
+
+        button.addEventListener("click", function() {
+            window.showTestJSON(testName, testResults);
+        });
+            
+        button.textContent = Strings["TEXT_RESULTS"][2] + "...";
+        td.appendChild(button);
         row.appendChild(td);
+    },
+
+    _showTest: function(testName, testResults)
+    {
+        var row = document.createElement("tr");
         
-        var axes = [];
-        sampler.experiments.forEach(function(experiment, index) {
-            this._showValue(row, testName, experiment.mean());
-            this._showValue(row, testName, experiment.concern(Experiment.defaults.CONCERN));
-            this._showValue(row, testName, experiment.standardDeviation());
-            this._showValue(row, testName, experiment.percentage());
-            axes.push(titles[index + 1].text);
-            
-        }, this);
+        for (var index = 0; index < this._headers.length; ++index) {
 
-        this._showValue(row, testName, sampler.experiments[0].score(Experiment.defaults.CONCERN));
+            switch (index) {
+            case 0:
+                this._showText(row, testName);
+                break;
 
-        if (finalResults)
-            this._showSamples(row, testName, axes, sampler.samples, sampler.samplingTimeOffset);
-        else
-            this._showEmpty(row, testName);
-            
+            case 1:
+                var data = testResults[Strings["JSON_SCORE"][0]];
+                this._showFixedNumber(row, data, 2);
+                break;
+
+            case 2:
+            case 3:
+                var data = testResults[Strings["JSON_EXPERIMENTS"][index - 2]];
+                for (var measurement in data)
+                    this._showFixedNumber(row, data[measurement], 2);
+                break;
+                
+            case 4:
+                this._showGraph(row, testName, testResults);
+                this._showJSON(row, testName, testResults);
+                break;
+            }
+        }
+        
         this.element.appendChild(row);
     },
-    
-    _showSuite: function(suite, suiteSamplers)
+
+    _showSuite: function(suiteName, suiteResults)
     {
-        var scores = [];        
-        for (var testName in suiteSamplers) {
-            var test = testFromName(suite, testName);
-            var sampler = suiteSamplers[testName]; 
-            this._showTest(testName, suite.titles, sampler, true);
-            scores.push(sampler.experiments[0].score(Experiment.defaults.CONCERN));
+        for (var testName in suiteResults[Strings["JSON_RESULTS"][2]]) {
+            this._showTest(testName, suiteResults[Strings["JSON_RESULTS"][2]][testName]);
         }
-        return scores;
     },
     
-    showRecord: function(suite, test, sampler, message)
+    _showIteration : function(iterationResults)
     {
-        this.clear();        
-        this._showHeader("", suite.titles, message);
-        this._showTest(test.name, suite.titles, sampler, false);        
+        for (var suiteName in iterationResults[Strings["JSON_RESULTS"][1]]) {
+            this._showSuite(suiteName, iterationResults[Strings["JSON_RESULTS"][1]][suiteName]);
+        }
     },
     
-    showIterations: function(iterationsSamplers)
+    showRecord: function(testName, message, testResults)
     {
         this.clear();
+        this._showHeader(message);
+        this._showTest(testName, testResults);
+    },
 
-        var scores = [];
-        var titles = null;
-        iterationsSamplers.forEach(function(suitesSamplers) {
-            for (var suiteName in suitesSamplers) {
-                var suite = suiteFromName(suiteName);
-                if (titles != suite.titles) {
-                    titles = suite.titles;
-                    this._showHeader(suiteName, titles, "");
-                }
-
-                var suiteScores = this._showSuite(suite, suitesSamplers[suiteName]);
-                scores.push.apply(scores, suiteScores);
-            }
+    showIterations: function(iterationsResults)
+    {
+        this.clear();
+        this._showHeader("");
+        
+        iterationsResults.forEach(function(iterationResults) {
+            this._showIteration(iterationResults);
         }, this);
-
-        return Statistics.geometricMean(scores);
     }
 }
index dcf95505b27ed252141176c664ef79a273bbaaa1..99d5f2df1046f6663bbdcdecfb47b119f97a4bc0 100644 (file)
@@ -103,22 +103,49 @@ function Sampler(count)
 
 Sampler.prototype =
 {
-    startSampling: function(timeOffset)
+    startSampling: function(samplingTimeOffset)
     {
-        for (var index = 0; index < this.experiments.length; ++index)
-            this.experiments[index].startSampling();
+        this.experiments.forEach(function(experiment) {
+            experiment.startSampling();
+        });
             
-        this.samplingTimeOffset = timeOffset / 1000;
+        this.samplingTimeOffset = samplingTimeOffset / 1000;
     },
     
     sample: function(timeOffset, values)
     {
         if (values.length < this.experiments.length)
             throw "Not enough sample points";
+
+        this.experiments.forEach(function(experiment, index) {
+            experiment.sample(values[index]);
+        });
                     
-        for (var index = 0; index < this.experiments.length; ++index)
-            this.experiments[index].sample(values[index]);
-            
         this.samples.push({ timeOffset: timeOffset / 1000, values: values });
+    },
+    
+    toJSON: function(statistics, graph)
+    {
+        var results = {};
+         
+        results[Strings["JSON_SCORE"]] = this.experiments[0].score(Experiment.defaults.CONCERN);
+           
+        if (statistics) {
+            this.experiments.forEach(function(experiment, index) {
+                results[Strings["JSON_EXPERIMENTS"][index]] = {};
+                results[Strings["JSON_EXPERIMENTS"][index]][Strings["JSON_MEASUREMENTS"][0]] = experiment.mean();
+                results[Strings["JSON_EXPERIMENTS"][index]][Strings["JSON_MEASUREMENTS"][1]] = experiment.concern(Experiment.defaults.CONCERN);
+                results[Strings["JSON_EXPERIMENTS"][index]][Strings["JSON_MEASUREMENTS"][2]] = experiment.standardDeviation();
+                results[Strings["JSON_EXPERIMENTS"][index]][Strings["JSON_MEASUREMENTS"][3]] = experiment.percentage();
+            });
+        }
+        
+        if (graph) {
+            results[Strings["JSON_SAMPLES"][0]] = {};
+            results[Strings["JSON_SAMPLES"][0]][Strings["JSON_GRAPH"][0]] = this.samples;
+            results[Strings["JSON_SAMPLES"][0]][Strings["JSON_GRAPH"][1]] = this.samplingTimeOffset;
+        }
+        
+        return results;
     }
 }
diff --git a/PerformanceTests/Animometer/resources/strings.js b/PerformanceTests/Animometer/resources/strings.js
new file mode 100644 (file)
index 0000000..0a7ee22
--- /dev/null
@@ -0,0 +1,15 @@
+var Strings = {
+    TEXT_TESTNAME:       [ "Test Name" ],
+    TEXT_EXPERIMENTS:    [ "Complexity", "FPS" ],
+    TEXT_MEASUREMENTS:   [ "Avg.", "W.5%", "Std.", "%" ],
+    TEXT_SCORE:          [ "Score" ],
+    TEXT_SAMPLES:        [ "Samples" ],
+    TEXT_RESULTS:        [ "Results", "Graph", "JSON" ],
+    
+    JSON_EXPERIMENTS:    [ "complexity", "frameRate" ],
+    JSON_MEASUREMENTS:   [ "average", "concern", "stdev", "percent" ],
+    JSON_SCORE:          [ "score" ],
+    JSON_SAMPLES:        [ "samples" ],
+    JSON_GRAPH:          [ "points", "samplingTimeOffset" ],
+    JSON_RESULTS:        [ "iterationsResults", "suitesResults", "testsResults" ],
+};
index d8d586c3f136bb80c54609872b62a37f50beaa78..1c3e31adfacdfcf1fba16ea54e6dba82974e413f 100644 (file)
@@ -2,6 +2,7 @@
 <html>
 <head>
     <link rel="stylesheet" href="resources/animometer.css">
+    <script src="../resources/strings.js" defer></script>
     <script src="../resources/sampler.js" defer></script>
     <script src="../resources/extensions.js" defer></script>
     <script src="resources/tests.js" defer=""></script>
             </div>
         </section>
         <section id="results">
-            <h1>Results</h1>
+            <h1>Results:</h1>
             <table class="results-table"></table>
             <div class="buttons">
+                <button onclick="showJson()">JSON</button>
                 <button onclick="startTest()">Test Again</button>
             </div>
         </section>  
-        <section id="graph">
-            <h1>Graph</h1>
+        <section id="json">
+            <h1>JSON:</h1>
+            <textarea class="results-json"></textarea>
+            <div class="buttons">
+                <button onclick="showResults()">Results</button>
+                <button onclick="startTest()">Test Again</button>
+            </div>
+        </section>  
+        <section id="test-graph">
+            <h1>Graph:</h1>
             <div id="graphContainer"></div>
             <div class="buttons">
                 <button onclick="showResults()">Results</button>
                 <button onclick="startTest()">Test Again</button>        
             </div>
         </section>  
+        <section id="test-json">
+            <h1>JSON:</h1>
+            <textarea class="results-json"></textarea>
+            <div class="buttons">
+                <button onclick="showResults()">Results</button>
+                <button onclick="startTest()">Test Again</button>        
+            </div>
+        </section>  
     </main>
 </body>
 </html>
index 1da336023444a83f2738840e97df2a65dd214a11..af79626773eca9aebcd87f7254494dc2245d2e2d 100644 (file)
@@ -117,6 +117,17 @@ section#results > table th {
     text-align: center;
 }
 
+section#test-json > textarea,
+section#json > textarea {
+    width: 800px;
+    height: 460px;
+    background-color: rgb(128, 128, 128);
+    border: 1px solid rgb(235, 235, 235);
+    color: white;
+    white-space: pre;
+    overflow: scroll;
+}
+
 .options {
     margin:0 auto;    
     margin-top: 30px;
index d8b3825f2dacfacaf7bd3d316939377ff00c2c7d..aaea4f1e0f3c88e59b43ecf49eadec0772608c63 100644 (file)
@@ -5,7 +5,7 @@ window.benchmarkRunnerClient = {
     recordTable: null,
     options: { testInterval: 30000, frameRate: 50, estimatedFrameRate: true, fixTestComplexity : false },
     score: 0,
-    _iterationsSamplers: [],
+    _resultsDashboard: null,
     _resultsTable: null,
     
     willAddTestFrame: function (frame)
@@ -23,21 +23,31 @@ window.benchmarkRunnerClient = {
     
     willStartFirstIteration: function ()
     {
-        this._iterationsSamplers = [];
-        this._resultsTable = new RecordTable(document.querySelectorAll(".results-table")[0]);
+        this._resultsDashboard = new ResultsDashboard();
+        this._resultsTable = new ResultsTable(document.querySelector(".results-table"), Headers);
         
         this.progressBar = new ProgressBar(document.getElementById("progress-completed"), this.testsCount);
-        this.recordTable = new RecordTable(document.querySelectorAll(".record-table")[0]);
+        this.recordTable = new ResultsTable(document.querySelector(".record-table"), Headers);
     },
     
     didRunSuites: function (suitesSamplers)
     {
-        this._iterationsSamplers.push(suitesSamplers);
+        this._resultsDashboard.push(suitesSamplers);
     },
     
     didFinishLastIteration: function ()
     {
-        this.score = this._resultsTable.showIterations(this._iterationsSamplers, "");
+        var json = this._resultsDashboard.toJSON(true, true);
+        this._resultsTable.showIterations(json[Strings["JSON_RESULTS"][0]]);
+        
+        var element = document.querySelector("#json > textarea");
+        element.innerHTML = JSON.stringify(json[Strings["JSON_RESULTS"][0]][0], function(key, value) { 
+            if (typeof value == "number")
+                return value.toFixed(2);
+            return value;
+        }, 4);
+        
+        this.score = json[Strings["JSON_SCORE"]];
         showResults();
     }
 }
@@ -92,10 +102,10 @@ function startTest()
     startBenchmark();
 }
 
-function showResults(score)
+function showResults()
 {
     var element = document.querySelector("#results > h1");
-    element.textContent = "Results:"
+    element.textContent = Strings["TEXT_RESULTS"][0] + ":";
     
     var score = benchmarkRunnerClient.score.toFixed(2);
     element.textContent += " [Score = " + score + "]";
@@ -103,16 +113,45 @@ function showResults(score)
     showSection("results", true);
 }
 
-function showGraph(testName, axes, samples, samplingTimeOffset)
+function showJson()
+{
+    var element = document.querySelector("#json > h1");
+    element.textContent = Strings["TEXT_RESULTS"][2] + ":";
+    
+    var score = benchmarkRunnerClient.score.toFixed(2);
+    element.textContent += " [Score = " + score + "]";
+
+    showSection("json", true);
+}
+
+function showTestGraph(testName, axes, samples, samplingTimeOffset)
 {
-    var element = document.querySelector("#graph > h1");
-    element.textContent = "Graph:"
+    var element = document.querySelector("#test-graph > h1");
+    element.textContent = Strings["TEXT_RESULTS"][1] + ":";
 
     if (testName.length)
         element.textContent += " [test = " + testName + "]";
             
     graph("#graphContainer", new Point(700, 400), new Insets(20, 50, 20, 50), axes, samples, samplingTimeOffset);
-    showSection("graph", true);    
+    showSection("test-graph", true);    
+}
+
+function showTestJSON(testName, testResults)
+{
+    var element = document.querySelector("#test-json > h1");
+    element.textContent = Strings["TEXT_RESULTS"][2] + ":";
+
+    if (testName.length)
+        element.textContent += " [test = " + testName + "]";
+            
+    var element = document.querySelector("#test-json > textarea");
+    element.innerHTML = JSON.stringify(testResults, function(key, value) { 
+        if (typeof value == "number")
+            return value.toFixed(2);
+        return value;
+    }, 4);
+
+    showSection("test-json", true);    
 }
 
 function populateSettings() {
index 1f715ffbc16c87d6c00386ff6b344f404c290468..c90467e76f8e18b37f675d3269956b41be8d3ce4 100644 (file)
@@ -1,46 +1,49 @@
-var Titles = [
+var Headers = [
     {
-        text: "Test Name",
-        width: 28,
+        text: Strings["TEXT_TESTNAME"][0],
+        width: 27,
         children: []
     },
     {
-        text: "Animated Items",
-        width: 28,
+        text: Strings["TEXT_SCORE"][0],
+        width: 7,
+        children: []
+    },
+    {
+        text: Strings["TEXT_EXPERIMENTS"][0],
+        width: 27,
         children:
         [
-            { text:   "Avg.", width: 7, children: [] },
-            { text:   "W.5%", width: 7, children: [] },
-            { text:   "Std.", width: 7, children: [] },
-            { text:      "%", width: 7, children: [] },
+            { text: Strings["TEXT_MEASUREMENTS"][0], width: 7, children: [] },
+            { text: Strings["TEXT_MEASUREMENTS"][1], width: 7, children: [] },
+            { text: Strings["TEXT_MEASUREMENTS"][2], width: 7, children: [] },
+            { text: Strings["TEXT_MEASUREMENTS"][3], width: 6, children: [] },
         ]
     },
     {
-        text: "FPS",
-        width: 28,
+        text: Strings["TEXT_EXPERIMENTS"][1],
+        width: 24,
         children:
         [
-            { text:   "Avg.", width: 7, children: [] },
-            { text:   "W.5%", width: 7, children: [] },
-            { text:   "Std.", width: 7, children: [] },
-            { text:      "%", width: 7, children: [] },
+            { text: Strings["TEXT_MEASUREMENTS"][0], width: 6, children: [] },
+            { text: Strings["TEXT_MEASUREMENTS"][1], width: 6, children: [] },
+            { text: Strings["TEXT_MEASUREMENTS"][2], width: 6, children: [] },
+            { text: Strings["TEXT_MEASUREMENTS"][3], width: 6, children: [] },
         ]
     },
     {
-        text: "Score",
-        width: 8,
-        children: []
-    },
-    {
-        text: "Samples",
-        width: 8,
-        children: []
+        text: Strings["TEXT_SAMPLES"][0],
+        width: 15,
+        children:
+        [
+            { text: Strings["TEXT_RESULTS"][1], width: 8, children: [] },
+            { text: Strings["TEXT_RESULTS"][2], width: 7, children: [] },
+        ]
     }
 ];
 
 var Suite = function(name, tests) {
     this.name = name;
-    this.titles = Titles;
     this.tests = tests;
 };
 Suite.prototype.prepare = function(runner, contentWindow, contentDocument)
@@ -54,7 +57,6 @@ Suite.prototype.run = function(contentWindow, test, options, recordTable, progre
     return contentWindow.runBenchmark(this, test, options, recordTable, progressBar);
 };
 
-
 var Suites = [];
 
 Suites.push(new Suite("HTML suite",
index 9e5886c0d2e7459542d99d5a2edba2b2c7b4cb6c..45baf4d1858524b051dd2eeff6bb5a8a074efaca 100644 (file)
@@ -9,6 +9,7 @@
     </style>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index 4b1bc354da1c4929df611bacf868b9e8f33d6f7a..7255873f7ad830b88f5d7b88928416671f6b1c50 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index f23642096bfbfb5bb91c4991856c691faae0b677..dfb5ba6306aebbf9e0b65c564a38e4fcde3e6c9a 100644 (file)
@@ -8,6 +8,7 @@
     </style>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index 66936385837547ee5bc5e31fdcb89f54ccd3d760..0cfc6fa8dde9b526b49c6facc8096f242d9d42a3 100644 (file)
@@ -19,6 +19,7 @@
     </style>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index 1cd90cf8a2f5f5c07c40894af7ab6c997c426f14..5a8ce434b1e920eeb528f14c1a2da7d8139b483f 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index 3c069fde67f09834654e07ef90029cbf928bd855..55b8edb238bd4f90deb396c9e3ff399cd8e20ca1 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index 22c20a67f81b8b219f77596463e8817d5a92b527..cc8789157450fd40fa44a0ed697fde8388e44482 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index abf6ea79d219cfef6d715ebaad6e18f1e53a4f18..382748ac7ec2d74132febc109436ae541ed56d60 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index 4763619e097f77e3ce375e87a9c9b129d5a2d023..07fa6617d6fb55058fa0bb077f6ac0aaa3ce781f 100644 (file)
@@ -174,11 +174,11 @@ StageBenchmark.prototype.clear = function()
 
 StageBenchmark.prototype.showResults = function(message, progress)
 {
-    if (!this._recordTable || !this._progressBar || !this._suite || !this._test)
+    if (!this._recordTable || !this._progressBar || !this._test)
         return;
 
     if (this.options.showRunningResults)
-        this._recordTable.showRecord(this._suite, this._test, this._sampler, message);
+        this._recordTable.showRecord(this._test.name, message, this._sampler.toJSON(true, false));
 
     this._progressBar.setPos(progress);
 }
index bf61846501c80803d2f5bea2d925b328988f4f42..64d7109c466a7e4807238cbc4b8469e1c4ba22ee 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index bbf969565ea8cab77bfd4339ec9a9d22e9cb080d..6ce5dab91d5cf1a937be1d2bc395a797c5b21662 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index e7d246d1a2b586658280798e29af2a1032e5393d..2aa80db70cbf1d9c0ca1594e1970556a91ec528c 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index cfaf70eed7e9dfa1a9b90ccccb26104f0f55cf07..b9c8fceb355e7f9ae607de65c26c6abc9759be01 100644 (file)
@@ -3,6 +3,7 @@
 <head>
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index d7e3d05d050bf8a4e16dfb945f53776043b72700..f58ef4ca6fdf4cc612aa97db9f3d19fa8b6e14c5 100644 (file)
@@ -13,6 +13,7 @@
     </style>  
     <link rel="stylesheet" type="text/css" href="../resources/stage.css">
     <script src="../../resources/algorithm.js"></script>
+    <script src="../../resources/strings.js"></script>
     <script src="../../resources/sampler.js"></script>
     <script src="../../resources/extensions.js"></script>
     <script src="../resources/math.js"></script>
index 0463633a274f6ccf88f84e71aed6bd602cea80f5..3e0a7f0357606fe6e5f8ac45d98724fbf84abd41 100644 (file)
@@ -1,3 +1,105 @@
+2015-10-26  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Add an option to output the results of the graphics benchmark in JSON format
+        https://bugs.webkit.org/show_bug.cgi?id=150484
+        <rdar://problem/23243721>
+
+        Reviewed by Darin Adler.
+
+        * Animometer/resources/extensions.js:
+        (ResultsDashboard): A new class to hold the iterations results.
+        (ResultsDashboard.prototype.push): Appends an iteration results;
+        (ResultsDashboard.prototype.toJSON): Converts the iterations results to JSON format.
+
+        (RecordTable.prototype.clear): Clears the results table.
+        (RecordTable.prototype._showTitles): Shows the header titles and appends the sub-titles to a queue.
+        (RecordTable.prototype._showHeader): Shows the table header titles.
+        (RecordTable.prototype._showEmpty): Shows an empty table cell.
+        (RecordTable.prototype._showValue): Shows a number value in the results table.
+        (RecordTable.prototype._showSamples): Shows a button for the sampled data graph.
+        (RecordTable.prototype._showTest): Shows the results of a single test.
+        (RecordTable.prototype._showSuite): Shows the results of a single suite.
+        (RecordTable.prototype.showRecord): Shows a single iteration for a single test.
+        (RecordTable.prototype.showIterations): Shows the results of all the suites of the iterations. 
+        
+        (ResultsTable): RecordTable was renamed to ResultsTable.
+        (ResultsTable.prototype.clear): Clears the table element.
+        (ResultsTable.prototype._showHeaderRow): Shows a row in the results table header.
+        (ResultsTable.prototype._showHeader): Shows the results table header.
+        (ResultsTable.prototype._showEmpty): Shows an empty table cell.
+        (ResultsTable.prototype._showText): Shows a string in a new table cell.
+        (ResultsTable.prototype._showFixedNumber): Shows a number in a new table cell.
+        (ResultsTable.prototype._showGraph): Shows a button for the sampled data graph.
+        (ResultsTable.prototype._showJSON): Shows a button for the sampled data JSON.
+        (ResultsTable.prototype._showTest): Shows the results of a single test.
+        (ResultsTable.prototype._showSuite): Shows the results of a single suite.
+        (ResultsTable.prototype._showIteration): Shows the results of a single iteration.
+        (ResultsTable.prototype.showRecord): Shows a single iteration for a single test.
+        (ResultsTable.prototype.showIterations): Shows all the results.
+        (RecordTable): Deleted.
+        (RecordTable.prototype.clear): Deleted.
+        (RecordTable.prototype._showTitles): Deleted.
+        (RecordTable.prototype._showHeader): Deleted.
+        (RecordTable.prototype._showEmpty): Deleted.
+        (RecordTable.prototype._showValue): Deleted.
+        (RecordTable.prototype._showSamples): Deleted.
+        (RecordTable.prototype._showTest): Deleted.
+        (RecordTable.prototype._showSuite): Deleted.
+        (RecordTable.prototype.showRecord): Deleted.
+        (RecordTable.prototype.showIterations): Deleted.
+        
+        * Animometer/resources/sampler.js:
+        (Sampler.prototype.startSampling): Use forEach.
+        (Sampler.prototype.sample): Use forEach.
+        (Sampler.prototype.toJSON): Converts the sampler data to JSON format.
+        
+        * Animometer/resources/strings.js: Added.
+        This new file will be used to associate the strings used by the benchmark
+        with IDs. A string can be changed in one place without having to change
+        all the instances of this string in multiple files. There two groups of
+        strings in this file. The first one is used by the UI elements and the second
+        group is used when constructing the results JSON.
+        
+        * Animometer/runner/animometer.html:
+        * Animometer/runner/resources/animometer.css:
+        
+        * Animometer/runner/resources/animometer.js:
+        (window.benchmarkRunnerClient.willAddTestFrame):
+        (window.benchmarkRunnerClient.willStartFirstIteration):
+        (window.benchmarkRunnerClient.didRunSuites):
+        (window.benchmarkRunnerClient.didFinishLastIteration):
+        Make benchmarkRunnerClient uses ResultsDashboard instead of _iterationsSamplers
+        Get the JSON from ResultsDashboard.toJSON() and pass it to ResultsTable.showIterations().
+        Also set the textContent of the "#json" textarea with the results JSON.
+        
+        (showResults): Delete unneeded code.
+        (showJson): Shows the "json" section.
+        (showTestGraph): Rename showGraph() to be showTestGraph().
+        (showTestJSON): Shows the JSON of a single testResults.
+        (showGraph): Deleted.
+        
+        * Animometer/runner/resources/tests.js:
+        Use the string table instead of putting literal strings.
+
+        * Animometer/tests/resources/stage.js:
+        (StageBenchmark.prototype.showResults):
+        Fix the parameters which are passed to RecordTable.showRecord().
+        
+        * Animometer/tests/bouncing-particles/bouncing-canvas-images.html:
+        * Animometer/tests/bouncing-particles/bouncing-canvas-shapes.html:
+        * Animometer/tests/bouncing-particles/bouncing-css-images.html:
+        * Animometer/tests/bouncing-particles/bouncing-css-shapes.html:
+        * Animometer/tests/bouncing-particles/bouncing-svg-images.html:
+        * Animometer/tests/bouncing-particles/bouncing-svg-shapes.html:
+        * Animometer/tests/examples/canvas-electrons.html:
+        * Animometer/tests/examples/canvas-stars.html:
+        * Animometer/tests/simple/simple-canvas-paths.html:
+        * Animometer/tests/template/template-canvas.html:
+        * Animometer/tests/template/template-css.html:
+        * Animometer/tests/template/template-svg.html:
+        * Animometer/tests/text/layering-text.html:
+        Include the new strings.js file in all the test files.
+
 2015-10-12  Jon Lee  <jonlee@apple.com>
 
         Add canvas line dash test