Adjust the FPS graph scale.
authorjonlee@apple.com <jonlee@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Feb 2016 03:30:29 +0000 (03:30 +0000)
committerjonlee@apple.com <jonlee@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Feb 2016 03:30:29 +0000 (03:30 +0000)
Instead of making the FPS graph linearly scale, scale it based on the frame length,
but show the data in terms of FPS. Because it is inversely proportional, and most
of the data never gets below 20, concentrate the axis from 20-60 FPS, since otherwise
over half of the available graph space ends up blank.

This means we should convert all of the FPS data to frame length data.

* Animometer/resources/debug-runner/graph.js: Update the domain to be based on
frame length in milliseconds instead of FPS. Update the cursor to consider all of the
values being shown, and then pick the min and max values to represent the length of the
cursor.
* Animometer/resources/runner/animometer.js:
* Animometer/resources/strings.js:
* Animometer/tests/resources/main.js:
(processSamples): Add the ability to only sample a range of the data instead of everything
after an offset index. Update sampler to record the frame lengths instead of the frame
rate.

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

PerformanceTests/Animometer/resources/debug-runner/graph.js
PerformanceTests/Animometer/resources/runner/animometer.js
PerformanceTests/Animometer/resources/strings.js
PerformanceTests/Animometer/tests/resources/main.js
PerformanceTests/ChangeLog

index c33ae2a..46564f0 100644 (file)
@@ -17,7 +17,7 @@ Utilities.extendObject(window.benchmarkController, {
                 .attr("transform", "translate(" + margins.left + "," + margins.top + ")");
 
         var axes = graphData.axes;
-        var targetFPS = graphData.targetFPS;
+        var targetFrameLength = graphData.targetFrameLength;
 
         // Axis scales
         var x = d3.scale.linear()
@@ -28,7 +28,7 @@ Utilities.extendObject(window.benchmarkController, {
                 .domain([0, d3.max(graphData.samples, function(s) { return s.complexity; })]);
         var yRight = d3.scale.linear()
                 .range([size.height, 0])
-                .domain([0, 60]);
+                .domain([1000/20, 1000/60]);
 
         // Axes
         var xAxis = d3.svg.axis()
@@ -40,6 +40,8 @@ Utilities.extendObject(window.benchmarkController, {
                 .orient("left");
         var yAxisRight = d3.svg.axis()
                 .scale(yRight)
+                .tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60])
+                .tickFormat(function(d) { return (1000/d).toFixed(0); })
                 .orient("right");
 
         // x-axis
@@ -123,12 +125,12 @@ Utilities.extendObject(window.benchmarkController, {
             .attr("class", "right-mean mean");
 
         // right-target
-        if (targetFPS) {
+        if (targetFrameLength) {
             svg.append("line")
                 .attr("x1", x(0))
                 .attr("x2", size.width)
-                .attr("y1", yRight(targetFPS))
-                .attr("y2", yRight(targetFPS))
+                .attr("y1", yRight(targetFrameLength))
+                .attr("y2", yRight(targetFrameLength))
                 .attr("class", "target-fps marker");
         }
 
@@ -143,7 +145,7 @@ Utilities.extendObject(window.benchmarkController, {
         // Data
         var allData = graphData.samples;
         var filteredData = graphData.samples.filter(function (sample) {
-            return "smoothedFPS" in sample;
+            return "smoothedFrameLength" in sample;
         });
 
         function addData(name, data, yCoordinateCallback, pointRadius, omitLine) {
@@ -169,8 +171,8 @@ Utilities.extendObject(window.benchmarkController, {
         }
 
         addData("complexity", allData, function(d) { return yLeft(d.complexity); }, 2);
-        addData("rawFPS", allData, function(d) { return yRight(d.fps); }, 1);
-        addData("filteredFPS", filteredData, function(d) { return yRight(d.smoothedFPS); }, 2);
+        addData("rawFPS", allData, function(d) { return yRight(d.frameLength); }, 1);
+        addData("filteredFPS", filteredData, function(d) { return yRight(d.smoothedFrameLength); }, 2);
 
         // Area to handle mouse events
         var area = svg.append("rect")
@@ -196,12 +198,7 @@ Utilities.extendObject(window.benchmarkController, {
             var data = allData[index];
             var cursor_x = x(data.time);
             var cursor_y = yAxisRight.scale().domain()[1];
-            if (form["rawFPS"].checked)
-                cursor_y = Math.max(cursor_y, data.fps);
-            cursorGroup.select("line")
-                .attr("x1", cursor_x)
-                .attr("x2", cursor_x)
-                .attr("y2", yRight(cursor_y));
+            var ys = [yRight(yAxisRight.scale().domain()[0]), yRight(yAxisRight.scale().domain()[1])];
 
             document.querySelector("#test-graph nav .time").textContent = (data.time / 1000).toFixed(4) + "s (" + index + ")";
             statsToHighlight.forEach(function(name) {
@@ -214,13 +211,13 @@ Utilities.extendObject(window.benchmarkController, {
                     data_y = yLeft(data.complexity);
                     break;
                 case "rawFPS":
-                    content = data.fps.toFixed(2);
-                    data_y = yRight(data.fps);
+                    content = (1000/data.frameLength).toFixed(2);
+                    data_y = yRight(data.frameLength);
                     break;
                 case "filteredFPS":
-                    if ("smoothedFPS" in data) {
-                        content = data.smoothedFPS.toFixed(2);
-                        data_y = yRight(data.smoothedFPS);
+                    if ("smoothedFrameLength" in data) {
+                        content = (1000/data.smoothedFrameLength).toFixed(2);
+                        data_y = yRight(data.smoothedFrameLength);
                     }
                     break;
                 }
@@ -228,6 +225,7 @@ Utilities.extendObject(window.benchmarkController, {
                 element.textContent = content;
 
                 if (form[name].checked && data_y !== null) {
+                    ys.push(data_y);
                     cursorGroup.select("." + name)
                         .attr("cx", cursor_x)
                         .attr("cy", data_y);
@@ -235,6 +233,15 @@ Utilities.extendObject(window.benchmarkController, {
                 } else
                     document.querySelector("#cursor ." + name).classList.add("hidden");
             });
+
+            if (form["rawFPS"].checked)
+                cursor_y = Math.max(cursor_y, data.frameLength);
+            cursorGroup.select("line")
+                .attr("x1", cursor_x)
+                .attr("x2", cursor_x)
+                .attr("y1", Math.min.apply(null, ys))
+                .attr("y2", Math.max.apply(null, ys));
+
         });
         this.onGraphOptionsChanged();
     },
index 74c596b..fda3468 100644 (file)
@@ -123,13 +123,13 @@ ResultsTable = Utilities.createClass(
                 axes: [Strings.text.experiments.complexity, Strings.text.experiments.frameRate],
                 mean: [
                     testResults[Strings.json.experiments.complexity][Strings.json.measurements.average],
-                    testResults[Strings.json.experiments.frameRate][Strings.json.measurements.average]
+                    1000 / testResults[Strings.json.experiments.frameRate][Strings.json.measurements.average]
                 ],
                 samples: data,
                 marks: testResults[Strings.json.marks]
             }
-            if (testResults[Strings.json.targetFPS])
-                graphData.targetFPS = testResults[Strings.json.targetFPS];
+            if (testResults[Strings.json.targetFrameLength])
+                graphData.targetFrameLength = testResults[Strings.json.targetFrameLength];
             benchmarkController.showTestGraph(testName, score, mean, graphData);
         });
 
index e8ad5e9..f9ebf67 100644 (file)
@@ -27,8 +27,9 @@ var Strings = {
         samples: "samples",
         marks: "marks",
 
-        targetFPS: "targetFPS",
-        samplingTimeOffset: "samplingTimeOffset",
+        targetFrameLength: "targetFrameLength",
+        samplingStartTimeOffset: "Start sampling",
+        samplingEndTimeOffset: "End sampling",
 
         experiments: {
             complexity: "complexity",
index 96166a4..74624f1 100644 (file)
@@ -23,7 +23,7 @@ Controller = Utilities.createClass(
     recordFirstSample: function(stage, startTimestamp)
     {
         this._sampler.record(startTimestamp, stage.complexity(), -1);
-        this.mark(Strings.json.samplingTimeOffset, startTimestamp);
+        this.mark(Strings.json.samplingStartTimeOffset, startTimestamp);
     },
 
     mark: function(comment, timestamp, data) {
@@ -40,7 +40,7 @@ Controller = Utilities.createClass(
     update: function(stage, timestamp)
     {
         this._estimator.sample(timestamp - this._sampler.samples[0][this._sampler.sampleCount - 1]);
-        this._sampler.record(timestamp, stage.complexity(), 1000 / this._estimator.estimate);
+        this._sampler.record(timestamp, stage.complexity(), this._estimator.estimate);
     },
 
     shouldStop: function(timestamp)
@@ -56,16 +56,15 @@ Controller = Utilities.createClass(
     processSamples: function(results)
     {
         var complexityExperiment = new Experiment;
-        var smoothedFPSExperiment = new Experiment;
+        var smoothedFrameLengthExperiment = new Experiment;
 
         var samples = this._sampler.samples;
 
-        var samplingIndex = 0;
-        var samplingMark = this._marks[Strings.json.samplingTimeOffset];
-        if (samplingMark) {
-            samplingIndex = samplingMark.index;
-            results[Strings.json.samplingTimeOffset] = samplingMark.time;
-        }
+        var samplingStartIndex = 0, samplingEndIndex = -1;
+        if (Strings.json.samplingStartTimeOffset in this._marks)
+            samplingStartIndex = this._marks[Strings.json.samplingStartTimeOffset].index;
+        if (Strings.json.samplingEndTimeOffset in this._marks)
+            samplingEndIndex = this._marks[Strings.json.samplingEndTimeOffset].index;
 
         for (var markName in this._marks)
             this._marks[markName].time -= this._startTimestamp;
@@ -73,25 +72,24 @@ Controller = Utilities.createClass(
 
         results[Strings.json.samples] = samples[0].map(function(timestamp, i) {
             var result = {
-                // Represent time in seconds
+                // Represent time in milliseconds
                 time: timestamp - this._startTimestamp,
                 complexity: samples[1][i]
             };
 
-            // time offsets represented as FPS
             if (i == 0)
-                result.fps = 60;
+                result.frameLength = 1000/60;
             else
-                result.fps = 1000 / (timestamp - samples[0][i - 1]);
+                result.frameLength = timestamp - samples[0][i - 1];
 
             if (samples[2][i] != -1)
-                result.smoothedFPS = samples[2][i];
+                result.smoothedFrameLength = samples[2][i];
 
             // Don't start adding data to the experiments until we reach the sampling timestamp
-            if (i >= samplingIndex) {
+            if (i >= samplingStartIndex && (samplingEndIndex == -1 || i < samplingEndIndex)) {
                 complexityExperiment.sample(result.complexity);
-                if (result.smoothedFPS && result.smoothedFPS != -1)
-                    smoothedFPSExperiment.sample(result.smoothedFPS);
+                if (result.smoothedFrameLength && result.smoothedFrameLength != -1)
+                    smoothedFrameLengthExperiment.sample(result.smoothedFrameLength);
             }
 
             return result;
@@ -106,12 +104,12 @@ Controller = Utilities.createClass(
         complexityResults[Strings.json.measurements.stdev] = complexityExperiment.standardDeviation();
         complexityResults[Strings.json.measurements.percent] = complexityExperiment.percentage();
 
-        var smoothedFPSResults = {};
-        results[Strings.json.experiments.frameRate] = smoothedFPSResults;
-        smoothedFPSResults[Strings.json.measurements.average] = smoothedFPSExperiment.mean();
-        smoothedFPSResults[Strings.json.measurements.concern] = smoothedFPSExperiment.concern(Experiment.defaults.CONCERN);
-        smoothedFPSResults[Strings.json.measurements.stdev] = smoothedFPSExperiment.standardDeviation();
-        smoothedFPSResults[Strings.json.measurements.percent] = smoothedFPSExperiment.percentage();
+        var smoothedFrameLengthResults = {};
+        results[Strings.json.experiments.frameRate] = smoothedFrameLengthResults;
+        smoothedFrameLengthResults[Strings.json.measurements.average] = 1000 / smoothedFrameLengthExperiment.mean();
+        smoothedFrameLengthResults[Strings.json.measurements.concern] = smoothedFrameLengthExperiment.concern(Experiment.defaults.CONCERN);
+        smoothedFrameLengthResults[Strings.json.measurements.stdev] = smoothedFrameLengthExperiment.standardDeviation();
+        smoothedFrameLengthResults[Strings.json.measurements.percent] = smoothedFrameLengthExperiment.percentage();
     }
 });
 
@@ -156,7 +154,7 @@ AdaptiveController = Utilities.createSubclass(Controller,
     {
         if (!this._startedSampling && timestamp > this._samplingTimestamp) {
             this._startedSampling = true;
-            this.mark(Strings.json.samplingTimeOffset, this._samplingTimestamp);
+            this.mark(Strings.json.samplingStartTimeOffset, this._samplingTimestamp);
         }
 
         // Start the work for the next frame.
@@ -175,7 +173,7 @@ AdaptiveController = Utilities.createSubclass(Controller,
         tuneValue = tuneValue > 0 ? Math.floor(tuneValue) : Math.ceil(tuneValue);
         stage.tune(tuneValue);
 
-        this._sampler.record(timestamp, stage.complexity(), intervalEstimatedFrameRate);
+        this._sampler.record(timestamp, stage.complexity(), this._estimator.estimate);
 
         // Start the next interval.
         this._intervalFrameCount = 0;
@@ -185,7 +183,7 @@ AdaptiveController = Utilities.createSubclass(Controller,
     processSamples: function(results)
     {
         Controller.prototype.processSamples.call(this, results);
-        results[Strings.json.targetFPS] = this._targetFrameRate;
+        results[Strings.json.targetFrameLength] = 1000 / this._targetFrameRate;
     }
 });
 
index 2f05023..4a8956f 100644 (file)
@@ -1,5 +1,27 @@
 2016-02-07  Jon Lee  <jonlee@apple.com>
 
+        Adjust the FPS graph scale.
+
+        Instead of making the FPS graph linearly scale, scale it based on the frame length,
+        but show the data in terms of FPS. Because it is inversely proportional, and most
+        of the data never gets below 20, concentrate the axis from 20-60 FPS, since otherwise
+        over half of the available graph space ends up blank.
+
+        This means we should convert all of the FPS data to frame length data.
+
+        * Animometer/resources/debug-runner/graph.js: Update the domain to be based on
+        frame length in milliseconds instead of FPS. Update the cursor to consider all of the
+        values being shown, and then pick the min and max values to represent the length of the
+        cursor.
+        * Animometer/resources/runner/animometer.js:
+        * Animometer/resources/strings.js:
+        * Animometer/tests/resources/main.js:
+        (processSamples): Add the ability to only sample a range of the data instead of everything
+        after an offset index. Update sampler to record the frame lengths instead of the frame
+        rate.
+
+2016-02-07  Jon Lee  <jonlee@apple.com>
+
         Add option to use different methods for retrieving a timestamp.
 
         * Animometer/developer.html: Add performance.now and Date.now options.