Skip to content

Commit 85ca394

Browse files
grorgsmfr
authored andcommitted
Support non-60 frame rates in MotionMark
https://bugs.webkit.org/show_bug.cgi?id=244656 <rdar://problem/99416135> Reviewed by Said Abou-Hallawa. Some devices have refresh rates that are not 60fps (like ProMotion @ 120Hz), and run requestAnimationFrame at that speed. Update MotionMark so that: - it doesn't hard-code 60fps everywhere - it attempts to detect the system frame rate - the results make it clear what frame rate the tests were using * PerformanceTests/MotionMark/developer.html: Add the system frame rate and some related text. * PerformanceTests/MotionMark/resources/debug-runner/graph.js: Get the graphing component to read the frame rate provided by the results. (updateGraphData): (createComplexityGraph): (onGraphTypeChanged): * PerformanceTests/MotionMark/resources/debug-runner/motionmark.css: (#frame-rate-detection span): Make this red when we're in progress. * PerformanceTests/MotionMark/resources/debug-runner/motionmark.js: Detect the system frame rate. * PerformanceTests/MotionMark/resources/runner/motionmark.css: (section .body p): This text got longer, so give it a max-width. * PerformanceTests/MotionMark/resources/runner/motionmark.js: Add support for variable frame rates where necessary. * PerformanceTests/MotionMark/resources/statistics.js: Ditto. * PerformanceTests/MotionMark/resources/strings.js: Add a new string. * PerformanceTests/MotionMark/tests/resources/main.js: Support for variable rates. [Note that this doesn't enable auto framerate detection when not running from developer.html] Canonical link: https://commits.webkit.org/254133@main
1 parent f5d127c commit 85ca394

File tree

10 files changed

+109
-34
lines changed

10 files changed

+109
-34
lines changed

MotionMark/about.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ <h1>About MotionMark <span class="version"></span></h1>
7373
<h3>Version log</h3>
7474

7575
<ul id="log">
76+
<li><strong>1.3</strong>: Add support for non-60Hz <code>requestAnimationFrame</code> rates to the <a href="developer.html">developer settings</a>.</li>
7677
<li><strong>1.2</strong>: Fix <a href="https://bugs.webkit.org/show_bug.cgi?id=220847">bug</a>, <a href="https://bugs.webkit.org/show_bug.cgi?id=221075">bug</a>, and <a href="https://bugs.webkit.org/show_bug.cgi?id=219984">bug</a> to reduce test variance and sensitivity to individual long frames.</li>
7778
<li><strong>1.1.1</strong>: Fix <a href="https://bugs.webkit.org/show_bug.cgi?id=210640">bug</a> in the calculation of timestamps used for animation during warm up phase of tests.</li>
7879
<li><a href="https://webkit.org/blog/8434/motionmark-1-1/"><strong>1.1</strong></a>: Update Multiply test to increase max capacity and expand methods for hiding elements. Update Leaves test to use range of sizes and opacity.</li>

MotionMark/developer.html

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ <h3>Adjusting the test complexity:</h3>
9999
</ul>
100100
</li>
101101
<li>
102-
<label>Target frame rate: <input type="number" id="frame-rate" value="50"> FPS</label>
102+
<label>System frame rate: <input type="number" id="system-frame-rate" value="60"> FPS</label><br>
103+
<label>Target frame rate: <input type="number" id="frame-rate" value="50"> FPS</label><br>
104+
(Guide: should be about 5/6th of the system frame rate)
103105
</li>
104106
<li>
105107
<h3>Time measurement method:</h3>
@@ -113,7 +115,14 @@ <h3>Time measurement method:</h3>
113115
</form>
114116
</div>
115117
</div>
116-
<p>For accurate results, please take the browser window full screen, or rotate the device to landscape orientation.</p>
118+
<p>
119+
For accurate results, please take the browser window full screen, or rotate the device to landscape orientation. Also,
120+
ensure that the target frame rate matches your system frame rate. Results cannot be compared between devices that
121+
use different frame rates.
122+
</p>
123+
<p id="frame-rate-detection">
124+
Attempting to detect system frame rate: <span>0</span> FPS (in progress).
125+
</p>
117126
<div class="start-benchmark">
118127
<p class="hidden">Please rotate the device to orientation before starting.</p>
119128
<button id="run-benchmark" onclick="benchmarkController.startBenchmark()">Run benchmark</button>

MotionMark/resources/debug-runner/graph.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Utilities.extendObject(window.benchmarkController, {
4242
samplesWithProperties[seriesName] = series.toArray();
4343
})
4444

45+
this._targetFrameRate = options["frame-rate"] || 60;
46+
4547
this.createTimeGraph(testResult, samplesWithProperties[Strings.json.controller], testData[Strings.json.marks], testData[Strings.json.controller], options, margins, size);
4648
this.onTimeGraphOptionsChanged();
4749

@@ -127,14 +129,14 @@ Utilities.extendObject(window.benchmarkController, {
127129
.domain([xMin, xMax]);
128130
var yScale = d3.scale.linear()
129131
.range([size.height, 0])
130-
.domain([1000/20, 1000/60]);
132+
.domain([1000/(this._targetFrameRate/3), 1000/this._targetFrameRate]);
131133

132134
var xAxis = d3.svg.axis()
133135
.scale(xScale)
134136
.orient("bottom");
135137
var yAxis = d3.svg.axis()
136138
.scale(yScale)
137-
.tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60])
139+
.tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60, 1000/90, 1000/120])
138140
.tickFormat(function(d) { return (1000 / d).toFixed(0); })
139141
.orient("left");
140142

@@ -284,7 +286,7 @@ Utilities.extendObject(window.benchmarkController, {
284286
.domain([0, complexityMax]);
285287
var yRight = d3.scale.linear()
286288
.range([size.height, 0])
287-
.domain([1000/20, 1000/60]);
289+
.domain([1000/(this._targetFrameRate/3), 1000/this._targetFrameRate]);
288290

289291
// Axes
290292
var xAxis = d3.svg.axis()
@@ -296,7 +298,7 @@ Utilities.extendObject(window.benchmarkController, {
296298
.orient("left");
297299
var yAxisRight = d3.svg.axis()
298300
.scale(yRight)
299-
.tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60])
301+
.tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60, 1000/90, 1000/120])
300302
.tickFormat(function(d) { return (1000/d).toFixed(0); })
301303
.orient("right");
302304

@@ -623,6 +625,6 @@ Utilities.extendObject(window.benchmarkController, {
623625
}
624626
}
625627

626-
sectionsManager.setSectionScore("test-graph", score, mean);
628+
sectionsManager.setSectionScore("test-graph", score, mean, this._targetFrameRate);
627629
}
628630
});

MotionMark/resources/debug-runner/motionmark.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ label.tree-label {
331331
color: hsl(11, 100%, 66%);
332332
}
333333

334+
#frame-rate-detection span {
335+
color: red;
336+
}
337+
334338
@media screen and (max-device-width: 414px),
335339
screen and (max-device-height: 414px) and (orientation: landscape) {
336340
#intro .body > div:first-of-type {

MotionMark/resources/debug-runner/motionmark.js

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,8 @@ Utilities.extendObject(window.benchmarkController, {
553553
suitesManager.updateUIFromLocalStorage();
554554
suitesManager.updateEditsElementsState();
555555

556+
benchmarkController.detectSystemFrameRate();
557+
556558
var dropTarget = document.getElementById("drop-target");
557559
function stopEvent(e) {
558560
e.stopPropagation();
@@ -664,8 +666,9 @@ Utilities.extendObject(window.benchmarkController, {
664666
var score = dashboard.score;
665667
var confidence = ((dashboard.scoreLowerBound / score - 1) * 100).toFixed(2) +
666668
"% / +" + ((dashboard.scoreUpperBound / score - 1) * 100).toFixed(2) + "%";
669+
var fps = dashboard._systemFrameRate;
667670
sectionsManager.setSectionVersion("results", dashboard.version);
668-
sectionsManager.setSectionScore("results", score.toFixed(2), confidence);
671+
sectionsManager.setSectionScore("results", score.toFixed(2), confidence, fps);
669672
sectionsManager.populateTable("results-header", Headers.testName, dashboard);
670673
sectionsManager.populateTable("results-score", Headers.score, dashboard);
671674
sectionsManager.populateTable("results-data", Headers.details, dashboard);
@@ -679,5 +682,47 @@ Utilities.extendObject(window.benchmarkController, {
679682
sectionsManager.setSectionHeader("test-graph", testName);
680683
sectionsManager.showSection("test-graph", true);
681684
this.updateGraphData(testResult, testData, benchmarkRunnerClient.results.options);
685+
},
686+
detectSystemFrameRate: function()
687+
{
688+
let last = 0;
689+
let average = 0;
690+
let count = 0;
691+
692+
const finish = function()
693+
{
694+
const commonFrameRates = [15, 30, 45, 60, 90, 120, 144];
695+
const distanceFromFrameRates = commonFrameRates.map(rate => {
696+
return Math.abs(Math.round(rate - average));
697+
});
698+
let shortestDistance = Number.MAX_VALUE;
699+
let targetFrameRate = undefined;
700+
for (let i = 0; i < commonFrameRates.length; i++) {
701+
if (distanceFromFrameRates[i] < shortestDistance) {
702+
targetFrameRate = commonFrameRates[i];
703+
shortestDistance = distanceFromFrameRates[i];
704+
}
705+
}
706+
targetFrameRate = targetFrameRate || 60;
707+
document.getElementById("frame-rate-detection").textContent = `Detected system frame rate as ${targetFrameRate} FPS`;
708+
document.getElementById("system-frame-rate").value = targetFrameRate;
709+
document.getElementById("frame-rate").value = Math.round(targetFrameRate * 5 / 6);
710+
}
711+
712+
const tick = function(timestamp)
713+
{
714+
average -= average / 30;
715+
average += 1000. / (timestamp - last) / 30;
716+
document.querySelector("#frame-rate-detection span").textContent = Math.round(average);
717+
last = timestamp;
718+
count++;
719+
if (count < 300)
720+
requestAnimationFrame(tick);
721+
else
722+
finish();
723+
}
724+
725+
requestAnimationFrame(tick);
682726
}
727+
683728
});

MotionMark/resources/runner/motionmark.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ section .body {
145145
section .body p {
146146
margin: 1em 0;
147147
line-height: 1.5em;
148+
max-width: 60vw;
148149

149150
-webkit-user-select: text;
150151
cursor: text;

MotionMark/resources/runner/motionmark.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
this._options = options;
3030
this._results = null;
3131
this._version = version;
32+
this._targetFrameRate = options["frame-rate"] || 60;
33+
this._systemFrameRate = options["system-frame-rate"] || 60;
3234
if (testData) {
3335
this._iterationsSamplers = testData;
3436
this._processData();
@@ -83,6 +85,7 @@
8385
}, this);
8486

8587
this._results[Strings.json.version] = this._version;
88+
this._results[Strings.json.fps] = this._targetFrameRate;
8689
this._results[Strings.json.score] = Statistics.sampleMean(iterationsScores.length, iterationsScores.reduce(function(a, b) { return a + b; }));
8790
this._results[Strings.json.scoreLowerBound] = this._results[Strings.json.results.iterations][0][Strings.json.scoreLowerBound];
8891
this._results[Strings.json.scoreUpperBound] = this._results[Strings.json.results.iterations][0][Strings.json.scoreUpperBound];
@@ -109,7 +112,7 @@
109112

110113
var complexityIndex = series.fieldMap[Strings.json.complexity];
111114
var frameLengthIndex = series.fieldMap[Strings.json.frameLength];
112-
var regressionOptions = { desiredFrameLength: 1000/60 };
115+
var regressionOptions = { desiredFrameLength: 1000/this._targetFrameRate };
113116
if (profile)
114117
regressionOptions.preferredProfile = profile;
115118
return {
@@ -165,6 +168,8 @@
165168
result[Strings.json.complexity][Strings.json.complexity] = calculation.complexity;
166169
result[Strings.json.complexity][Strings.json.measurements.stdev] = Math.sqrt(calculation.error / samples[Strings.json.complexity].length);
167170

171+
result[Strings.json.fps] = data.targetFPS || 60;
172+
168173
if (isRampController) {
169174
var timeComplexity = new Experiment;
170175
data[Strings.json.controller].forEach(function(regression) {
@@ -442,9 +447,10 @@ window.sectionsManager =
442447
document.querySelector("#" + sectionIdentifier + " .version").textContent = version;
443448
},
444449

445-
setSectionScore: function(sectionIdentifier, score, confidence)
450+
setSectionScore: function(sectionIdentifier, score, confidence, fps)
446451
{
447-
document.querySelector("#" + sectionIdentifier + " .score").textContent = score;
452+
if (fps && score)
453+
document.querySelector("#" + sectionIdentifier + " .score").textContent = `${score} @ ${fps}fps`;
448454
if (confidence)
449455
document.querySelector("#" + sectionIdentifier + " .confidence").textContent = confidence;
450456
},
@@ -557,8 +563,9 @@ window.benchmarkController = {
557563
var dashboard = benchmarkRunnerClient.results;
558564
var score = dashboard.score;
559565
var confidence = "±" + (Statistics.largestDeviationPercentage(dashboard.scoreLowerBound, score, dashboard.scoreUpperBound) * 100).toFixed(2) + "%";
566+
var fps = dashboard._systemFrameRate;
560567
sectionsManager.setSectionVersion("results", dashboard.version);
561-
sectionsManager.setSectionScore("results", score.toFixed(2), confidence);
568+
sectionsManager.setSectionScore("results", score.toFixed(2), confidence, fps);
562569
sectionsManager.populateTable("results-header", Headers.testName, dashboard);
563570
sectionsManager.populateTable("results-score", Headers.score, dashboard);
564571
sectionsManager.populateTable("results-data", Headers.details, dashboard);
@@ -658,3 +665,4 @@ window.benchmarkController = {
658665
};
659666

660667
window.addEventListener("load", function() { benchmarkController.initialize(); });
668+

MotionMark/resources/statistics.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ Experiment.defaults =
179179
Regression = Utilities.createClass(
180180
function(samples, getComplexity, getFrameLength, startIndex, endIndex, options)
181181
{
182-
var desiredFrameLength = options.desiredFrameLength || 1000/60;
182+
var targetFrameRate = options["frame-rate"] || 60;
183+
var desiredFrameLength = options.desiredFrameLength || 1000/targetFrameRate;
183184
var bestProfile;
184185

185186
if (!options.preferredProfile || options.preferredProfile == Strings.json.profiles.slope) {

MotionMark/resources/strings.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ var Strings = {
4949
score: "score",
5050
scoreLowerBound: "scoreLowerBound",
5151
scoreUpperBound: "scoreUpperBound",
52+
fps: "fps",
5253
bootstrap: "bootstrap",
5354
measurements: {
5455
average: "average",

0 commit comments

Comments
 (0)