Skip to content

Commit 135a092

Browse files
committed
Fix the graph display
This change fixes various issues in the graph display. First, the graphs overflowed the page and triggered scrolling. Fix by using flex layout for `#test-graph .body`, with a fixed-height header, and a flexible `#test-graph-data` element. Graph layout uses getBoundingClientRect() on that lower box, using the result to size the SVG. To make this work, the header has to have the final height, so pre-fill header fields with a non-breaking space so they have height before they get the actual values (which happens after graph building). Second, the graphs were hardcoded for 60fps. Make them scale for other frame rates, supplying some reasonable set of axis labels for common frame rates, and computing a set otherwise.
1 parent 9aff631 commit 135a092

File tree

3 files changed

+121
-47
lines changed

3 files changed

+121
-47
lines changed

MotionMark/developer.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ <h1>MotionMark score</h1>
167167
<header>
168168
<button onclick="benchmarkController.showResults()">&lt; Results</button>
169169
<h1>Graph:</h1>
170-
<p class="score"></p>
171-
<p class="confidence"></p>
170+
<p class="score">&nbsp;</p>
171+
<p class="confidence">&nbsp;</p>
172172
</header>
173173
<nav>
174174
<form name="graph-type">

MotionMark/resources/debug-runner/graph.js

Lines changed: 96 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2323
* THE POSSIBILITY OF SUCH DAMAGE.
2424
*/
25+
26+
const msPerSecond = 1000;
27+
2528
Utilities.extendObject(window.benchmarkController, {
2629
updateGraphData: function(testResult, testData, options)
2730
{
@@ -30,10 +33,11 @@ Utilities.extendObject(window.benchmarkController, {
3033
element._testResult = testResult;
3134
element._options = options;
3235

33-
var margins = new Insets(30, 30, 30, 40);
36+
// top, right, bottom, left.
37+
var margins = new Insets(30, 30, 50, 40);
38+
// Note that changes to header content (in onGraphTypeChanged()) can change the available size, so we prepopulate
39+
// "score" and "confidence" elements with non-breaking spaces in the HTML.
3440
var size = Point.elementClientSize(element);
35-
size.y = window.innerHeight - element.offsetTop;
36-
size = size.subtract(margins.size);
3741

3842
// Convert from compact JSON output to propertied data
3943
var samplesWithProperties = {};
@@ -98,14 +102,43 @@ Utilities.extendObject(window.benchmarkController, {
98102
this._addRegressionLine(svg, xScale, yScale, data.segment1, data.stdev);
99103
this._addRegressionLine(svg, xScale, yScale, data.segment2, data.stdev);
100104
},
105+
106+
_tickValuesForFrameRate: function(frameRate, minValue, maxValue)
107+
{
108+
// Tick labels go up to 1.5x frame rate
109+
const buildInFrameRates = {
110+
15 : [5, 10, 15, 20],
111+
30 : [5, 10, 15, 20, 25, 30, 35, 40],
112+
45 : [30, 35, 40, 45, 50, 55, 60],
113+
60 : [30, 35, 40, 45, 50, 55, 60, 90],
114+
90 : [30, 35, 40, 45, 50, 55, 60, 90, 120],
115+
120 : [30, 40, 50, 60, 70, 80, 100, 120, 150],
116+
144 : [40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 200],
117+
};
118+
119+
let tickValues = buildInFrameRates[frameRate];
120+
if (!tickValues) {
121+
const minLabel = Math.round(minValue / 10) * 10;
122+
const maxLabel = Math.round(maxValue / 10) * 10;
123+
tickValues = [];
124+
let curValue = minLabel;
125+
while (curValue <= maxLabel) {
126+
tickValues.push(curValue);
127+
curValue += 20;
128+
}
129+
}
130+
131+
tickValues = tickValues.map((x) => msPerSecond / x);
132+
return tickValues;
133+
},
101134

102135
createComplexityGraph: function(result, timeRegressions, data, options, margins, size)
103136
{
104137
var svg = d3.select("#test-graph-data").append("svg")
105138
.attr("id", "complexity-graph")
106139
.attr("class", "hidden")
107-
.attr("width", size.width + margins.left + margins.right)
108-
.attr("height", size.height + margins.top + margins.bottom)
140+
.attr("width", size.width)
141+
.attr("height", size.height)
109142
.append("g")
110143
.attr("transform", "translate(" + margins.left + "," + margins.top + ")");
111144

@@ -124,38 +157,47 @@ Utilities.extendObject(window.benchmarkController, {
124157
xMax = d3.max(timeSamples, function(s) { return s.complexity; });
125158
}
126159

160+
const axisWidth = size.width - margins.left - margins.right;
161+
const axisHeight = size.height - margins.top - margins.bottom;
162+
163+
// The y axis is frameLength in ms, inverted with the axis labels showing fps.
164+
const minFrameRate = this._targetFrameRate / 4;
165+
const maxFrameRate = this._targetFrameRate * 1.5;
166+
167+
const yMin = msPerSecond / minFrameRate;
168+
const yMax = msPerSecond / maxFrameRate;
169+
127170
var xScale = d3.scale.linear()
128-
.range([0, size.width])
171+
.range([0, axisWidth])
129172
.domain([xMin, xMax]);
130173
var yScale = d3.scale.linear()
131-
.range([size.height, 0])
132-
.domain([1000/(this._targetFrameRate/3), 1000/this._targetFrameRate]);
174+
.range([axisHeight, 0])
175+
.domain([yMin, yMax]);
133176

134177
var xAxis = d3.svg.axis()
135178
.scale(xScale)
136179
.orient("bottom");
137180
var yAxis = d3.svg.axis()
138181
.scale(yScale)
139-
.tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60, 1000/90, 1000/120])
140-
.tickFormat(function(d) { return (1000 / d).toFixed(0); })
182+
.tickValues(this._tickValuesForFrameRate(this._targetFrameRate, minFrameRate, maxFrameRate))
183+
.tickFormat(function(d) { return (msPerSecond / d).toFixed(0); })
141184
.orient("left");
142185

143186
// x-axis
144187
svg.append("g")
145188
.attr("class", "x axis")
146-
.attr("transform", "translate(0," + size.height + ")")
189+
.attr("transform", "translate(0," + axisHeight + ")")
147190
.call(xAxis);
148191

149192
// y-axis
150-
svg.append("g")
193+
var yAxisGroup = svg.append("g")
151194
.attr("class", "y axis")
152195
.call(yAxis);
153196

154197
// time result
155198
var mean = svg.append("g")
156199
.attr("class", "mean complexity");
157200
var timeResult = result[Strings.json.controller];
158-
var yMin = yScale.domain()[0], yMax = yScale.domain()[1];
159201
this._addRegressionLine(mean, xScale, yScale, [[timeResult.average, yMin], [timeResult.average, yMax]], timeResult.stdev, true);
160202

161203
// regression
@@ -166,7 +208,7 @@ Utilities.extendObject(window.benchmarkController, {
166208
var histogram = d3.layout.histogram()
167209
.bins(xScale.ticks(100))(bootstrapResult.data);
168210
var yBootstrapScale = d3.scale.linear()
169-
.range([size.height/2, 0])
211+
.range([axisHeight/2, 0])
170212
.domain([0, d3.max(histogram, function(d) { return d.y; })]);
171213
group = svg.append("g").attr("class", "bootstrap");
172214
var bar = group.selectAll(".bar")
@@ -176,14 +218,14 @@ Utilities.extendObject(window.benchmarkController, {
176218
.attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yBootstrapScale(d.y) + ")"; });
177219
bar.append("rect")
178220
.attr("x", 1)
179-
.attr("y", size.height/2)
221+
.attr("y", axisHeight/2)
180222
.attr("width", xScale(histogram[1].x) - xScale(histogram[0].x) - 1)
181-
.attr("height", function(d) { return size.height/2 - yBootstrapScale(d.y); });
223+
.attr("height", function(d) { return axisHeight/2 - yBootstrapScale(d.y); });
182224
group = group.append("g").attr("class", "median");
183225
this._addRegressionLine(group, xScale, yScale, [[bootstrapResult.median, yMin], [bootstrapResult.median, yMax]], [bootstrapResult.confidenceLow, bootstrapResult.confidenceHigh], true);
184226
group.append("circle")
185227
.attr("cx", xScale(bootstrapResult.median))
186-
.attr("cy", yScale(1000/60))
228+
.attr("cy", yScale(msPerSecond / 60))
187229
.attr("r", 5);
188230
}
189231

@@ -193,7 +235,8 @@ Utilities.extendObject(window.benchmarkController, {
193235
.selectAll("line")
194236
.data(data[Strings.json.complexity])
195237
.enter();
196-
group.append("line")
238+
239+
group.append("line")
197240
.attr("x1", function(d) { return xScale(d.complexity) - 3; })
198241
.attr("x2", function(d) { return xScale(d.complexity) + 3; })
199242
.attr("y1", function(d) { return yScale(d.frameLength) - 3; })
@@ -236,7 +279,7 @@ Utilities.extendObject(window.benchmarkController, {
236279
.attr("x", 0)
237280
.attr("y", 0)
238281
.attr("width", size.width)
239-
.attr("height", size.height);
282+
.attr("height", axisHeight);
240283

241284
area.on("mouseover", function() {
242285
document.querySelector("#complexity-graph .cursor").classList.remove("hidden");
@@ -256,22 +299,25 @@ Utilities.extendObject(window.benchmarkController, {
256299
.attr("y2", location[1]);
257300
cursorGroup.select("text.y")
258301
.attr("y", location[1])
259-
.text((1000 / location_domain[1]).toFixed(1));
302+
.text((msPerSecond / location_domain[1]).toFixed(1));
260303
});
261304
},
262305

263306
createTimeGraph: function(result, samples, marks, regressions, options, margins, size)
264307
{
308+
const axisWidth = size.width - margins.left - margins.right;
309+
const axisHeight = size.height - margins.top - margins.bottom;
310+
265311
var svg = d3.select("#test-graph-data").append("svg")
266312
.attr("id", "time-graph")
267-
.attr("width", size.width + margins.left + margins.right)
268-
.attr("height", size.height + margins.top + margins.bottom)
313+
.attr("width", size.width)
314+
.attr("height", size.height)
269315
.append("g")
270316
.attr("transform", "translate(" + margins.left + "," + margins.top + ")");
271317

272318
// Axis scales
273319
var x = d3.scale.linear()
274-
.range([0, size.width])
320+
.range([0, axisWidth])
275321
.domain([
276322
Math.min(d3.min(samples, function(s) { return s.time; }), 0),
277323
d3.max(samples, function(s) { return s.time; })]);
@@ -280,37 +326,47 @@ Utilities.extendObject(window.benchmarkController, {
280326
return s.complexity;
281327
return 0;
282328
});
329+
complexityMax *= 1.2;
283330

331+
const graphTop = 10;
284332
var yLeft = d3.scale.linear()
285-
.range([size.height, 0])
333+
.range([axisHeight, graphTop])
286334
.domain([0, complexityMax]);
335+
336+
337+
const minFrameRate = this._targetFrameRate / 2;
338+
const maxFrameRate = this._targetFrameRate * 1.5;
339+
const yRightMin = msPerSecond / minFrameRate;
340+
const yRightMax = msPerSecond / maxFrameRate;
341+
287342
var yRight = d3.scale.linear()
288-
.range([size.height, 0])
289-
.domain([1000/(this._targetFrameRate/3), 1000/this._targetFrameRate]);
343+
.range([axisHeight, graphTop])
344+
.domain([yRightMin, yRightMax]);
290345

291346
// Axes
292347
var xAxis = d3.svg.axis()
293348
.scale(x)
294349
.orient("bottom")
295-
.tickFormat(function(d) { return (d/1000).toFixed(0); });
350+
.tickFormat(function(d) { return (d / msPerSecond).toFixed(0); });
296351
var yAxisLeft = d3.svg.axis()
297352
.scale(yLeft)
298353
.orient("left");
354+
299355
var yAxisRight = d3.svg.axis()
300356
.scale(yRight)
301-
.tickValues([1000/20, 1000/25, 1000/30, 1000/35, 1000/40, 1000/45, 1000/50, 1000/55, 1000/60, 1000/90, 1000/120])
302-
.tickFormat(function(d) { return (1000/d).toFixed(0); })
357+
.tickValues(this._tickValuesForFrameRate(this._targetFrameRate, minFrameRate, maxFrameRate))
358+
.tickFormat(function(d) { return (msPerSecond / d).toFixed(0); })
303359
.orient("right");
304360

305361
// x-axis
306362
svg.append("g")
307363
.attr("class", "x axis")
308364
.attr("fill", "rgb(235, 235, 235)")
309-
.attr("transform", "translate(0," + size.height + ")")
365+
.attr("transform", "translate(0," + axisHeight + ")")
310366
.call(xAxis)
311367
.append("text")
312368
.attr("class", "label")
313-
.attr("x", size.width)
369+
.attr("x", axisWidth)
314370
.attr("y", -6)
315371
.attr("fill", "rgb(235, 235, 235)")
316372
.style("text-anchor", "end")
@@ -334,7 +390,7 @@ Utilities.extendObject(window.benchmarkController, {
334390
svg.append("g")
335391
.attr("class", "yRight axis")
336392
.attr("fill", "#FA4925")
337-
.attr("transform", "translate(" + size.width + ", 0)")
393+
.attr("transform", "translate(" + axisWidth + ", 0)")
338394
.call(yAxisRight)
339395
.append("text")
340396
.attr("class", "label")
@@ -376,15 +432,15 @@ Utilities.extendObject(window.benchmarkController, {
376432
var frameLength = result[Strings.json.frameLength];
377433
var regression = svg.append("g")
378434
.attr("class", "fps mean");
379-
this._addRegressionLine(regression, x, yRight, [[samples[0].time, 1000/frameLength.average], [samples[samples.length - 1].time, 1000/frameLength.average]], frameLength.stdev);
435+
this._addRegressionLine(regression, x, yRight, [[samples[0].time, msPerSecond / frameLength.average], [samples[samples.length - 1].time, msPerSecond / frameLength.average]], frameLength.stdev);
380436
}
381437

382438
// right-target
383439
if (options["controller"] == "adaptive") {
384-
var targetFrameLength = 1000 / options["frame-rate"];
440+
var targetFrameLength = msPerSecond / options["frame-rate"];
385441
svg.append("line")
386442
.attr("x1", x(0))
387-
.attr("x2", size.width)
443+
.attr("x2", axisWidth)
388444
.attr("y1", yRight(targetFrameLength))
389445
.attr("y2", yRight(targetFrameLength))
390446
.attr("class", "target-fps marker");
@@ -485,8 +541,8 @@ Utilities.extendObject(window.benchmarkController, {
485541
.attr("fill", "transparent")
486542
.attr("x", 0)
487543
.attr("y", 0)
488-
.attr("width", size.width)
489-
.attr("height", size.height);
544+
.attr("width", axisWidth)
545+
.attr("height", axisHeight);
490546

491547
var timeBisect = d3.bisector(function(d) { return d.time; }).right;
492548
var statsToHighlight = ["complexity", "rawFPS", "filteredFPS"];
@@ -506,7 +562,7 @@ Utilities.extendObject(window.benchmarkController, {
506562
var cursor_y = yAxisRight.scale().domain()[1];
507563
var ys = [yRight(yAxisRight.scale().domain()[0]), yRight(yAxisRight.scale().domain()[1])];
508564

509-
document.querySelector("#test-graph nav .time").textContent = (data.time / 1000).toFixed(4) + "s (" + index + ")";
565+
document.querySelector("#test-graph nav .time").textContent = (data.time / msPerSecond).toFixed(4) + "s (" + index + ")";
510566
statsToHighlight.forEach(function(name) {
511567
var element = document.querySelector("#test-graph nav ." + name);
512568
var content = "";
@@ -517,12 +573,12 @@ Utilities.extendObject(window.benchmarkController, {
517573
data_y = yLeft(data.complexity);
518574
break;
519575
case "rawFPS":
520-
content = (1000/data.frameLength).toFixed(2);
576+
content = (msPerSecond / data.frameLength).toFixed(2);
521577
data_y = yRight(data.frameLength);
522578
break;
523579
case "filteredFPS":
524580
if ("smoothedFrameLength" in data) {
525-
content = (1000/data.smoothedFrameLength).toFixed(2);
581+
content = (msPerSecond / data.smoothedFrameLength).toFixed(2);
526582
data_y = yRight(data.smoothedFrameLength);
527583
}
528584
break;

MotionMark/resources/debug-runner/motionmark.css

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -570,10 +570,6 @@ body.showing-test-container.tiles-classic {
570570
flex-direction: row;
571571
}
572572

573-
#test-graph {
574-
flex: 1 0 calc(100% - 40px);
575-
}
576-
577573
#test-graph h1 {
578574
margin-bottom: 0;
579575
}
@@ -626,15 +622,37 @@ body.showing-test-container.tiles-classic {
626622
/* Graph Section */
627623
/* -------------------------------------------------------------------------- */
628624

625+
body.showing-test-graph {
626+
height: 100vh;
627+
}
628+
629+
body.showing-test-graph main, #test-graph {
630+
height: 100%;
631+
}
632+
633+
body.showing-test-graph header, body.showing-test-graph nav {
634+
flex-basis: auto;
635+
}
636+
637+
#test-graph .body {
638+
display: flex;
639+
flex-direction: column;
640+
margin-trim: block-start;
641+
margin: 1em;
642+
height: calc(100% - 2em);
643+
}
644+
629645
#test-graph-data {
646+
flex-grow: 1;
647+
min-height: 0;
630648
z-index: 1;
631649
font: 10px sans-serif;
632650
color: rgb(235, 235, 235);
633651
}
634652

635653
#test-graph-data > svg {
636654
fill: none;
637-
overflow: visible;
655+
/* overflow: hidden;*/
638656
}
639657

640658
.axis path,

0 commit comments

Comments
 (0)