Skip to content

Commit b5b5118

Browse files
committed
Eliminate 'async time' in StyleBench
https://bugs.webkit.org/show_bug.cgi?id=219785 Reviewed by Antti Koivisto. r270132 (a RunLoop change) measured as a 13% regression on the StyleBench bot. But I don't think the measured regression was user-real. Instead, I think the baseline score was artificially high because 'async time' sometimes did not measure painting. I decided just to eliminate 'async time' (and force style resolution + layout during 'sync time') because this benchmark intends to measure style resolution + layout, and not painting or frame rate. With this change, there is no measured regression anymore. Explanation of 'did not measure painting': StyleBench synchronously modifies DOM + style, and then sets a zero-delay timer to measure 'async time'. If layout has not happened by the time the timer fires, StyleBench forces layout and then computes 'async time'. The flaw here is painting. StyleBench accepts both of these orders of operations as valid: (A) { modify DOM + style }, { measure 'sync time' }, { style resolution + layout }, { paint }, { measure 'async time' } (B) { modify DOM + style }, { measure 'sync time' }, { style resolution + layout }, { measure 'async time' }, { paint } ^ (B) includes more stuff than (A). Not cool! Evidence for the theory that the baseline was sometimes doing (B): * Forcing style resolution + layout during sync time reduces the baseline score and eliminates the difference in async time between baseline and patch. * Starting the benchmark from a requestAnimationFrame() instead of a timer reduces the baseline score and eliminates the difference in async time between baseline and patch. * The regression only reproduced on machines with fewer cores. * The new benchmark method reduces sttdev by ~3X - ~5X. * StyleBench/resources/benchmark-runner.js: (BenchmarkRunner.prototype._runTest): Call getBoundingClientRect() during sync time to force style resolution + layout consistently. Always report async time as 1, since this benchmark doesn't have an async time component anymore. (The harness doesn't like zeroes.) Just store height in a global because that is sufficient to prevent dead code elimination (which was probably impossible anyway, since getBoundingClientRect() has side effects). Canonical link: https://commits.webkit.org/232347@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@270684 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent fa9e4d3 commit b5b5118

2 files changed

Lines changed: 63 additions & 8 deletions

File tree

PerformanceTests/ChangeLog

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,60 @@
1+
2020-12-11 Geoffrey Garen <ggaren@apple.com>
2+
3+
Eliminate 'async time' in StyleBench
4+
https://bugs.webkit.org/show_bug.cgi?id=219785
5+
6+
Reviewed by Antti Koivisto.
7+
8+
r270132 (a RunLoop change) measured as a 13% regression on the
9+
StyleBench bot. But I don't think the measured regression was user-real.
10+
Instead, I think the baseline score was artificially high because 'async
11+
time' sometimes did not measure painting.
12+
13+
I decided just to eliminate 'async time' (and force style resolution +
14+
layout during 'sync time') because this benchmark intends to measure
15+
style resolution + layout, and not painting or frame rate.
16+
17+
With this change, there is no measured regression anymore.
18+
19+
Explanation of 'did not measure painting':
20+
21+
StyleBench synchronously modifies DOM + style, and then sets a
22+
zero-delay timer to measure 'async time'. If layout has not
23+
happened by the time the timer fires, StyleBench forces layout
24+
and then computes 'async time'. The flaw here is painting.
25+
StyleBench accepts both of these orders of operations as valid:
26+
27+
(A) { modify DOM + style }, { measure 'sync time' }, { style resolution + layout }, { paint }, { measure 'async time' }
28+
29+
(B) { modify DOM + style }, { measure 'sync time' }, { style resolution + layout }, { measure 'async time' }, { paint }
30+
31+
^ (B) includes more stuff than (A). Not cool!
32+
33+
Evidence for the theory that the baseline was sometimes doing (B):
34+
35+
* Forcing style resolution + layout during sync time reduces the
36+
baseline score and eliminates the difference in async time
37+
between baseline and patch.
38+
39+
* Starting the benchmark from a requestAnimationFrame() instead
40+
of a timer reduces the baseline score and eliminates the
41+
difference in async time between baseline and patch.
42+
43+
* The regression only reproduced on machines with fewer cores.
44+
45+
* The new benchmark method reduces sttdev by ~3X - ~5X.
46+
47+
* StyleBench/resources/benchmark-runner.js:
48+
(BenchmarkRunner.prototype._runTest): Call getBoundingClientRect()
49+
during sync time to force style resolution + layout consistently.
50+
51+
Always report async time as 1, since this benchmark doesn't have an
52+
async time component anymore. (The harness doesn't like zeroes.)
53+
54+
Just store height in a global because that is sufficient to prevent
55+
dead code elimination (which was probably impossible anyway, since
56+
getBoundingClientRect() has side effects).
57+
158
2020-12-10 Tadeu Zagallo <tzagallo@apple.com>
259

360
Removing unnecessary locking from JSValue API functions

PerformanceTests/StyleBench/resources/benchmark-runner.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,22 +127,20 @@ BenchmarkRunner.prototype._runTest = function(suite, test, prepareReturnValue, c
127127
var contentDocument = self._frame.contentDocument;
128128

129129
self._writeMark(suite.name + '.' + test.name + '-start');
130+
130131
var startTime = now();
131132
test.run(prepareReturnValue, contentWindow, contentDocument);
133+
// Force style resolution + layout to ensure we're measuring it.
134+
window._unusedHeightValue = self._frame.contentDocument.body.getBoundingClientRect().height;
132135
var endTime = now();
136+
133137
self._writeMark(suite.name + '.' + test.name + '-sync-end');
134138

135139
var syncTime = endTime - startTime;
136-
137-
var startTime = now();
138140
setTimeout(function () {
139-
// Some browsers don't immediately update the layout for paint.
140-
// Force the layout here to ensure we're measuring the layout time.
141-
var height = self._frame.contentDocument.body.getBoundingClientRect().height;
142-
var endTime = now();
143-
self._frame.contentWindow._unusedHeightValue = height; // Prevent dead code elimination.
141+
var asyncTime = 1;
144142
self._writeMark(suite.name + '.' + test.name + '-async-end');
145-
callback(syncTime, endTime - startTime, height);
143+
callback(syncTime, asyncTime);
146144
}, 0);
147145
}
148146

0 commit comments

Comments
 (0)